将默认资源样式应用于所有DataGridTextColumns

时间:2010-11-22 18:52:55

标签: c# wpf wpfdatagrid c#-4.0

我有几个数字列,希望它们是右对齐的。这是一个有点人为的例子,展示了我的问题:

<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=PresentationFramework" xmlns:Windows="clr-namespace:System.Windows;assembly=PresentationFramework" xmlns:Data="clr-namespace:System.Windows.Data;assembly=PresentationFramework" Title="MyApp"
        Width="Auto" Height="Auto" SizeToContent="WidthAndHeight" Loaded="Window_Loaded">
  <Controls:DataGrid Name="MyDataGrid" IsReadOnly="True"
          xmlns="http://schemas.microsoft.com/wpf/2008/toolkit" ItemsSource="{Data:Binding}" AutoGenerateColumns="True">
    <Controls:DataGrid.Columns>
      <!-- This is a product name and is left justified by default -->
      <Controls:DataGridTextColumn Header="ProductName" Binding="{Data:Binding Path=ProductName}" />
      <!-- The rest of the columns are numeric and I would like for them to be right justified -->
      <Controls:DataGridTextColumn Header="ProductId1" Binding="{Data:Binding Path=ProductId1}" >
        <Controls:DataGridTextColumn.ElementStyle>
          <Windows:Style TargetType="Controls:TextBlock">
            <Windows:Setter Property="HorizontalAlignment" Value="Right"/>
          </Windows:Style>
        </Controls:DataGridTextColumn.ElementStyle>
      </Controls:DataGridTextColumn>
      <Controls:DataGridTextColumn Header="ProductId2" Binding="{Data:Binding Path=ProductId2}" >
        <Controls:DataGridTextColumn.ElementStyle>
          <Windows:Style TargetType="Controls:TextBlock">
            <Windows:Setter Property="HorizontalAlignment" Value="Right"/>
          </Windows:Style>
        </Controls:DataGridTextColumn.ElementStyle>
      </Controls:DataGridTextColumn>
      <Controls:DataGridTextColumn Header="ProductId3" Binding="{Data:Binding Path=ProductId3}" >
        <Controls:DataGridTextColumn.ElementStyle>
          <Windows:Style TargetType="Controls:TextBlock">
            <Windows:Setter Property="HorizontalAlignment" Value="Right"/>
          </Windows:Style>
        </Controls:DataGridTextColumn.ElementStyle>
      </Controls:DataGridTextColumn>
      <!-- More numeric columns follow... -->
    </Controls:DataGrid.Columns>
  </Controls:DataGrid>
</Window>

对于除第一列之外的所有列重复右对齐样式并且看起来多余。如果我只能将此网格中的DataGridTextColumns设置为右对齐,那么我只需要明确地左对齐第一列。我怎么能这样做,也许使用样式作为资源?还有更好的方法吗?

1 个答案:

答案 0 :(得分:7)

DataGridTextColumn不是从FrameworkElement派生的,因此您无法为其创建开箱即用的样式。

最简单的方法是创建一个Style for DataGridCell并从那里右对齐TextBlock。然后为不应该具有此列的列设置CellStyle = {x:Null}(或您可能需要的任何其他样式)

<Controls:DataGrid ...>
    <Controls:DataGrid.Resources>
        <Windows.Style TargetType="Controls:DataGridCell">
            <Windows.Setter Property="TextBlock.HorizontalAlignment" Value="Right"/>
        </Windows.Style>
    </Controls:DataGrid.Resources>
    <Controls:DataGrid.Columns>
        <!-- This is a product name and is left justified by default -->
        <Controls:DataGridTextColumn Header="ProductName"
                                     Binding="{Binding Path=ProductName}"
                                     CellStyle="{x:Null}"/>

更新

但是如果你想将一个Style应用于DataGridTextColumn,则需要这样的东西。

首先我们需要一个可以“持有样式”的辅助类。在其中,我们添加了我们希望能够设置的所有属性(不在FrameworkElement中)。在这种情况下,ElementStyle。

public class DataGridTextColumnStyleHelper : FrameworkElement
{
    public DataGridTextColumnStyleHelper(){}
    public static readonly DependencyProperty ElementStyleProperty =
        DependencyProperty.Register(
            "ElementStyle",
            typeof(Style),
            typeof(DataGridTextColumnStyleHelper));
    public Style ElementStyle
    {
        get { return (Style)GetValue(ElementStyleProperty); }
        set { SetValue(ElementStyleProperty, value); }
    }
}

然后我们在xaml中添加Style

<Style x:Key="DataGridTextColumnStyle"
       TargetType="local:DataGridTextColumnStyleHelper">
    <Setter Property="ElementStyle">
        <Setter.Value>
            <Style TargetType="TextBlock">
                <Setter Property="HorizontalAlignment" Value="Right"/>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

为了能够在DataGridTextColumn上应用此Style,我们需要另一个带有TextColumnStyle属性的Helper类。在其中,我们使用反射和SetValue来应用样式。

public class MyDataGridHelper : DependencyObject 
{
    private static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.RegisterAttached(
        "TextColumnStyle",
        typeof(Style),
        typeof(MyDataGridHelper),
        new PropertyMetadata(MyPropertyChangedCallback));
    public static void SetTextColumnStyle(DependencyObject element, string value)
    {
        element.SetValue(TextColumnStyleProperty, value);
    }
    public static Style GetTextColumnStyle(DependencyObject element)
    {
        return (Style)element.GetValue(TextColumnStyleProperty);
    }
    private static void MyPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (DesignerProperties.GetIsInDesignMode(d) == true)
        {
            return;
        }
        DataGridTextColumn textColumn = (DataGridTextColumn)d;
        Style textColumnStyle = e.NewValue as Style;
        foreach (SetterBase setterBase in textColumnStyle.Setters)
        {
            if (setterBase is Setter)
            {
                Setter setter = setterBase as Setter;
                if (setter.Value is BindingBase)
                {
                    //Not done yet..
                }
                else
                {
                    Type type = textColumn.GetType();
                    PropertyInfo propertyInfo = type.GetProperty(setter.Property.Name);
                    propertyInfo.SetValue(textColumn, setter.Value, null);
                }
            }
        }
    }
}

最后,我们可以像这样使用DataGridTextColumn上的Style

<DataGridTextColumn Header="ProductId1"  Binding="{Binding Path=ProductId1}"
    local:MyDataGridHelper.TextColumnStyle="{StaticResource DataGridTextColumnStyle}">