在 UserControl 中绑定 ToolTip

ikn*_*now 2 data-binding wpf xaml

ToolTip我尝试以这种方式绑定文本UserControl

<Grid.ToolTip>
    <TextBlock
        Text="{
            Binding Path=InfoTT,  
            RelativeSource={
                RelativeSource Mode=FindAncestor, 
                AncestorType={x:Type UserControl}
            }
        }" />
</Grid.ToolTip>
Run Code Online (Sandbox Code Playgroud)

它不起作用,Tooltip是空的,在日志中,我看到:

System.Windows.Data 错误:4:无法找到引用“RelativeSource FindAncestor,AncestorType='System.Windows.Controls.UserControl”,AncestorLevel='1'' 进行绑定的源。BindingExpression:Path=InfoTT; 数据项=空;目标元素是“TextBlock”(名称=“”);目标属性是“文本”(类型“字符串”)*

但是当我这样做时:

<Grid
    ToolTip="{
        Binding Path=InfoTT,  
        RelativeSource={
            RelativeSource Mode=FindAncestor, 
            AncestorType={x:Type UserControl}
        }
    }">
</Grid>
Run Code Online (Sandbox Code Playgroud)

有效。谁能解释为什么第一种方法不起作用?

Bio*_*ode 6

Binding.RelativeSource无法解决时,您始终可以确定它Binding.Target不是可视化树的一部分。

在您的第一个示例中,您显式定义了ToolTip. 您正在显式创建内容,例如通过添加TextBlock. 的内容ToolTip不是视觉树的一部分,因此Binding.RelativeSource无法解析。

在第二个示例中,您让FrameworkElement隐式创建ToolTip内容。
现在FrameWorkElement将首先解析Binding,它会解析,因为FrameworkElement仍然是可视化树的一部分。解析的值被获取、ToString调用、TextBlock创建并将字符串值分配给TextBlock.Text

解决方案

为了解决绑定问题,在ToolTip显式实现时,您可以按照 @Mark Feldman 的评论中的建议实现绑定代理,它利用标记为不属于可视化树的元素StaticResource提供 a 。 它基本上是一个可绑定的.Binding.Source
ObjectDataProvider

与绑定代理类似的解决方案是将内容定义为 的资源Grid,然后通过DynamicResource使用引用它ContentPresnter

<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>
Run Code Online (Sandbox Code Playgroud)

但您也可以利用DataContext仍然继承的事实。对遗嘱的绑定DataContext仍会解析。

在您的场景中,如果您想要将 的内容绑定ToolTip到父级的属性UserControl,则可以将此属性绑定到视图模型的属性,该属性是 的当前属性DataContextGrid因此也是其当前的属性ToolTip)。我仅在绑定到业务数据而不是布局数据时建议这样做:

<UserControl InfoTT="{Binding ViewModelInfoTT}">
  <UserControl.DataContext>
    <ViewModel />
  </UserControl.DataContext>

  <Grid>
    <Grid.ToolTip>
      <ToolTip>
        <TextBlock Text="{Binding ViewModelInfoTT}" />
      </ToolTip>
    </Grid.ToolTip>
  </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

如果您不使用视图模型并将数据直接托管在控件中,您可能希望将 设为DataContext控件本身。通过这种方式,您可以简化所有绑定,当然现在可以绑定到UserControl以下内容ToolTip

// 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>
Run Code Online (Sandbox Code Playgroud)

或者覆盖DataContext. 当然,您将无法访问当前上下文:

<UserControl>
  <Grid DataContext="{Binding RelativeSource={RelativeSource AncestoType=UserControl}>
    <Grid.ToolTip>
      <ToolTip>
        <TextBlock Text="{Binding InfoTT}" />
      </ToolTip>
    </Grid.ToolTip>
  </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)