WPF数据表格数字列右对齐

5

我希望为我的应用程序中的DataGrid单元格创建一个样式。我想知道是否有一种方法可以使用DataTrigger来右对齐DataGrid中的数字单元格。这个有可能吗?

我为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个回答

3

一种实现这个的方法是在代码后台设置触发器。以下方法将一个触发器应用于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()方法后,可以安全地调用此方法。

如果列包含数字和非数字数据的混合,则该方法可行。如果列仅包含一种类型的数据,则该方法仍然可行,但创建的触发器将永远不会触发或保持永久触发状态。

当然,上述方法不必为每个使用DataGrid的控件在代码后台中重复。您可以将其移动到静态实用程序类中,并使所有代码后台类调用此方法。您甚至可以添加一个静态实用程序方法,该方法循环遍历您传递的DataGrid中的列,并为每个列调用上述方法。

更新:我修改了上述方法以允许其推断绑定属性路径。这使得它更易于使用。我还将该方法设置为publicstatic,以便清楚地表明它可以移动到静态实用程序类中。

我想到了另一种方法,可以运行通过DataGrid中的所有列,检查绑定,推断绑定到的属性类型并将右对齐应用于列。这将避免创建永远不会触发或保持永久触发状态的触发器,并且可能更适合每个列仅包含一种类型数据的情况。但是,这种方法仍涉及到代码后台,需要传递每行将绑定到的类型,并且如果绑定属性路径涉及多个属性名称,则会变得复杂。

很遗憾,我看不到只使用Style并避免代码后台的解决方案。


这并不完全正确。我想为我的应用程序中的每个DataGrid的所有单元格/列(每列仅具有一种类型的值)定义一个样式,以便如果它是数字(double,int,decimal等),则右对齐。 - Carles Company
@Carles:我更新了我的答案,使上面的方法更易于使用。如果你在某个静态实用程序类中设置了上述方法,并添加了一个静态实用程序方法来循环遍历所有DataGrid列,那么你应该能够使用这个方法并且每个DataGrid只需要多加一行代码。也许这对你来说会更好? - Luke Woodward

2

我知道这篇文章已经有三年的历史了,但我成功地完成了这项任务,而没有在后端代码中添加任何代码,并且我想分享一下我的做法。使用这篇文章作为一个范例:链接

它使用多绑定作为解决您原始问题的一种方法,即传递一行到转换器。

将此添加到您的数据网格:

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;
    }

现在,您的包含数字数据的单元格应该右对齐!


非常有用,但需要注意的是 - 右对齐只适用于整数。浮点值需要通过小数点进行对齐,而这不是HorizontalAlignment选项。 - marklam

0

我使用转换器创建固定长度的字符串,并使用等宽字体进行查看。

转换器:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接