【发布时间】:2025-02-10 14:45:02
【问题描述】:
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。
【问题讨论】:
-
也许您可以使用动态资源...除此之外,您的层次结构颠倒了。使用合并字典,您可以在当前范围内使用引用字典中的资源。但是您不能真正使用合并字典中的当前范围资源。
-
你能展示一下代理是如何实例化的吗?如果代理是单例的,你可以使用 ServiceLocator 模式。
-
您能否将您的示例扩展到一个实际需要代理的简单案例?现在,您总是可以跳过整个代理并绑定到隐式可用的数据上下文。我有 3 种不同的想法如何解决这种情况,但我无法通过所提供的示例确定正确的方法。
-
@grek40,在文章中是
DataGridTextColumn,在我的例子中是GridViewColumn(参见相关问题)。任何不属于视觉树的东西都会做,例如ContextMenu,如果我没记错的话Popup等等。在那里你不能使用RelativeSource,需要以某种方式通过DataContext。 -
@Sinatr 我回答了你的另一个问题,因为我认为这不是一个 XY 问题。我大多同意 LuckyBrain。绑定代理是我发现在非常有限的情况下有用的东西。大多数时候有更好的方法,当代理和它的用户(一些模板资源)之间的连接变得不明确时,是时候继续前进,而不是试图修复不应该存在的东西。
标签: c# wpf data-binding