我尝试以这种方式在 UserControl
中绑定(bind) ToolTip
文本:
<Grid.ToolTip>
<TextBlock
Text="{
Binding Path=InfoTT,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}
}" />
</Grid.ToolTip>
它不起作用,Tooltip
是空的,在日志中,我看到:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=InfoTT; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')*
但是当我这样做的时候:
<Grid
ToolTip="{
Binding Path=InfoTT,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}
}">
</Grid>
成功了。谁能解释为什么第一种方法不起作用?
最佳答案
当 Binding.RelativeSource
未解析时,您始终可以确定 Binding.Target
不是可视化树的一部分。
在您的第一个示例中,您明确定义了 ToolTip
的树结构。您正在明确创建内容,例如通过添加 TextBlock
。 ToolTip
的内容不是可视化树的一部分,因此无法解析 Binding.RelativeSource
。
在第二个示例中,您让 FrameworkElement
隐式创建 ToolTip
内容。
现在 FrameWorkElement
将首先解析 Binding
,因为 FrameworkElement
仍然是可视化树的一部分。获取解析值,调用 ToString
,创建 TextBlock
并将字符串值分配给 TextBlock.Text
。
解决方案
要解决绑定(bind)问题,在显式实现ToolTip
时,可以实现一个Binding Proxy。正如@Mark Feldman 在评论中所建议的那样,它使用 StaticResource
标记为不属于可视化树的元素提供 Binding.Source
。
它基本上是一个可绑定(bind)的 ObjectDataProvider
。
与绑定(bind)代理类似的解决方案是将内容定义为 Grid
的资源,然后使用 ContentPresnter
通过 DynamicResource
引用它>:
<UserControl>
<Grid>
<Grid.Resources>
<!-- The proxy -->
<TextBlock x:Key="ToolTipText"
Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=InfoTT}" />
<Grid.ToolTip>
<ToolTip>
<ContentPresenter Content="{DynamicResource ToolTipText}" />
</ToolTip>
</Grid.ToolTip>
</Grid>
</UserControl>
但是您也可以利用 DataContext
仍然是继承的这一事实。与 DataContext
的绑定(bind)仍将解析。
在您的场景中,如果您想将 ToolTip
的内容绑定(bind)到父级 UserControl
的属性,您可以将该属性绑定(bind)到 View 的属性模型,它是 Grid
的当前 DataContext
(因此对于它的 ToolTip
)。我只在绑定(bind)到业务数据而不是布局数据时推荐这样做:
<UserControl InfoTT="{Binding ViewModelInfoTT}">
<UserControl.DataContext>
<ViewModel />
</UserControl.DataContext>
<Grid>
<Grid.ToolTip>
<ToolTip>
<TextBlock Text="{Binding ViewModelInfoTT}" />
</ToolTip>
</Grid.ToolTip>
</Grid>
</UserControl>
如果您不使用 View 模型并直接在控件中托管数据,您可能希望将 DataContext
设置为控件本身。这样您就可以简化所有绑定(bind),当然现在可以从 ToolTip
中绑定(bind)到 UserControl
:
// Constructor
public MyUserControl()
{
InitializeComponent();
// Set the UserControl's DataContext to the control itself
this.DataContext = this;
}
<UserControl>
<Grid>
<Grid.ToolTip>
<ToolTip>
<TextBlock Text="{Binding InfoTT}" />
</ToolTip>
</Grid.ToolTip>
</Grid>
</UserControl>
或者覆盖 DataContext
。当然,您将无法访问当前上下文:
<UserControl>
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestoType=UserControl}>
<Grid.ToolTip>
<ToolTip>
<TextBlock Text="{Binding InfoTT}" />
</ToolTip>
</Grid.ToolTip>
</Grid>
</UserControl>
关于wpf - 在 UserControl 中绑定(bind) ToolTip,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62048541/