WPF Datagrid выровнять цифры по столбцам вправо - PullRequest
4 голосов
/ 20 июля 2011

Я пытаюсь создать стиль для ячеек DataGrid в моем приложении. Я полагаю, что, возможно, есть способ выровнять числовые ячейки в DataGrid с помощью DataTrigger. Это вообще возможно?

Мой стиль для моей DataGrid такой:

<Style TargetType="{x:Type DataGrid}">
    <Setter Property="AlternatingRowBackground">
        <Setter.Value>
            <SolidColorBrush Color="#CCCCCC" />
        </Setter.Value>
    </Setter>
    <Setter Property="CanUserAddRows" Value="False" />
    <Setter Property="CanUserDeleteRows" Value="False" />
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                <GradientStop Offset="0" Color="#CCCCCC" />
                <GradientStop Offset="1" Color="#FFFFFF" />
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="RowHeaderWidth" Value="0" />
    <Setter Property="CellStyle">
        <Setter.Value>
            <Style TargetType="{x:Type DataGridCell}">
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Background">
                            <Setter.Value>
                                <SolidColorBrush Color="#7777FF" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

Я подумываю о том, чтобы добавить в CellStyle какой-то триггер, чтобы определить, является ли содержимое числовым (int, double, decimal, ...) и соответствующим образом оформить ячейку. Это возможно?

Обновление

Думая об этом, я попробовал несколько вещей, но это не сработало. Я пытался использовать DataTrigger, определенный как:

<DataTrigger Binding="{Binding Converter={StaticResource IsNumericConverter}}" Value="True">
    <Setter Property="HorizontalContentAlignment" Value="Right" />
</DataTrigger>

Где IsNumericConverter:

public class IsNumericConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is int || (value is decimal || value is double);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Но когда я устанавливаю точку останова на преобразователе, я получаю, что значение имеет тип целой строки, а не каждой отдельной ячейки ...

Ответы [ 3 ]

1 голос
/ 24 июля 2014

Я знаю, что это три года, но я смог сделать это без добавления какого-либо кода в код, и я подумал, что поделюсь как.используя эту статью в качестве модели: ссылка

Она использует многосвязывание как способ решения исходной проблемы передачи строки в конвертер.

добавьте это в свою таблицу данных:

CellStyle="{StaticResource CellRightAlignStyle }"

затем добавьте этот стиль в свой xaml, вы должны добавить его в качестве ресурса:

<Window.Resources>

    <Style x:Key="CellRightAlignStyle" TargetType="{x:Type DataGridCell}">
        <Setter Property="HorizontalAlignment">
            <Setter.Value>
                <MultiBinding
                    Converter="{converters:IsNumericConverter}" >
                    <MultiBinding.Bindings>
                        <Binding RelativeSource="{RelativeSource Self}"/>
                        <Binding Path="Row" Mode="OneWay"/>
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>

</Window.Resources>

Затем конвертер:

    public object Convert(
        object[] values,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
    if (values[1] is DataRow)
        {
            //change the text alignment left or right.
            var cell = (DataGridCell)values[0];
            var row = (DataRow)values[1];
            var columnName = cell.Column.SortMemberPath;

            if (row[columnName] is int || (row[columnName] is decimal ||   row[columnName] is double))
            return System.Windows.HorizontalAlignment.Right;
        }
    return System.Windows.HorizontalAlignment.Left;
    }

    public override object ConvertBack(
        object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        return null;
    }

, то естьтеперь все ваши ячейки, содержащие числовые данные, должны быть выровнены по правому краю!

1 голос
/ 20 июля 2011

Один из способов сделать это - установить триггеры в коде позади.Следующий метод применяет триггер к DataGridColumn.Этот триггер использует ваш IsNumericConverter, чтобы определить, следует ли выполнить выравнивание по правому краю:

    public static void AddTriggerToColumnStyle(DataGridColumn column)
    {
        var boundColumn = column as DataGridBoundColumn;
        if (boundColumn != null && boundColumn.Binding is Binding)
        {
            string bindingPropertyPath = (boundColumn.Binding as Binding).Path.Path;
            column.CellStyle = new Style()
            {
                BasedOn = column.CellStyle,
                TargetType = typeof(DataGridCell),
                Triggers =
                {
                    new DataTrigger
                    {
                        Binding = new Binding(bindingPropertyPath) { Converter = new IsNumericConverter() },
                        Value = true,
                        Setters =
                        {
                            new Setter
                            {
                                Property = TextBlock.TextAlignmentProperty,
                                Value = TextAlignment.Right
                            }
                        }
                    }
                }
            };
        }
    }

Этот метод должен быть безопасно вызываться после InitializeComponent() в конструкторе выделенного кода.

Этот подход будет работать, если столбец содержит смесь числовых и нечисловых данных.Если столбцы содержат данные только одного типа, то этот подход все равно будет работать, но созданные триггеры либо никогда не сработают, либо останутся запущенными постоянно.

Конечно, вышеупомянутый метод не должен повторяться вкод для каждого элемента управления, который использует DataGrids.Вы можете переместить его в статический служебный класс, и все ваши классы кода будут вызывать этот метод.Вы даже можете добавить метод статической утилиты, который проходит по столбцам в DataGrid, который вы передаете, и вызывает вышеупомянутый метод для каждого столбца.

UPDATE : я изменил вышеупомянутый метод, чтобы разрешить еговывести обязательный путь-свойства.Это облегчает использование.Я также сделал метод public и static, чтобы было понятно, что его можно переместить в статический служебный класс.

Я подумал о другом подходе, который будет проходить через все столбцы вDataGrid, проверяйте привязки, определяйте тип привязанного свойства и применяйте выравнивание по столбцу по правому краю.Это позволит избежать создания триггеров, которые никогда не сработают или останутся постоянно запущенными, и, возможно, подойдет для случая, когда каждый столбец содержит данные одного типа только немного лучше.Тем не менее, этот подход по-прежнему будет включать в себя выделение кода, ему необходимо будет передать тип, к которому будет привязана каждая строка, и он будет усложнен, если пути привязки свойств будут включать в себя нечто большее, чем одно имя свойства.

Боюсь, я не вижу решения этой проблемы, которое использует только Style s и избегает кода позади.

0 голосов
/ 02 июля 2019

Я использую конвертер для создания строки фиксированной длины и моноширинного шрифта для просмотра.

Преобразователь:

public class AlignRightConverter : IValueConverter // samples: _10 F2_14 C2_16
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            if (parameter == null) throw new Exception("Format is missing");

            var parameterStr = "" + parameter;

            if (!parameterStr.Contains('_')) throw new Exception("Unknown format");

            var parameterParts = parameterStr.Split('_');

            var format = parameterParts[0];

            var lengthStr = parameterParts[1];

            var length = int.TryParse(lengthStr, out int l) ? l : 12;

            if (value == null) return new String(' ', length);

            var type = value.GetType();

            String targetStr;

            if (type == typeof(Double) && format.Length > 0) targetStr = ((Double)value).ToString(format, CultureInfo.GetCultureInfo("ru-ru"));
            else
            if (type == typeof(Single) && format.Length > 0) targetStr = ((Single)value).ToString(format, CultureInfo.GetCultureInfo("ru-ru"));
            else
            if (type == typeof(Int32) && format.Length > 0) targetStr = ((Int32)value).ToString(format, CultureInfo.GetCultureInfo("ru-ru"));
            else
                targetStr = value.ToString();

            if (targetStr.Length >= length) return targetStr;
            else
                return new String(' ', length - targetStr.Length) + targetStr;
        }
        catch (Exception exception)
        {
            exception.Log($"Failed convert to string value {value} with parameters {parameter}");

            return "" + value;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Вид:

<DataGridTextColumn Header="Цена покупки" Binding="{Binding Data.CostBuy.Value, Converter={StaticResource AlignRightConverter}, ConverterParameter=C2_16}"  FontFamily="Courier New"  />

Результат:

Result

...