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 – 相关行是否是其组的最后一行(组中的所有项共享相同的数字). 数据绑定在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(); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |