Примените стиль ресурса по умолчанию ко всем DataGridTextColumns - PullRequest
2 голосов
/ 22 ноября 2010

У меня есть несколько числовых столбцов, и я хочу, чтобы они были правильно выровнены. Вот несколько надуманный пример, демонстрирующий мою проблему:

<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 Ответ

7 голосов
/ 23 ноября 2010

DataGridTextColumn не является производным от FrameworkElement, поэтому вы не можете создать стиль для него "из коробки".

Самый простой способ сделать то, что вам нужно, это создать стиль для 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}"/>

Обновление

Ноесли вы хотите применить стиль к 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 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, нам нужен другой класс Helper со свойством TextColumnStyle,В нем мы применяем стиль с помощью отражений и 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, например:

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