微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 在多行条件下格式化WPF DataGrid

我有一个 WPF DataGrid与这样的数据

Number  | Attribute  | Old     | New         |
=============================================|
1       | Height     | 1.1     | 0.9         |
--------+------------+---------+-------------|
1       | Material   | Steel1  | Steel2      |
--------+------------+---------+-------------|
2       | Color      | Green   | Light-Green |
--------+------------+---------+-------------|

由于相同的数字,前两个记录属于一起,我想删除两个记录之间的边界,所以它看起来像这样

Number  | Attribute  | Old     | New         |
=============================================|
1       | Height     | 1.1     | 0.9         |
1       | Material   | Steel1  | Steel2      |
--------+------------+---------+-------------|
2       | Color      | Green   | Light-Green |
--------+------------+---------+-------------|

我有一种方法来加载格式化行

private void myGrid_LoadingRow(object sender,DataGridRowEventArgs e) {
        ...
}

但是这只能在这一行的数据上格式化,而且我不知道之后或之前的哪一行.所以我无法决定如何格式化此行的边框.

如何根据不仅当前行但上一行和后一行的信息来格式化行?

解决方法

我写了一个简单的示例应用程序,它只有一个XAML文件代码隐藏.要重新创建我所做的,只需创建一个新的WPF 4.5应用程序,并将下面的代码粘贴到正确的文件中.

我的解决方案使用视图模型,它允许您使用数据绑定执行所有操作(并且不需要您在代码隐藏中连接事件).

这可能看起来比您预期的代码要多得多,但请记住,这是一个完整的示例,其中很多只是设置.对于真正重要的代码,希望你会发现,即使它增加了相当多的行,它为你提供了一个非常强大的模板,用于在WPF中创建各种很酷的用户界面.我在每个代码文件添加了一些注释,希望能让它更容易理解代码的作用.

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="350"
        Width="525"
        d:DataContext="{d:DesignInstance Type=wpfApplication1:Mainviewmodel,IsDesignTimeCreatable=False}">
    <DataGrid AutoGenerateColumns="False"
              ItemsSource="{Binding AttributeUpdateviewmodels}"
              GridLinesVisibility="Vertical">
        <DataGrid.RowStyle>
            <Style targettype="DataGridRow">
                <Setter Property="BorderThickness"
                        Value="{Binding BorderThickness}" />
                <Setter Property="BorderBrush"
                        Value="Black" />
            </Style>
        </DataGrid.RowStyle>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Number"
                                Binding="{Binding Number}" />
            <DataGridTextColumn Header="Attribute"
                                Binding="{Binding Attribute}" />
            <DataGridTextColumn Header="Old"
                                Binding="{Binding Old}" />
            <DataGridTextColumn Header="New"
                                Binding="{Binding New}" />
        </DataGrid.Columns>
    </DataGrid>
</Window>

这基本上只是一个带有文本列的简单数据网格.神奇的是自定义行样式,可根据需要创建水平网格线. (有关数据绑定的更多详细信息,请参见下文.)

MainWindow.xaml.cs(即代码隐藏):

using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new Mainviewmodel();
        }
    }

    public class Mainviewmodel
    {
        public List<AttributeUpdateviewmodel> AttributeUpdateviewmodels { get; set; }

        public Mainviewmodel()
        {
            var rawAttributeUpdates = new[]
            {
            new AttributeUpdate { Number = 1,Attribute = "Height",Old = "1.1",New = "0.9" },new AttributeUpdate { Number = 1,Attribute = "Material",Old = "Steel1",New = "Steel2" },new AttributeUpdate { Number = 2,Attribute = "Color",Old = "Green",New = "Light-Green" },new AttributeUpdate { Number = 3,Attribute = "Attribute4",Old = "Old4",New = "New4" },Attribute = "Attribute5",Old = "Old5",New = "New5" },Attribute = "Attribute6",Old = "Old6",New = "New6" },new AttributeUpdate { Number = 4,Attribute = "Attribute7",Old = "Old7",New = "New7" },new AttributeUpdate { Number = 5,Attribute = "Attribute8",Old = "Old8",New = "New8" },Attribute = "Attribute9",Old = "Old9",New = "New9" },Attribute = "Attribute10",Old = "Old10",New = "New10" }
            };
            var sortedAttributeUpdates = rawAttributeUpdates.OrderBy(x => x.Number);
            var groupedAttributeUpdates = sortedAttributeUpdates
                .GroupBy(x => x.Number);
            AttributeUpdateviewmodels = sortedAttributeUpdates
                .Select(x => GetAttributeUpdateRow(x,groupedAttributeUpdates))
                .ToList();
        }

        private AttributeUpdateviewmodel GetAttributeUpdateRow(
            AttributeUpdate attributeUpdate,IEnumerable<IGrouping<int,AttributeUpdate>> groupedAttributeUpdates)
        {
            var lastInGroup = groupedAttributeUpdates.Single(x => x.Key == attributeUpdate.Number).Last();
            return new AttributeUpdateviewmodel
            {
                Number = attributeUpdate.Number,Attribute = attributeUpdate.Attribute,New = attributeUpdate.New,Old = attributeUpdate.Old,IsLastInGroup = attributeUpdate == lastInGroup
            };
        }
    }

    public class AttributeUpdate
    {
        public int Number { get; set; }
        public string Attribute { get; set; }
        public string Old { get; set; }
        public string New { get; set; }
    }

    public class AttributeUpdateviewmodel
    {
        public int Number { get; set; }
        public string Attribute { get; set; }
        public string Old { get; set; }
        public string New { get; set; }

        public bool IsLastInGroup { get; set; }

        public Thickness BorderThickness
        {
            get { return IsLastInGroup ? new Thickness(0,1) : new Thickness(); }
        }
    }
}

基本上,我假设您在表的每一行中显示的数据是AttributeUpdate. (我刚刚做了,你可能有一个更好的名字.)

由于AttributeUpdate是纯数据并且与数据的格式化无关,因此我创建了一个AttributeUpdateviewmodel来组合显示所需的数据和格式信息.

因此,AttributeUpdate和AttributeUpdateviewmodel共享相同的数据,但视图模型添加了一些处理格式的属性.

用于格式化的新属性是什么?

> IsLastInGroup – 相关行是否是其组的最后一行(组中的所有项共享相同的数字).
> BorderThickness – 边框的厚度.在这种情况下,如果项目在组中的最后一个,则底部边框为1,其他所有项为零,否则为0.

数据绑定在XAML文件显示为{Binding name_of_property},只需点击视图模型中的数据和格式信息即可.如果基础数据在应用程序运行期间可能发生变化,您将需要让视图模型实现INotifyPropertyChanged interface. INotifyPropertyChanged实际上为您的应用程序添加了“更改检测”,允许您的绑定自动重新绑定到新的/更改的数据.

最后一点是我使用LINQ query来处理分组逻辑.此特定查询按Number对行进行排序,然后按Number对它们进行分组.然后,它创建AttributeUpdateviewmodel实例,根据当前AttributeUpdate是否与其组中的最后一项匹配来填充IsLastInGroup.

注意:为了简单起见,我将几个类放在一个文件中.通常的约定是每个文件一个类,因此您可能希望将每个类分解为自己的文件.

结果

编辑

@Mike Strobel的评论指出按数字排序可能不一定是可取的.例如,用户可能希望按其他列排序,但仍会看到按Number分组的行.我不确定这是一个常见的用例,但是如果这是一个要求,你可以简单地用另一个将“当前”值与“next”值进行比较的LINQ查询替换,然后确定Number是否改变.这是我的解决方案:

var nextAttributeUpdates = rawAttributeUpdates
    .Skip(1)
    .Concat(new[] { new AttributeUpdate { Number = -1 } });
AttributeUpdateviewmodels = rawAttributeUpdates
    .Zip(
        nextAttributeUpdates,(c,n) => new { Current = c,NextNumber = n.Number })
    .Select(
        x => new AttributeUpdateviewmodel
        {
            Number = x.Current.Number,Attribute = x.Current.Attribute,New = x.Current.New,Old = x.Current.Old,IsLastInGroup = x.Current.Number != x.NextNumber
        })
    .ToList();

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐