WPF如何将附加属性绑定到依赖属性

问题描述

我正在自定义DataGridCell,以在工具提示的角上有一个小三角形。该三角形仅应显示工具提示是否包含内容,并且工具提示内容将来自DataGrid的ItemsSource。

DataGrid中的三角形位于拐角处:

DataGrid with the triangle in the corner

现在,我创建了一个名为“提示”的附加属性,该属性将绑定到具有工具提示内容的ItemsSource的属性

public class HintAttachedProperty
{

        public static void SetHint(DependencyObject obj,string text)
        {
            obj.SetValue(HintProperty,text);
        }

        public static string GetHint(DependencyObject obj)
        {
            return obj.GetValue(HintProperty)?.ToString() ?? string.Empty;
        }

        public static readonly DependencyProperty HintProperty =
            DependencyProperty.Registerattached("Hint",typeof(string),typeof(HintAttachedProperty),new FrameworkPropertyMetadata(null));

}

DataGrid的xaml,现在附加的属性提示已设置为值“ A test”:

        <local:CustomDataGrid x:Name="datagrid"
              AutoGenerateColumns="False"
              ItemsSource="{Binding ItemsCollection}"
              ClipboardcopyMode="IncludeHeader"
              EnableRowsMove="True"
              AlternatingRowBackground="LightBlue"
              AlternationCount="2">
        <DataGrid.Columns>
           
            <DataGridCheckBoxColumn Header="IsChecked" Binding="{Binding IsChecked}"/>
            <DataGridTextColumn x:Name="Test" 
                                local:IsHighLightedAttachedProperty.IsHighLighted="True" 
                                local:HintAttachedProperty.Hint="A test" 
                                Header="ExperienceInMonth" 
                                Binding="{Binding ExperienceInMonth}">
            </DataGridTextColumn>
            <DataGridTemplateColumn Header="References">
                ...
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="EmployeeName" Binding="{Binding EmployeeName}"/>
            <DataGridTextColumn Header="EmployeeAge" Binding="{Binding EmployeeAge}" />
        </DataGrid.Columns>
    </local:CustomDataGrid>

这是DataGridCell的样式,该样式控制三角形的可见性,并且应将附加属性绑定到工具提示内容

 <Style targettype="{x:Type DataGridCell}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate targettype="{x:Type DataGridCell}">
                <Border x:Name="borderSides" BorderThickness="2,2,0" Background="Transparent" BorderBrush="Transparent" SnapsToDevicePixels="True">
                    <Border x:Name="borderTopBottom" BorderThickness="0,2" Background="Transparent" BorderBrush="Transparent" SnapsToDevicePixels="True">
                        <Grid>
                            <Grid x:Name="grid">
                                <Grid.ColumnDeFinitions>
                                    <ColumnDeFinition Width="*"/>
                                    <ColumnDeFinition Width="Auto"/>
                                </Grid.ColumnDeFinitions>
                                <ContentPresenter Grid.Column="0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                <polygon x:Name="pol" ToolTip="{Binding RelativeSource={RelativeSource Self},Converter={StaticResource HintConverter}}" Grid.Column="1" HorizontalAlignment="Right" Points="5,0 10,10,5" stroke="Black" Fill="Black" >
                                
                                </polygon>
                            </Grid>
                        </Grid>
                    </Border>
                </Border>

                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Converter={StaticResource HintConverter}}" Value="{x:Static sys:String.Empty}">
                        <Setter TargetName="pol" Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Converter={StaticResource HintConverter}}" Value="{x:Null}">
                        <Setter TargetName="pol" Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>                
        </Setter.Value>
    </Setter>
</Style>

在绑定 {Binding RelativeSource = {RelativeSource Self},Converter = {StaticResource HintConverter}} 中,我正在使用DataGridCell内容的转换器来获取附加属性的值,因为当我做 {Binding path =(local:HintAttachedProperty.Hint)} 时,它总是返回null。

转换器的代码

public class HintConverters : IValueConverter
{

    public object Convert(object value,Type targettype,object parameter,System.Globalization.CultureInfo culture)
    {
         DataGridCell dgc = value as DataGridCell;
         if (dgc != null)
         {
             DataGridColumn col = dgc.Column;
             if (col != null)
             {
                 var hint = HintAttachedProperty.GetHint(col);
                 return hint;
             }
         }
         return "";
     }

    public object ConvertBack(object value,System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

调试时,我可以在转换器中看到该值如何为“ A test”,因此未隐藏该三角形,但是当我将光标放在工具提示上时为空:

提示值:

Value of hint

工具提示为空:

Tooltip is empty

另一方面,如果我直接绑定到样式中ItemsSource的属性,例如Employee Name, ToolTip =“ {Binding EmployeeName}” ,则可以正常工作:

Tooltip working

如何将和附加属性的值绑定到属性?这可能吗?也许我应该朝另一个方向走?

感谢您的关注

解决方法

转换器是多余的,您只需要更正绑定即可使其工作。

Polygon中,您需要找到DataGridCell的祖先,而不是Self,因为那是多边形。从那里您需要访问Column,因为Hint就是这个附件。

<Polygon x:Name="pol" ToolTip="{Binding Column.(local:HintAttachedProperty.Hint),RelativeSource={RelativeSource AncestorType={x:Type DataGridCell}}}" Grid.Column="1" HorizontalAlignment="Right" Points="5,0 10,10,5" Stroke="Black" Fill="Black"/>

在触发器中,相对源是正确的,因为在这种情况下,SelfDataGridCell,但是如上所述,您需要访问Column,其中Hint

<DataTrigger Binding="{Binding Column.(local:HintAttachedProperty.Hint),RelativeSource={RelativeSource Self}}" Value="{x:Static system:String.Empty}">
   <Setter TargetName="pol" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Column.(local:HintAttachedProperty.Hint),RelativeSource={RelativeSource Self}}" Value="{x:Null}">
   <Setter TargetName="pol" Property="Visibility" Value="Collapsed"/>
</DataTrigger>

用Upadate发表您的评论。在当前项目的数据上下文或数据网格数据上下文上绑定属性无法通过这种方式工作,因为该列不是可视化树的一部分,因为该列仅是单元格的定义方式应该在此列中构建。

我将向您展示当前项目的数据上下文的解决方法。绑定到父DataGrid的数据上下文的工作方式不同。您可以通过HintStyle属性附加到单元格中实际显示的元素。您可以使用该样式访问当前项目的数据上下文。

如果您有一个只读列,则只需创建一个ElementStyle。如果您有一个editbale列要在其中显示多边形和工具提示,则还需要一个EditingElementStyle

<DataGridTextColumn Header="EmployeeName" Binding="{Binding EmployeeName}">
   <DataGridTextColumn.ElementStyle>
      <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
        <Setter Property="local:HintAttachedProperty.Hint" Value="{Binding EmployeeName}"/>
      </Style>
   </DataGridTextColumn.ElementStyle>
   <DataGridTextColumn.EditingElementStyle>
      <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
         <Setter Property="local:HintAttachedProperty.Hint" Value="{Binding EmployeeName}"/>
      </Style>
   </DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>

使绑定适应以使用Content属性而不是Column来访问已将Hint属性附加到的单元格模板中的顶级元素,例如TextBlock

<Polygon x:Name="pol" ToolTip="{Binding Content.(local:HintAttachedProperty.Hint),5" Stroke="Black" Fill="Black" >
<DataTrigger Binding="{Binding Content.(local:HintAttachedProperty.Hint),RelativeSource={RelativeSource Self}}" Value="{x:Static system:String.Empty}">
   <Setter TargetName="pol" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding Content.(local:HintAttachedProperty.Hint),RelativeSource={RelativeSource Self}}" Value="{x:Null}">
   <Setter TargetName="pol" Property="Visibility" Value="Collapsed"/>
</DataTrigger>

回顾一下,这里的主要问题是您不能从列访问数据上下文。

覆盖单元格ControlTemplate的一种方法是创建DataGridTemplateColumn,在其中为每个带有箭头多边形和工具提示的列创建自定义DataTemplate

然后,您可以轻松地附加和绑定Hint属性,因为您可以访问当前项目的所有控件和数据上下文。该解决方案的缺点是,您将不得不为每列创建自定义数据模板,并在各处复制箭头和工具提示XAML。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...