如何根据用户输入更改 DataGrid 前景色?
Posted
技术标签:
【中文标题】如何根据用户输入更改 DataGrid 前景色?【英文标题】:How can I change the DataGrid Foreground color based on user input? 【发布时间】:2021-12-03 10:27:12 【问题描述】:我有一个DataGrid
。 DataGrid
中有 12 列。这些列中的每一列都代表 0-255 之间的 byte
值。我想根据用户输入的范围为它们着色。
我不知道如何根据用户输入更改这些值。用户可以为每列指定不同的范围。下面是我手动实现的应用程序。如何将此应用绑定到用户登录。
转换器
public class DataGridColorConverter : IValueConverter
public object Convert(
object value, Type targetType,
object parameter, CultureInfo culture)
byte data = (byte)value;
if (data <= 30)
return 0;
else if (data <= 60)
return 1;
else if (data <= 90)
return 2;
else
return 3;
public object ConvertBack(
object value, Type targetType,
object parameter, CultureInfo culture)
throw new NotImplementedException();
Xaml
<UserControl.Resources>
<my:DataGridColorConverter x:Key="DGCConverter"/>
</UserControl.Resources>
<DataGrid Name="MyDataGrid"
Grid.Row="1"
AutoGenerateColumns="False"
ItemsSource="Binding JobsCollectionView , IsAsync=True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
IsReadOnly="True"
Height="480">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="Binding ID"/>
<DataGridTextColumn Header="RTR" Binding="Binding RTR"/>
<DataGridTextColumn Header="IDE" Binding="Binding IDE"/>
<DataGridTextColumn Header="DLC" Binding="Binding DLC"/>
<DataGridTextColumn Header="BYTE-0" Binding="Binding Byte0"/>
<DataGridTextColumn Header="BYTE-1" Binding="Binding Byte1"/>
<DataGridTextColumn Header="BYTE-2" Binding="Binding Byte2"/>
<DataGridTextColumn Header="BYTE-3" Binding="Binding Byte3"/>
<DataGridTextColumn Header="BYTE-4" Binding="Binding Byte4"/>
<DataGridTextColumn Header="BYTE-5" Binding="Binding Byte5"/>
<DataGridTextColumn Header="BYTE-6" Binding="Binding Byte6"/>
<DataGridTextColumn Header="BYTE-7" Binding="Binding Byte7">
<DataGridTextColumn.ElementStyle>
<Style TargetType="x:Type TextBlock">
<Setter Property="Foreground" Value="Green" />
<Style.Triggers>
<DataTrigger Binding="Binding Byte7,Converter=StaticResource DGCConverter" Value="1">
<Setter Property="Foreground" Value="Yellow" />
</DataTrigger>
<DataTrigger Binding="Binding Byte7,Converter=StaticResource DGCConverter" Value="2">
<Setter Property="Foreground" Value="Orange" />
</DataTrigger>
<DataTrigger Binding="Binding Byte7,Converter=StaticResource DGCConverter" Value="3">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="TIME" Binding="Binding Time, StringFormat=\0:dd.MM.yy HH:mm:ss\"/>
</DataGrid.Columns>
</DataGrid>
注意:我正在使用 MVVM。
注意2:我没有共享用户可以输入值范围的字段,以免在XAML中拥挤。
例如,用户希望Blue
介于 0-100 之间,Red
介于 100-150 之间,Green
介于 150-255 之间。
【问题讨论】:
【参考方案1】:我不知道如何根据用户输入更改这些值。用户可以为每一列指定不同的范围。
如果用户可以指定范围,例如通过Slider
s 或TextBox
es,需要绑定这些值才能对更改做出反应。让我们假设这些值映射到的画笔不需要绑定(还)。 IValueConverter
只能绑定一个值。您可以改为创建一个IMultiValueConverter
,正如其名称所暗示的那样,它可以绑定多个值。具体转换器的外观有多种选择,具体取决于您的视图、视图模型和其他要求。
以下是IMultiValueConverter
的示例,它允许绑定多个byte
属性,其中第一个是要比较的原始data
值,其余的代表每个范围的边界。这些范围的Brush
es 作为parameter
(集合)传递并且不可绑定。如果您希望它们也可绑定,它们也将通过 values
数组传递。此转换器假定所有值都是byte
s,而parameter
是Brush
es 的集合。此外,必须有 不同 范围边界(无重复)和相等数量的 Brush
es(可以重复),否则不存在 1:1 映射(抛出异常)。如果没有绑定值或没有可能的映射,则不会返回画笔。
public class DataGridColorConverter : IMultiValueConverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
if (values == null)
return Binding.DoNothing;
var byteValues = values.Cast<byte>().ToList();
var brushes = ((IEnumerable)parameter).Cast<Brush>().ToList();
var data = byteValues[0];
var bounds = byteValues.Skip(1).Distinct().ToList();
if (bounds.Count != brushes.Count)
throw new ArgumentException("The number of distinct stops must be equal to the number of stop brushes.");
foreach (var (boundary, brush) in bounds.Zip(brushes))
if (data <= boundary)
return brush;
return Binding.DoNothing;
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
throw new NotImplementedException();
在 XAML 中,您可以使用新的转换器通过 MultiBinding
调整您的样式。
<Style TargetType="x:Type TextBlock">
<Setter Property="Foreground">
<Setter.Value>
<MultiBinding Converter="StaticResource DataGridColorConverter">
<MultiBinding.Bindings>
<!-- ...binds the current data context, your BYTE 7. -->
<Binding/>
<!-- ...these bindings may vary depending on the source for binding, view model, text block, ... -->
<Binding Path="MyBlueRangeEndProperty"/>
<Binding Path="MyRedRangeEndProperty"/>
<Binding Path="MyGreenRangeEndProperty"/>
</MultiBinding.Bindings>
<MultiBinding.ConverterParameter>
<!-- ...this array could also be shared (moved to resource and refernce via StaticResource ...). -->
<x:Array Type="x:Type Brush">
<SolidColorBrush Color="Blue"/>
<SolidColorBrush Color="Red"/>
<SolidColorBrush Color="Green"/>
</x:Array>
</MultiBinding.ConverterParameter>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
如上所述,有很多选项可以实现这一点。这对于您的用例来说应该足够了,并且如果颜色数组对于所有列都相同或单独定义,您甚至可以共享颜色数组。
更新关于Zip
编译错误的评论。此扩展方法并非在所有目标框架上都可用。这同样适用于 C# 语言版本和元组解构。但是,在这些情况下,您可以改用简单的 for
循环。
for (var i = 0; i < bounds.Count; i++)
if (data <= bounds[i])
return brushes[i];
【讨论】:
太好了,我得出了接近这个答案的结论。但我心里还是有问号。问号不见了。谢谢。 我在转换函数中的 foreach 中遇到了一些错误。 “方法'Zip'没有重载需要1个参数”和“不包含隐式类型解构变量('boundart')或('brush')的类型”我不明白问题是什么。 我解决了这个问题。我写了一个 for 循环,它返回颜色和值而不是 foreach。据我了解,这是 C# 版本的情况。我应该编辑答案吗? @saklanmaz 谢谢。查看我的最新编辑,我为旧框架和 C# 语言版本添加了解释和替代方案。 另外;如果有非常密集的数据流,我认为这个过程很慢。如果 Binding.DoNothing 返回,它会在 UI 中混淆。如果使用 Brushes.Transparent,则背景没有问题。以上是关于如何根据用户输入更改 DataGrid 前景色?的主要内容,如果未能解决你的问题,请参考以下文章
根据 JasperReports 中的条件更改文本字段数据颜色(前景色)