将DataGrid列DataTemplate绑定到附加属性

时间:2013-07-27 13:13:51

标签: wpf datatemplate datagridcolumn datagridcolumnheader

我正在尝试自定义 DataGridColumnHeader 以显示多个文本字段而不是 仅显示 DataGridColumn.Header 属性提供的标题文本 如果我没有错过任何东西,我只需要创建一个 DataTemplate 并绑定到属性
父对象的。这适用于 DataGridColumn.Header 属性但是 绑定到附加属性失败。

为了完整起见,附加财产的实施:

public static class CustomHeader
{
    public static string GetUnit(DependencyObject obj) { return (string)obj.GetValue(UnitProperty); }
    public static void SetUnit(DependencyObject obj, string value) { obj.SetValue(UnitProperty, value); }

    public static readonly DependencyProperty UnitProperty = DependencyProperty.RegisterAttached(
        "Unit", typeof(string), typeof(CustomHeader), new FrameworkPropertyMetadata(null));
}

Xaml-Markup中的用法:

<DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
                  AutoGenerateColumns="False" EnableRowVirtualization="True"  
                  ItemsSource="{Binding ObjectList}"  
                  RowDetailsVisibilityMode="VisibleWhenSelected" >
  <DataGrid.Resources>  
    <DataTemplate x:Key="CustomHeaderTemplate">  
      <StackPanel>  
        <TextBlock Text="{Binding}" />  
        <TextBlock Text="{Binding Path=(cust:CustomHeader.Unit)}" /> <-- attached binding doesn't work :( 
      </StackPanel>  
    </DataTemplate>  
  </DataGrid.Resources>  

  <DataGrid.Columns>  
    <DataGridTextColumn x:Name="SpeedColumn"
                        Width="1*"
                        Binding="{Binding Speed}"
                        Header="Speed"
                        HeaderTemplate="{StaticResource CustomHeaderTemplate}"
                        cust:CustomHeader.Unit="[m/s]" />  
  </DataGrid.Columns>  
</DataGrid>  

我非常感谢任何澄清我在这里缺少的评论或网络链接。 提前谢谢。

2 个答案:

答案 0 :(得分:3)

您应该使用多值转换器(msdn)。

XAML:

<DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
          AutoGenerateColumns="False" EnableRowVirtualization="True"  
          ItemsSource="{Binding ObjectList}"  
          RowDetailsVisibilityMode="VisibleWhenSelected" >
    <DataGrid.Resources>
        <cust:UnitConverter x:Key="unitCon" />
        <DataTemplate x:Key="CustomHeaderTemplate">
            <StackPanel>
                <TextBlock Text="{Binding}" />
                <TextBlock>
                    <TextBlock.Text>
                        <MultiBinding Converter="{StaticResource unitCon}">
                            <Binding Path="Columns" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGrid}" />
                            <Binding Path="." />
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>
            </StackPanel>
        </DataTemplate>
    </DataGrid.Resources>

    <DataGrid.Columns>
        <DataGridTextColumn x:Name="SpeedColumn"
                Width="1*"
                Binding="{Binding Speed}"
                Header="Speed"
                HeaderTemplate="{StaticResource CustomHeaderTemplate}"
                cust:CustomHeader.Unit="[m/s]" />

        <DataGridTextColumn x:Name="SpeedColumn2"
                Width="1*"
                Binding="{Binding Speed2}"
                Header="Speed2"
                HeaderTemplate="{StaticResource CustomHeaderTemplate}"
                cust:CustomHeader.Unit="[km/h]" />
    </DataGrid.Columns>
</DataGrid>

代码隐藏:

public class UnitConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string result = null;

        ObservableCollection<DataGridColumn> columns = values[0] as ObservableCollection<DataGridColumn>;
        string headerName = values[1].ToString();

        var coll = columns.Where(x => x.Header.ToString() == headerName).FirstOrDefault();

        if (coll != null)
            result = CustomHeader.GetUnit(coll);

        return result;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

我认为更好的解决方案是创建新类,例如HeaderData,之后您可以在xaml中创建它的实例并绑定到此类。

示例:

用于保存标题数据的类:

class HeaderData
{
    public string Name { get; set; }
    public string Unit { get; set; }
}

XAML代码:

<DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
          AutoGenerateColumns="False" EnableRowVirtualization="True"  
          ItemsSource="{Binding ObjectList}"  
          RowDetailsVisibilityMode="VisibleWhenSelected" >
    <DataGrid.Resources>
        <DataTemplate x:Key="CustomHeaderTemplate">
            <StackPanel>
                <TextBlock Text="{Binding Name}" />
                <TextBlock Text="{Binding Unit}" />
            </StackPanel>
        </DataTemplate>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="SpeedColumn"
                        Width="1*"
                        Binding="{Binding Speed}"                                
                        HeaderTemplate="{StaticResource CustomHeaderTemplate}">             
            <DataGridTextColumn.Header>
                <cust:HeaderData Name="Speed" Unit="[m/s]" />
            </DataGridTextColumn.Header>
        </DataGridTextColumn>
        <DataGridTextColumn x:Name="SpeedColumn2"
                        Width="1*"
                        Binding="{Binding Speed2}"                                
                        HeaderTemplate="{StaticResource CustomHeaderTemplate}">
            <DataGridTextColumn.Header>
                <cust:HeaderData Name="Speed2" Unit="[km/h]" />
            </DataGridTextColumn.Header>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

答案 1 :(得分:1)

乍一看,你的代码是正常的,应该可行。但是,当您的依赖项属性设置为DataGridTextColumn时,SetUnit未被调用,变量UnitNULL。我尝试在Window中分配附加依赖项属性的值(因为它附加了,你可以在任何地方设置它的值),在这种情况下必须工作:

<Window x:Class="DataGridAttachedHelp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:DataGridAttachedHelp"
    local:CustomHeader.Unit="[m/s]"
    Name="MyWindow"
    Title="MainWindow" Height="350" Width="525"
    WindowStartupLocation="CenterScreen">

<Grid>
    <DataGrid x:Name="tObjectDataGrid" Margin="10,50,10,10" 
              AutoGenerateColumns="False" EnableRowVirtualization="True"                    
              RowDetailsVisibilityMode="VisibleWhenSelected" >

        <DataGrid.Resources>
            <DataTemplate x:Key="CustomHeaderTemplate">
                <StackPanel>
                    <TextBlock Text="{Binding}" />
                    <TextBlock Text="{Binding Path=(local:CustomHeader.Unit), ElementName=MyWindow}" />
                </StackPanel>  
            </DataTemplate>  
        </DataGrid.Resources>  

        <DataGrid.Columns>  
            <DataGridTextColumn x:Name="SpeedColumn" Width="1*" Binding="{Binding Speed}" Header="Speed"
                    HeaderTemplate="{StaticResource CustomHeaderTemplate}" />  
        </DataGrid.Columns>  
    </DataGrid>      
</Grid>
</Window>

在您的情况下,该属性不起作用,因为有必要指明属性的来源,例如:ElementNameSource。因此,只需在参数DataGridTextColumn中添加ElementName的名称:

<TextBlock Text="{Binding Path=(local:CustomHeader.Unit), ElementName=SpeedColumn}" />