如何根据用户输入更改 DataGrid 前景颜色?
How can I change the DataGrid Foreground color based on user input?
我有一个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 之间。
I don't know how I can change these values based on user input. The user can specify different ranges for each column.
如果用户可以指定范围,例如通过 Slider
s 或 TextBox
es,需要绑定这些值才能对变化做出反应。假设这些值映射到的画笔不需要绑定(目前)。 IValueConverter
只能绑定一个值。您可以创建一个 IMultiValueConverter
,正如其名称所示,它可以绑定多个值。具体转换器的外观有多种选择,具体取决于您的视图、视图模型和其他要求。
下面是一个IMultiValueConverter
的例子,它允许绑定多个byte
属性,其中第一个是要比较的原始data
值,其余代表的边界每个范围。这些范围的 Brush
es 作为 parameter
(集合)传递并且不可绑定。如果您希望它们也可绑定,它们也将通过 values
数组传递。此转换器假定所有值都是 byte
,而 parameter
是 Brush
的集合。此外,必须有 distinct 范围边界(无重复)和相等数量的 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];
}
我有一个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 之间。
I don't know how I can change these values based on user input. The user can specify different ranges for each column.
如果用户可以指定范围,例如通过 Slider
s 或 TextBox
es,需要绑定这些值才能对变化做出反应。假设这些值映射到的画笔不需要绑定(目前)。 IValueConverter
只能绑定一个值。您可以创建一个 IMultiValueConverter
,正如其名称所示,它可以绑定多个值。具体转换器的外观有多种选择,具体取决于您的视图、视图模型和其他要求。
下面是一个IMultiValueConverter
的例子,它允许绑定多个byte
属性,其中第一个是要比较的原始data
值,其余代表的边界每个范围。这些范围的 Brush
es 作为 parameter
(集合)传递并且不可绑定。如果您希望它们也可绑定,它们也将通过 values
数组传递。此转换器假定所有值都是 byte
,而 parameter
是 Brush
的集合。此外,必须有 distinct 范围边界(无重复)和相等数量的 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];
}