资源部分中的 WPF DataContextProxy

chr*_*233 5 c# silverlight wpf datacontext mvvm

我\xe2\x80\x99m 在我的 WPF 应用程序中使用 DataContextProxy 时遇到问题。当我将 DataContextProxy 放置在网格的资源部分时,它永远不会加载。如果我将 DataContextProxy 移出资源部分,一切都会正常工作。

\n\n

我\xe2\x80\x99已经对此进行了一段时间的研究,并尝试了多种方法来调试应用程序。

\n\n
    \n
  • 我\xe2\x80\x99已在我\xe2\x80\x99m尝试使用代理的控件上放置了一个DebugConverter。调试转换器永远不会被调用。

  • \n
  • 我\xe2\x80\x99ve使用WPFSnoop来查看是否有任何绑定错误。我在 DataContextProxy 上遇到\n以下绑定错误,

    \n\n

    System.Windows.Data 错误:3:找不到提供 DataContext 的元素。\nBindingExpression:(无路径);数据项=空;目标元素是\'Proxy\'\n(Name=\'\'); 目标属性是“DataContext”(类型“Object”)

  • \n
  • 我\xe2\x80\x99在我的DataContextProxy的加载事件上放置了一个断点。\n加载的事件从未被调用,而我\xe2\x80\x99在\nDataContextChanged事件中放置了一个断点,该事件从未被调用。

  • \n
\n\n

这是一些示例代码来演示这一点。显然我知道我并不真正需要在 TextBox 上使用 DataContextProxy。

\n\n
<Window x:Class="WpfDataContextProxyBug.MainWindow"\n        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n        xmlns:local="clr-namespace:WpfDataContextProxyBug"\n        Title="MainWindow" Height="350" Width="525">\n    <Window.Resources>\n        <local:DebugConverter x:Key="DebugConverter"/>\n    </Window.Resources>\n    <Grid>\n        <Grid.Resources>\n            <local:Proxy x:Key="Proxy" DataContext="{Binding}" />\n        </Grid.Resources>\n\n    <TextBox DataContext="{Binding Path=Name, Source={StaticResource Proxy}, Converter={StaticResource DebugConverter}}"/>\n    </Grid>\n</Window>\n
Run Code Online (Sandbox Code Playgroud)\n\n

DataContextProxy 类

\n\n
public class Proxy : FrameworkElement\n{\n    public Proxy()\n    {\n        Loaded += DataContextProxy_Loaded;\n        DataContextChanged += Proxy_DataContextChanged;\n    }\n\n    void Proxy_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)\n    {\n\n    }\n\n    void DataContextProxy_Loaded(object sender, RoutedEventArgs e)\n    {\n\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Art*_*nes 2

当我尝试在 WPF 中使用 DataContextProxy 时,我也遇到了这个问题。受其启发,我想出了一个解决方案,它似乎可以很好地处理这项工作。一探究竟:

public class DataContextProxyBehavior : Behavior<FrameworkElement>
{
    public Object DataSource
    {
        get { return (Object)GetValue(DataSourceProperty); }
        set { SetValue(DataSourceProperty, value); }
    }
    public static readonly DependencyProperty DataSourceProperty =
        DependencyProperty.Register("DataSource", typeof(Object), typeof(DataContextProxy), null);

    protected override void OnAttached()
    {
        base.OnAttached();

        // Binds the target datacontext to the proxy,
        // so whenever it changes the proxy will be updated
        var binding = new Binding();
        binding.Source = this.AssociatedObject;
        binding.Path = new PropertyPath("DataContext");
        binding.Mode = BindingMode.OneWay;
        BindingOperations.SetBinding(this, DataContextProxyBehavior.DataSourceProperty, binding);

        // Add the proxy to the resource collection of the target
        // so it will be available to nested controls
        this.AssociatedObject.Resources.Add(
            "DataContextProxy",
            this
        );
    }
    protected override void OnDetaching()
    {
        base.OnDetaching();

        // Removes the proxy from the Resources
        this.AssociatedObject.Resources.Remove(
            "DataContextProxy"
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

您只需将其附加到父元素即可。子元素中的静态资源引用将保持不变。我在这里发布了一个用法示例。