我正在尝试在附加属性的内容上设置DynamicResource,但这不起作用。试图理解为什么,但我无法弄清楚。
基本上,我正在使用以下代码中的代码在文本框上实现水印:Watermark / hint text / placeholder TextBox in 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);
正在加载我的资源。
附加属性上的控件是否与其“父母”共享相同的资源?这有什么不对? 谢谢
答案 0 :(得分:1)
问题很明显。通过向上解析逻辑树来解析动态资源。找不到动态资源,因为您的文本块不在正确的逻辑树中,可能他没有逻辑父级,这就是找不到资源的原因。
您可以通过将其添加到正确的逻辑树来解决它,例如它可能是文本框的子项。它不是那么简单,也取决于所需的用法,因为逻辑树的自定义并不是那么简单。
没有像公共方法AddLogicalChild这么简单,因为那样你就会搞乱整个系统。现在的问题是谁有责任这样做。一般的解决方案可能是使用自定义TextBox来覆盖与逻辑子相关的方法,并返回水印文本块。
这不是全局解决方案,但在您的情况下,您可以使用自定义文本框覆盖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这样的接口来定义像IsWaterMarkAdded这样的属性,它将由您的自定义TextBox和ComboBox实现,并将由水印服务使用。 LogicalChildren覆盖将检查此属性的值。这样,您可以扩展TextBox和ComboBox的功能,但它仍然不是任何控件的可扩展解决方案。