附加属性和动态资源
本文关键字:动态 资源 属性 | 更新日期: 2023-09-27 18:30:36
我正在尝试在附加属性的内容上设置动态资源,但这不起作用。试图理解为什么,但我无法弄清楚。
基本上,我正在使用以下代码在文本框上实现水印:水印/提示文本/占位符 WPF 中的文本框 由John Myczek提供并按如下方式使用它:
<TextBox Text="{Binding SomeProperty}">
<helper:WatermarkService.Watermark>
<TextBlock FontStyle="Italic" Text="{DynamicResource SomeResource}" />
</helper:WatermarkService.Watermark>
</TextBox>
如果内部TextBlock
位于WatermarkService.Watermark
附加属性之外,则工作正常。由于某种原因,SomeResource
为空。
我的资源正在加载,因为应用程序已本地化并且数据是从中心位置检索的,因此this.Resources.MergedDictionaries.Add(lastDictionary);
加载。
附加属性上的控件是否共享与其"父属性"相同的资源集?这是怎么回事?谢谢
问题很明显。动态资源是通过向上解析逻辑树来解决的。找不到动态资源,因为您的文本块不在正确的逻辑树中,可能他没有逻辑父级,这就是找不到资源的原因。
您可以通过将其添加到正确的逻辑树来解决它,例如它可以是文本框的子级。它不是那么简单,还取决于所需的用法,因为逻辑树的自定义不是那么简单。
没有像拥有公共方法AddLogicalChild那么简单,因为那样你会搞砸整个系统。现在的问题是,谁有责任这样做。常规解决方案可能是使用一个自定义文本框,该文本框覆盖与逻辑子项相关的方法,并返回水印文本块。
它不是全局解决方案,但在您的情况下,您可以使用一个自定义文本框覆盖 LogicalChildren 属性,如下所示:
public class WaterTextBox : TextBox
{
protected override IEnumerator LogicalChildren
{
get
{
ArrayList list = new ArrayList();
list.Add(WatermarkService.GetWatermark(this));
return (IEnumerator)list.GetEnumerator();
}
}
}
请记住,这只是一种解决方法,这种方式仅适用于具有动态资源的自定义文本框。
它也不是正确的实现,因为您应该将水印添加到其他逻辑子项,而不是忽略其他逻辑子项,并且只有水印,甚至没有像这样检查 null:
public class WaterTextBox : TextBox
{
protected override IEnumerator LogicalChildren
{
get
{
ArrayList list = new ArrayList();
IEnumerator enumerator = base.LogicalChildren;
while (enumerator.MoveNext())
{
list.Add(enumerator.Current);
}
object watermark = WatermarkService.GetWatermark(this);
if (watermark != null && !list.Contains(watermark))
{
list.Add(WatermarkService.GetWatermark(this));
}
return (IEnumerator)list.GetEnumerator();
}
}
}
若要使其更通用,您应该定义一个接口,如 IWatermark,定义一个属性,如 IsWaterMarkAdd,该属性将由自定义文本框和组合框实现,并由水印服务使用。逻辑子项覆盖将检查此属性的值。这样,您可以扩展文本框和组合框的功能,但它仍然不是任何控件的可扩展解决方案。