如何根据DataGrid中数据的变化及时改变背景颜色?
How to change the background color timely depending on the data change in the DataGrid?
我在 DataGrid 中有它。目前,如果数据大于 150,我将行的背景颜色更改为红色,如果数据小于 150,则更改为绿色。我想做的是如果背景颜色改变后 5 秒内数据没有改变,它应该再次变成无色。我不确定如何实施。你能帮忙解决这个问题吗?
我的转换器
class ChangedDataConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var val = (int)value;
return new SolidColorBrush(val > 150 ? Colors.Red : Colors.Green);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
xaml
<Syncfusion:GridTextColumn DisplayBinding="{Binding ID, Converter={StaticResource IntToHexadecimalConverter}}">
<Syncfusion:GridTextColumn.CellStyle>
<Style TargetType="Syncfusion:GridCell">
<Setter Property="Background" Value="{Binding ID, Converter={StaticResource ChangedDataConverter}}"/>
</Style>
</Syncfusion:GridTextColumn.CellStyle>
</Syncfusion:GridTextColumn>
编辑: 我尝试了以下方法。我接近我想要的,但它只发生一次,因为它有一个 Onloaded 事件。我找不到我应该使用哪个 activity。有这样的吗?
<Syncfusion:GridTextColumn DisplayBinding="{Binding ID, Converter={StaticResource ByteToHexadecimalConverter}}" Width="100">
<Syncfusion:GridTextColumn.CellStyle>
<Style TargetType="Syncfusion:GridCell">
<Setter Property = "Background" Value="{Binding ID,Converter={StaticResource ChangedDataConverter}}"/>
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(DataGridRow.Background).(SolidColorBrush.Color)"
Duration="00:00:10"
To="Transparent"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Syncfusion:GridTextColumn.CellStyle>
</Syncfusion:GridTextColumn>
在 MVVM 模式中,它可能看起来像这样:
型号:
public class LineModel : INotifyPropertyChanged
{
private int iD;
public int ID
{
get => iD;
set
{
iD = value;
OnPropertyChanged("ID");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
视图模型:
public class ViewModel : INotifyPropertyChanged
{
public Timer Tmr;
private bool timeOut;
public bool TimeOut
{
get => timeOut;
set
{
timeOut = value;
OnPropertyChanged();
}
}
public ObservableCollection<LineModel> Lines { get; set; }
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
TimeOut = false;
}
void LineModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
TimeOut = Lines != null && e.PropertyName == "ID";
Tmr.Enabled = true;
}
public ViewModel()
{
Tmr = new Timer(5000);
Tmr.Elapsed += OnTimedEvent;
Tmr.AutoReset = false;
var line = new LineModel() { ID = 10 };
line.PropertyChanged += LineModel_PropertyChanged;
Lines = new ObservableCollection<LineModel>() { line };
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
转换器:
class ChangedDataConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is int valInt && values[1] is bool valTimeout)
return new SolidColorBrush(valTimeout && valInt > 150 ? Colors.Red : Colors.Green);
else return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
XAML:
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Width="300">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource ChangedDataConverter}">
<Binding Path="ID"/>
<Binding RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}" Path="DataContext.TimeOut"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
与使用故事板相同:
<DataGrid ItemsSource="{Binding Lines}"
AutoGenerateColumns="False">
<DataGrid.Resources>
<ColorAnimationUsingKeyFrames x:Key="KeyFramesAnimation"
Storyboard.TargetProperty="(DataGridCell.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame
KeyTime="0:0:0.3"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:4.7"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:5"
Value="Green"/>
</ColorAnimationUsingKeyFrames>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ID, Converter={StaticResource IntToBooleanConverter}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<StaticResource ResourceKey="KeyFramesAnimation"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
转换器:
public class IntToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is int valInt ? valInt > 150 : Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
我修复了解决方案,现在它每次都有效。但是我不得不添加一个额外的 class 并重新定义事件。不再需要转换器。
帮手class:
public static class EventMonitor
{
public static readonly RoutedEvent CustomEvent =
EventManager.RegisterRoutedEvent("Greater150", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(EventMonitor));
internal static RoutedEventArgs RaiseAlarmEvent(DependencyObject target)
{
if (target is null) return null;
RoutedEventArgs args = new RoutedEventArgs { RoutedEvent = CustomEvent };
if (target is UIElement) (target as UIElement).RaiseEvent(args);
else if (target is ContentElement) (target as ContentElement).RaiseEvent(args);
return args;
}
public static DataGridCell GetDataGridCell(DataGridCellInfo cellInfo)
{
var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent != null)
return (DataGridCell)cellContent.Parent;
return null;
}
}
XAML:
<DataGrid HorizontalAlignment="Left"
Height="303" Margin="30,78,0,0"
Width="300"
VerticalAlignment="Top"
ItemsSource="{Binding Lines}"
AutoGenerateColumns="False" CellEditEnding="DataGrid_CellEditEnding">
<DataGrid.Resources>
<ColorAnimationUsingKeyFrames x:Key="KeyFramesAnimation"
Storyboard.TargetProperty="(DataGridCell.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame
KeyTime="0:0:0.3"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:4.7"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:5"
Value="Green"/>
</ColorAnimationUsingKeyFrames>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Width="290">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<EventTrigger RoutedEvent="local:EventMonitor.Greater150">
<BeginStoryboard>
<Storyboard>
<StaticResource ResourceKey="KeyFramesAnimation"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
事件处理程序:
private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditingElement is TextBox textBox && double.TryParse(textBox.Text, out double result) && result > 150)
{
EventMonitor.RaiseAlarmEvent(EventMonitor.GetDataGridCell((sender as DataGrid).SelectedCells[0]));
}
}
我在 DataGrid 中有它。目前,如果数据大于 150,我将行的背景颜色更改为红色,如果数据小于 150,则更改为绿色。我想做的是如果背景颜色改变后 5 秒内数据没有改变,它应该再次变成无色。我不确定如何实施。你能帮忙解决这个问题吗?
我的转换器
class ChangedDataConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var val = (int)value;
return new SolidColorBrush(val > 150 ? Colors.Red : Colors.Green);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
xaml
<Syncfusion:GridTextColumn DisplayBinding="{Binding ID, Converter={StaticResource IntToHexadecimalConverter}}">
<Syncfusion:GridTextColumn.CellStyle>
<Style TargetType="Syncfusion:GridCell">
<Setter Property="Background" Value="{Binding ID, Converter={StaticResource ChangedDataConverter}}"/>
</Style>
</Syncfusion:GridTextColumn.CellStyle>
</Syncfusion:GridTextColumn>
编辑: 我尝试了以下方法。我接近我想要的,但它只发生一次,因为它有一个 Onloaded 事件。我找不到我应该使用哪个 activity。有这样的吗?
<Syncfusion:GridTextColumn DisplayBinding="{Binding ID, Converter={StaticResource ByteToHexadecimalConverter}}" Width="100">
<Syncfusion:GridTextColumn.CellStyle>
<Style TargetType="Syncfusion:GridCell">
<Setter Property = "Background" Value="{Binding ID,Converter={StaticResource ChangedDataConverter}}"/>
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(DataGridRow.Background).(SolidColorBrush.Color)"
Duration="00:00:10"
To="Transparent"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Syncfusion:GridTextColumn.CellStyle>
</Syncfusion:GridTextColumn>
在 MVVM 模式中,它可能看起来像这样:
型号:
public class LineModel : INotifyPropertyChanged
{
private int iD;
public int ID
{
get => iD;
set
{
iD = value;
OnPropertyChanged("ID");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
视图模型:
public class ViewModel : INotifyPropertyChanged
{
public Timer Tmr;
private bool timeOut;
public bool TimeOut
{
get => timeOut;
set
{
timeOut = value;
OnPropertyChanged();
}
}
public ObservableCollection<LineModel> Lines { get; set; }
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
TimeOut = false;
}
void LineModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
TimeOut = Lines != null && e.PropertyName == "ID";
Tmr.Enabled = true;
}
public ViewModel()
{
Tmr = new Timer(5000);
Tmr.Elapsed += OnTimedEvent;
Tmr.AutoReset = false;
var line = new LineModel() { ID = 10 };
line.PropertyChanged += LineModel_PropertyChanged;
Lines = new ObservableCollection<LineModel>() { line };
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
转换器:
class ChangedDataConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is int valInt && values[1] is bool valTimeout)
return new SolidColorBrush(valTimeout && valInt > 150 ? Colors.Red : Colors.Green);
else return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
XAML:
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Width="300">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource ChangedDataConverter}">
<Binding Path="ID"/>
<Binding RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}" Path="DataContext.TimeOut"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
与使用故事板相同:
<DataGrid ItemsSource="{Binding Lines}"
AutoGenerateColumns="False">
<DataGrid.Resources>
<ColorAnimationUsingKeyFrames x:Key="KeyFramesAnimation"
Storyboard.TargetProperty="(DataGridCell.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame
KeyTime="0:0:0.3"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:4.7"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:5"
Value="Green"/>
</ColorAnimationUsingKeyFrames>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ID, Converter={StaticResource IntToBooleanConverter}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<StaticResource ResourceKey="KeyFramesAnimation"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
转换器:
public class IntToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is int valInt ? valInt > 150 : Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
我修复了解决方案,现在它每次都有效。但是我不得不添加一个额外的 class 并重新定义事件。不再需要转换器。
帮手class:
public static class EventMonitor
{
public static readonly RoutedEvent CustomEvent =
EventManager.RegisterRoutedEvent("Greater150", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(EventMonitor));
internal static RoutedEventArgs RaiseAlarmEvent(DependencyObject target)
{
if (target is null) return null;
RoutedEventArgs args = new RoutedEventArgs { RoutedEvent = CustomEvent };
if (target is UIElement) (target as UIElement).RaiseEvent(args);
else if (target is ContentElement) (target as ContentElement).RaiseEvent(args);
return args;
}
public static DataGridCell GetDataGridCell(DataGridCellInfo cellInfo)
{
var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent != null)
return (DataGridCell)cellContent.Parent;
return null;
}
}
XAML:
<DataGrid HorizontalAlignment="Left"
Height="303" Margin="30,78,0,0"
Width="300"
VerticalAlignment="Top"
ItemsSource="{Binding Lines}"
AutoGenerateColumns="False" CellEditEnding="DataGrid_CellEditEnding">
<DataGrid.Resources>
<ColorAnimationUsingKeyFrames x:Key="KeyFramesAnimation"
Storyboard.TargetProperty="(DataGridCell.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame
KeyTime="0:0:0.3"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:4.7"
Value="Red"/>
<LinearColorKeyFrame
KeyTime="0:0:5"
Value="Green"/>
</ColorAnimationUsingKeyFrames>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Width="290">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<EventTrigger RoutedEvent="local:EventMonitor.Greater150">
<BeginStoryboard>
<Storyboard>
<StaticResource ResourceKey="KeyFramesAnimation"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
事件处理程序:
private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditingElement is TextBox textBox && double.TryParse(textBox.Text, out double result) && result > 150)
{
EventMonitor.RaiseAlarmEvent(EventMonitor.GetDataGridCell((sender as DataGrid).SelectedCells[0]));
}
}