将工具提示绑定到自定义控件内的DependencyProperty

时间:2019-03-06 08:56:50

标签: c# wpf data-binding dependency-properties

我试图将某些值绑定到ToolTipService.ShowDuration的{​​{1}}中的CellStyle和其他一些ToolTip的属性。

通常,我正在做这样的事情:

DataGridTextColumn

由于ToolTip具有其自己的可视树,因此我正在使用像这样的绑定代理:

<UserControl
    ...namespace declarations...>
    <UserControl.Resources>
        <mycontrols:BindingProxy x:Key="proxy" Data="{Binding MySettings}"/>
    </UserControl.Resources>
    <DataGrid>
        <DataGridTextColumn
            Binding="{Binding SomeBinding}">
            <DataGridTextColumn.CellStyle>
                <Style 
                    TargetType="DataGridCell" 
                    BasedOn="{StaticResource ResourceKey={x:Type DataGridCell}}">
                    <Setter 
                        Property="ToolTipService.ShowDuration" 
                        Value="{Binding Data.ToolTipDuration, Source={StaticResource proxy}}"/>
                    <Setter Property="ToolTip">
                        <Setter.Value>
                            <TextBlock 
                                Text="{Binding SomeBinding}" 
                                MaxWidth="{Binding Data.ToolTipMaxWidth, Source={StaticResource proxy}}" 
                                TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
                        </Setter.Value>
                    </Setter>
                </Style>
            </DataGridTextColumn.CellStyle>
        </DataGridTextColumn>
    </DataGrid>
</UserControl>

到目前为止,所有操作均按预期进行。但是我想重新使用这个DataGridTextColumn,所以我创建了这样的新文件:

public class BindingProxy : Freezable
    {
        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }

        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }

附有代码:

<DataGridTextColumn
    x:Class="Test.MyControls.DataGridLargeTextColumn"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Test.MyControls">
    <DataGridTextColumn.CellStyle>
        <Style 
            TargetType="DataGridCell" 
            BasedOn="{StaticResource ResourceKey={x:Type DataGridCell}}">
            <Setter 
                Property="ToolTipService.ShowDuration" 
                Value="{Binding ToolTipDuration}"/>
            <Setter Property="ToolTip">
                <Setter.Value>
                    <TextBlock 
                        Text="{Binding SomeBinding}" 
                        MaxWidth="{Binding ToolTipWidth}" 
                        TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

这是行不通的,因为ToolTip有它自己的可视树,但是由于我无处放置代理,因此我不知道如何使其工作,甚至不可行。我找到了this answer,而且似乎步入了正确的轨道,但是,我尝试这样实现它的过程并不顺利:

public partial class DataGridLargeTextColumn : DataGridTextColumn
{
    public int ToolTipDuration
    {
        get { return (int)GetValue(ToolTipDurationProperty); }
        set { SetValue(ToolTipDurationProperty, value); }
    }
    public static readonly DependencyProperty ToolTipDurationProperty =
        DependencyProperty.Register("ToolTipDuration", typeof(int), typeof(DataGridLargeTextColumn), new UIPropertyMetadata(default(int)));

    public string SomeBinding
    {
        get { return (string)GetValue(SomeBindingProperty); }
        set { SetValue(SomeBindingProperty, value); }
    }
    public static readonly DependencyProperty SomeBindingProperty =
        DependencyProperty.Register("SomeBinding", typeof(string), typeof(DataGridLargeTextColumn), new UIPropertyMetadata(default(string)));

    public int ToolTipWidth
    {
        get { return (int)GetValue(ToolTipWidthProperty); }
        set { SetValue(ToolTipWidthProperty, value); }
    }
    public static readonly DependencyProperty ToolTipWidthProperty =
        DependencyProperty.Register("ToolTipWidth", typeof(int), typeof(DataGridLargeTextColumn), new UIPropertyMetadata(default(int)));

    public DataGridLargeTextColumn()
    {
        InitializeComponent();
    }
}

我使用PlacementTarget错误吗?如果没有,为什么它不起作用,还有其他解决方案吗?

更新:

根据Mark的回答,我修改了<Setter Property="ToolTipService.ShowDuration" Value="{Binding Path=PlacementTarget.(local:DataGridLargeTextColumn.ToolTipDuration), RelativeSource={RelativeSource Self}}"/> <Setter Property="ToolTip"> <Setter.Value> <TextBlock Text="{Binding Path=PlacementTarget.(local:DataGridLargeTextColumn.SomeBinding), RelativeSource={RelativeSource Self}}" MaxWidth="{Binding Path=PlacementTarget.(local:DataGridLargeTextColumn.ToolTipWidth), RelativeSource={RelativeSource Self}}" TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/> </Setter.Value> </Setter> 的样式:

DataGridLargeTextColumn

我正在使用这样的控件:

<Style
    TargetType="DataGridCell" 
    BasedOn="{StaticResource {x:Type DataGridCell}}">
    <Setter 
        Property="ToolTipService.ShowDuration" Value="{Binding Path=PlacementTarget.ToolTipShowDuration, RelativeSource={x:Static RelativeSource.Self}}"/>
    <Setter Property="ToolTip">
        <Setter.Value>
            <ToolTip DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
                <TextBlock 
                    Text="{Binding DataContext.SomeBinding}"
                    MaxWidth="{Binding Column.ToolTipWidth}"
                    TextWrapping="Wrap" TextTrimming="CharacterEllipsis"/>
            </ToolTip>
        </Setter.Value>
    </Setter>
</Style>

宽度绑定现在可以像超级按钮一样工作,但是有两个我仍然无法解决的问题:

  1. 我无法绑定工具提示的持续时间,我尝试了几种不同的方法,但是由于它是抽象的,因此无法显式声明
  2. ToolTip的<UserControl ...namespace declarations...> <UserControl.Resources> <mycontrols:BindingProxy x:Key="proxy" Data="{Binding MySettings}"/> </UserControl.Resources> <DataGrid> <DataGrid.Columns> <mycontrols:DataGridLargeTextColumn Binding="{Binding SomeBinding}" ToolTipShowDuration="{Binding Data.ToolTipDuration, Source={StaticResource proxy}}" ToolTipWidth="{Binding Data.ToolTipMaxWidth, Source={StaticResource proxy}}"/> </DataGrid.Columns> </DataGrid> </UserControl> 属性设置为Text,在这种特殊情况下可以,但是我希望能够将其设置为任何值,因此我尝试使用{{1}进行声明}从上面这样:

SomeBinding

如果我将其与字符串文字一起使用,则可以正常工作:

DependencProperty

但是当我尝试绑定它时,它不起作用,这是我要实现的目标:

Text="{Binding Column.ToolTipText}"

1 个答案:

答案 0 :(得分:1)

默认情况下,您的工具提示的DataContext设置为单元格的DataContext。但是,您正尝试绑定到单元格列中的依赖项属性,因此您将必须更改DataContext使其指向单元格本身,然后在要访问数据时显式引用DataContextColumn,当您想访问DataGridLargeTextColumn中的DP时。

换句话说,除了其内容之外,还明确声明ToolTip并设置其DataContext,如下所示:

<Setter Property="ToolTip">
    <Setter.Value>
        <ToolTip DataContext="{Binding Path=PlacementTarget, RelativeSource={x:Static RelativeSource.Self}}">
            <TextBlock 
                Text="{Binding DataContext.SomeBinding}"
                Width="{Binding Column.ToolTipWidth}" />
        </ToolTip>
    </Setter.Value>
</Setter>

......,其中Text绑定到数据,Width绑定到自定义列DP。

或者,您也可以仅保留DataContext,而使用ToolTip的Tag属性作为DataGridLargeTextColumn的绑定代理:

<Setter Property="ToolTip">
    <Setter.Value>
        <ToolTip Tag="{Binding Path=PlacementTarget.Column, RelativeSource={x:Static RelativeSource.Self}}">
            <TextBlock 
                Text="{Binding SomeBinding}"
                Width="{Binding Tag.ToolTipWidth, RelativeSource={RelativeSource AncestorType=ToolTip}}" />
        </ToolTip>
    </Setter.Value>
</Setter>