WPF MVVM DataGrid:根据选中行值设置单元格背景色
解决WPF DataGrid选中行后动态对比单元格背景色问题
场景概述
开发WPF应用收集不同版本设备的设置(单设备约500项,设置数量/内容随版本增减),使用Dictionary<string, string>存储单设备设置,转换为DataTable绑定到DataGrid实现可视化。需求:选中某行后,其他行同列单元格值与选中行相同则显示绿色背景,不同则显示红色背景,切换选中行时自动更新背景色。
解决方案
1. 优化ViewModel选中行数据获取逻辑
原CellSelected方法循环SelectedCells效率较低,利用SelectionUnit="FullRow"的特性,直接获取选中的DataRowView并转换为Dictionary:
private void CellSelected(object o) { DataGrid dataGrid = o as DataGrid; if (dataGrid?.SelectedItem is DataRowView selectedRowView) { var newSelectedUnit = selectedRowView.Row.Table.Columns .Cast<DataColumn>() .ToDictionary(col => col.ColumnName, col => selectedRowView.Row[col].ToString()); SelectedUnit = newSelectedUnit; } }
2. 实现MultiValueConverter处理背景色逻辑
创建转换器,接收三个参数:当前单元格值、选中行对应列的值、当前行是否选中,根据对比结果返回对应背景色:
using System.Globalization; using System.Windows.Data; using System.Windows.Media; namespace WpfApp1 { public class CellBackgroundConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length != 3) return Brushes.Transparent; bool isCurrentRowSelected = (bool)values[2]; if (isCurrentRowSelected) { return Brushes.Blue; // 选中行保持蓝色背景 } string cellValue = values[0]?.ToString() ?? "-"; string selectedValue = values[1]?.ToString() ?? "-"; return cellValue.Equals(selectedValue, StringComparison.Ordinal) ? Brushes.Green : Brushes.Red; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } }
3. 修改DataGrid的CellStyle绑定逻辑
通过MultiBinding将所需参数传递给转换器,替换原有的静态触发器:
<DataGrid.CellStyle> <Style TargetType="DataGridCell"> <Setter Property="Background"> <Setter.Value> <MultiBinding Converter="{StaticResource CellBackgroundConverter}"> <!-- 当前单元格的值 --> <Binding Path="Content.Text" RelativeSource="{RelativeSource Self}" /> <!-- 选中行对应列的值:通过列头名称从SelectedUnit字典中获取 --> <Binding Path="DataContext.SelectedUnit[{Binding Path=Column.Header, RelativeSource={RelativeSource Self}}]" RelativeSource="{RelativeSource AncestorType=DataGrid}" /> <!-- 当前行是否被选中 --> <Binding Path="IsSelected" RelativeSource="{RelativeSource AncestorType=DataGridRow}" /> </MultiBinding> </Setter.Value> </Setter> <!-- 可选:增强选中行的视觉效果 --> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="BorderBrush" Value="Black" /> <Setter Property="BorderThickness" Value="2" /> </Trigger> </Style.Triggers> </Style> </DataGrid.CellStyle>
关键说明
- 转换器中统一处理
null值为"-",与ViewModel中缺失设置的填充逻辑保持一致,避免对比异常 MultiBinding仅在三个绑定值(单元格值、选中行数据、行选中状态)变化时触发转换,减少不必要的计算- 选中行保持蓝色背景,未选中行根据值对比结果显示绿/红,完全匹配需求
内容的提问来源于stack exchange,提问作者nilsakesson
相关产品推荐
相关产品推荐

