'How to change the background color timely depending on the data change in the DataGrid?
I have it in a DataGrid. Currently I am changing the background color of the row to be Red if the data is greater than 150 then green if less. What I want to do is if the data does not change within 5 seconds after the background color changes, it should turn colorless again. I wasn't sure how to implement this. Can you please help with this?
My Converter
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>
Edit: I tried the following way. I'm close to what I want, but it only happens once because it has an Onloaded event. I couldn't find which activity I should use. Is there anything like that ?
<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>
Solution 1:[1]
In the MVVM pattern, it might look like this:
Model:
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));
}
}
ViewModel:
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));
}
}
Converter:
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>
Solution 2:[2]
I fixed the solution, now it works every time. But I had to add an additional class and redefine the event. The converter is no longer needed.
The helper 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>
Event Handler:
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]));
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alexander Shapovalov |
| Solution 2 | Alexander Shapovalov |
