wpf - 在 UserControl 中绑定(bind) ToolTip

标签 wpf xaml data-binding

我尝试以这种方式在 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 的树结构。您正在明确创建内容,例如通过添加 TextBlockToolTip 的内容不是可视化树的一部分,因此无法解析 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/

相关文章:

data-binding - AngularJS如何将数据与SVG小部件绑定(bind)

java - Spring 闪光范围

c# - WPF 文本 block 闪烁

xaml - 第一次未单击按钮单击[仅适用于Windows 8.1/10平板电脑]

javascript - 如何在 JavaScript 中不断增加范围输入( slider )的值,直到达到最大值?

c# - 如何找到 Windows Phone 8.1 Xaml 应用程序内存泄漏的原因?

c# - 如何在图像上写XAML控件?

wpf - 当我延迟输入最新输入时,组合框过滤器文本丢失

c# - WPF SelectionChanged 事件在选项卡更改之前执行操作

c# - 绑定(bind)实际上是如何工作的?