【问题标题】:Binding ToolTip in UserControl在 UserControl 中绑定 ToolTip
【发布时间】:2020-09-14 19:32:47
【问题描述】:

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

                   <Grid.ToolTip>
                        <TextBlock
                            Text="{
                                    Binding Path=InfoTT,  
                                    RelativeSource={
                                        RelativeSource Mode=FindAncestor, 
                                        AncestorType={x:Type UserControl}
                                       }
                                 }" />
                    </Grid.ToolTip>

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

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

但是当我这样做时:

                    <Grid
                    ToolTip="{
                                    Binding Path=InfoTT,  
                                    RelativeSource={
                                        RelativeSource Mode=FindAncestor, 
                                        AncestorType={x:Type UserControl}
                                       }
                                 }">

                </Grid>

成功了。谁能解释为什么第一种方法不起作用?

【问题讨论】:

标签: wpf xaml data-binding


【解决方案1】:

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

在您的第一个示例中,您明确定义了ToolTip 的树结构。您正在明确创建内容,例如通过添加TextBlockToolTip 的内容不是可视化树的一部分,因此无法解析 Binding.RelativeSource

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

解决方案

为了解决绑定问题,在显式实现ToolTip 时,您可以按照@Mark Feldman 的评论中的建议实现Binding Proxy,它利用StaticResource 标记为元素提供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>

但您也可以利用DataContext 仍然被继承的事实。与DataContext 的绑定仍将解析。

在您想要将ToolTip 的内容绑定到父UserControl 的属性的场景中,您可以将此属性绑定到视图模型的属性,即当前的DataContext Grid(因此对于它的ToolTip)。我只推荐这个,当绑定到业务数据而不是布局数据时:

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

  <Grid>
    <Grid.ToolTip>
      <ToolTip>
        <TextBlock Text="{Binding ViewModelInfoTT}" />
      </ToolTip>
    </Grid.ToolTip>
  </Grid>
</UserControl>

如果您不使用视图模型并将数据直接托管在控件中,您可能希望将DataContext 设置为控件本身。这样您就可以简化所有绑定,当然现在可以从ToolTip 中绑定到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>

【讨论】:

  • 如果你想用第一种方法,那么你可以通过Binding Proxy绑定来实现。
  • @MarkFeldman 感谢您的评论和启发。你是对的,我应该为这个问题提供一个解决方案。我参考了您的其他解决方案。
  • 我是用第一种方式做的。效果很好,谢谢
  • @BionicCode 谢谢!您也在那里发布了非常好的替代解决方案,并且没有中级课程。没想到会奏效,但确实如此。
猜你喜欢
  • 2021-10-12
  • 2017-02-18
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
  • 1970-01-01
  • 2021-12-17
  • 2018-10-15
  • 1970-01-01
相关资源
最近更新 更多