首页 > 解决方案 > 如何从 ResourceDictionary 引用 BindingProxy 实例

问题描述

任何 wpf 程序员迟早都会开始使用BindingProxy

我试图通过将一些资源移动到单独的资源字典中来拆分 xaml。我的问题是资源包含对BindingProxy.

我该如何处理这种情况?

例如,假设有一个资源在BindingProxy某处使用

<Window.Resources>
    <local:BindingProxy x:Key="proxy" />
    <ControlTemplate x:Key="test">
        <TextBlock Text="{Binding DataContext.Test, Source={StaticResource proxy}}" />
    </ControlTemplate>
</Window.Resources>
<Control Template="{StaticResource test}" />

和后面的代码

public partial class MainWindow : Window
{
    public string Test { get; set; } = "Test 123";

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }
}

它可能不是最好的例子,使用BindingProxy并不合理,但它很好地服务于演示目的。在运行时窗口"Test 123"将显示文本。


现在让我们尝试将资源移动到资源字典Dictionary1.xaml

<ResourceDictionary ... >
    <ControlTemplate x:Key="test">
        <TextBlock Text="{Binding Test, Source={StaticResource proxy}}"  /> <!-- error here -->
    </ControlTemplate>
</ResourceDictionary>

并将主窗口资源更改为

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
        <local:BindingProxy x:Key="proxy" />
    </ResourceDictionary>
</Window.Resources>
<Control Template="{StaticResource test}" />

会导致设计器和运行时异常

System.Windows.Markup.XamlParseException: ''在 'System.Windows.Markup.StaticResourceHolder' 上提供值引发了异常。' 行号“5”和行位置“20”。
内部异常
异常:找不到名为“代理”的资源。资源名称区分大小写。

我该如何参考proxy?是否存在另一种技术来引用资源字典中的某些内容?也许某种RelativeResource方法,但对于不在视觉树中的东西?由于显而易见的原因,我无法proxy进入ResourceDictionary1.xaml:它不会捕获DataContext窗口。

标签: c#wpfdata-binding

解决方案


尽管我不推荐BindingProxy在 MVVM 中,但我认为您的问题是这样解决的:

  • 请记住,当您ResourceDictionary在视图 XAML 中包含 a 时,它会自动继承DataContext视图的 ,因此您可以保留BindingProxyResourceDictionary但您需要明确指定绑定。
  • 请记住还要从 View XAML 中删除代理声明,因为它现在在字典中。
  • 你失去了改变的能力DataContextBindingProxy它将使用DataContext消费者视图。

资源字典:

<ResourceDictionary ...>
    <!-- NOTE: Data property grabs the DataContext of the consumer view -->
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
    <ControlTemplate x:Key="text">
        <TextBlock Text="{Binding Data.Test, Source={StaticResource proxy}}" />
    </ControlTemplate>
</ResourceDictionary>

窗户:

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>

快照:

在此处输入图像描述


你真的需要BindingProxy吗?

上面的建议违背了它的目的,BindingProxy因为它不再需要了;请注意,您可以更改ResourceDictionary如下,它的工作原理完全相同,无需任何BindingProxy

<ResourceDictionary ...>
    <ControlTemplate x:Key="test">
        <TextBlock Text="{Binding Test}" />
    </ControlTemplate>
</ResourceDictionary>

推荐阅读