This is the DataGrid. Each row represents a tournament object and each cell a property, which can be updated externally. Goal is to highlight the updated value.
UPDATE
While creating a minimal example I found, that the problem is the automatic sorting which immediately removes the formatting again. I guess there is no way around having a map etc. to save the updated state and binding somehow. In the example app below you can trigger that behaviour by sorting a column.
MainWindow.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Media.Animation;
using TurnierChecker.Basic;
using WPFTestProject.Model;
namespace WPFTestProject
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Initial loading of data.
this.TournamentList = new SortableBindingList<Tournament>();
this.TournamentList.ListChanged += this.TournamentListChanged;
// tie View with ViewModel
this.TournamentGrid.DataContext = this.TournamentList;
}
public SortableBindingList<Tournament> TournamentList { get; private set; }
/// <summary>
/// Property change method. Should add a animation / format to the related cell to highlight the change.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="ListChangedEventArgs"/> instance containing the event data.</param>
private void TournamentListChanged(object sender, ListChangedEventArgs e)
{
// Property of tournament change.
if (e.ListChangedType == ListChangedType.ItemChanged)
{
Tournament tmnt = (sender as SortableBindingList<Tournament>)?.ElementAt(e.NewIndex);
DataGridRow row = this.TournamentGrid.ItemContainerGenerator.ContainerFromItem(tmnt) as DataGridRow;
switch (e.PropertyDescriptor?.Name)
{
case nameof(Tournament.Date):
if (row != null)
{
DataGridCell cell = this.GetCell(this.TournamentGrid, row, 0);
if (cell != null)
{
cell.Background = Brushes.Orange;
}
}
break;
case nameof(Tournament.Series):
if (row != null)
{
DataGridCell cell = this.GetCell(this.TournamentGrid, row, 1);
if (cell != null)
{
cell.Background = Brushes.Orange;
}
}
break;
// Default property change.
default:
break;
}
}
}
/// <summary>
/// Gets the visual child.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="parent">The parent.</param>
/// <returns>The child.</returns>
private T GetVisualChild<T>(Visual parent)
where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = this.GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
/// <summary>
/// Gets the cell.
/// </summary>
/// <param name="grid">The grid.</param>
/// <param name="row">The row.</param>
/// <param name="column">The column.</param>
/// <returns>The cell.</returns>
private DataGridCell GetCell(DataGrid grid, DataGridRow row, int column)
{
if (row != null)
{
DataGridCellsPresenter presenter = this.GetVisualChild<DataGridCellsPresenter>(row);
if (presenter == null)
{
grid.ScrollIntoView(row, grid.Columns[column]);
presenter = this.GetVisualChild<DataGridCellsPresenter>(row);
}
DataGridCell cell = (DataGridCell)presenter?.ItemContainerGenerator?.ContainerFromIndex(column);
return cell;
}
return null;
}
/// <summary>
/// Handles the Click event of the AddTournamentButton control. Adds a tournament.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
private void AddTournamentButton_Click(object sender, RoutedEventArgs e)
{
Tournament tmnt = new Tournament();
tmnt.Date = DateTime.Now;
tmnt.Series = "Sample Changing Series Name Nr. " + new Random().Next(1, 10);
this.TournamentList.Add(tmnt);
}
/// <summary>
/// Handles the Click event of the ChangeButton control. Changes a random tournament data.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
private void ChangeButton_Click(object sender, RoutedEventArgs e)
{
int cnt = this.TournamentList.Count();
if (cnt < 1) { return; }
switch (new Random().Next(0,2))
{
case 0:
this.TournamentList[new Random().Next(0, cnt - 1)].Date = DateTime.Now;
break;
case 1:
this.TournamentList[new Random().Next(0, cnt - 1)].Series = "Sample Changing Series Name Nr. " + new Random().Next(1, 10);
break;
}
}
/// <summary>
/// Handles the Click event of the ApplyButton control. Should remove the updated highlight of a cell.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
private void ApplyButton_Click(object sender, RoutedEventArgs e)
{
// How can I remove the applied format / animation from the DataGrid-Cells.
var rows = GetDataGridRows(this.TournamentGrid);
foreach (DataGridRow row in rows)
{
for (int i = 0; i < this.TournamentGrid.Columns.Count;i++)
{
DataGridCell cell = this.GetCell(this.TournamentGrid, row, i);
cell.Background = Brushes.Transparent;
}
}
}
private IEnumerable<DataGridRow> GetDataGridRows(DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row) yield return row;
}
}
}
}
MainWindow.xaml
<Window x:Class="WPFTestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFTestProject"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" FlowDirection="LeftToRight" Orientation="Horizontal">
<Button x:Name="AddTournamentButton" Grid.Row="0" Content="Add" Width="100" Margin="10,10,10,10" Click="AddTournamentButton_Click" />
<Button x:Name="ChangeButton" Grid.Row="0" Content="Change" Width="100" Margin="10,10,10,10" Click="ChangeButton_Click" />
<Button x:Name="ApplyButton" Grid.Row="0" Content="Apply" Width="100" Margin="10,10,10,10" Click="ApplyButton_Click" />
</StackPanel>
<DataGrid x:Name="TournamentGrid" ItemsSource="{Binding}" Grid.Row="1" AlternationCount="2" IsReadOnly="True" HeadersVisibility="Column" AutoGenerateColumns="False" VerticalScrollBarVisibility="Auto" RowHeight="28" SelectionUnit="FullRow">
<DataGrid.Columns>
<!--Tournament Date-->
<DataGridTextColumn Binding="{Binding Date, StringFormat=\{0: ddd dd.MM.yy HH:mm U\\hr\}, ConverterCulture=de-DE}" Header="Datum" Width="160" MinWidth="170" SortDirection="Ascending"/>
<!--Tournament Series-->
<DataGridTextColumn Binding="{Binding Series}" Header="Serie" Width="410" MinWidth="395"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Model: Tournament.cs
namespace WPFTestProject.Model
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
/// <summary>
/// The tournament model.
/// </summary>
public class Tournament : INotifyPropertyChanged
{
/// <summary>
/// The date and time of the tournament.
/// </summary>
private DateTime? date;
/// <summary>
/// The series of the tournament.
/// </summary>
private string series;
/// <summary>
/// Initializes a new instance of the <see cref="Tournament"/> class.
/// </summary>
public Tournament()
{
}
/// <summary>
/// Tritt ein, wenn sich ein Eigenschaftswert ändert.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Gets or sets the date and time of the tournament.
/// </summary>
/// <value>
/// The date and time.
/// </value>
public DateTime? Date
{
get => this.date;
set => this.SetField(ref this.date, value);
}
/// <summary>
/// Gets or sets the series of the tournament.
/// </summary>
/// <value>
/// The series.
/// </value>
public string Series
{
get => this.series;
set => this.SetField(ref this.series, value);
}
/// <summary>
/// Called when [property changed].
/// </summary>
/// <param name="propertyName">Name of the property.</param>
private void OnPropertyChanged(string propertyName) => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
/// <summary>
/// Sets the field.
/// </summary>
/// <typeparam name="T">The property type.</typeparam>
/// <param name="field">The field.</param>
/// <param name="value">The value.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns>Returns true if the property was changed.</returns>
private bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
this.OnPropertyChanged(propertyName);
return true;
}
}
}
Basic: SortableBindingList.cs
namespace WPFTestProject.Model
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
/// <summary>
/// Sortable binding list.
/// </summary>
/// <typeparam name="T">The innertype.</typeparam>
/// <seealso cref="System.ComponentModel.BindingList<T>" />
public class SortableBindingList<T> : BindingList<T>
{
private readonly Dictionary<Type, PropertyComparer<T>> comparers;
private bool isSorted;
private ListSortDirection listSortDirection;
private PropertyDescriptor propertyDescriptor;
/// <summary>
/// Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
/// </summary>
public SortableBindingList()
: base(new List<T>())
{
this.comparers = new Dictionary<Type, PropertyComparer<T>>();
}
/// <summary>
/// Initializes a new instance of the <see cref="SortableBindingList{T}"/> class.
/// </summary>
/// <param name="enumeration">The enumeration.</param>
public SortableBindingList(IEnumerable<T> enumeration)
: base(new List<T>(enumeration))
{
this.comparers = new Dictionary<Type, PropertyComparer<T>>();
}
/// <summary>
/// Gets a value indicating whether the list supports sorting.
/// </summary>
protected override bool SupportsSortingCore
{
get { return true; }
}
/// <summary>
/// Gets a value indicating whether the list is sorted.
/// </summary>
protected override bool IsSortedCore
{
get { return this.isSorted; }
}
/// <summary>
/// Gets the property descriptor that is used for sorting the list if sorting is implemented in a derived class; otherwise, returns <see langword="null" />.
/// </summary>
protected override PropertyDescriptor SortPropertyCore
{
get { return this.propertyDescriptor; }
}
/// <summary>
/// Gets the direction the list is sorted.
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get { return this.listSortDirection; }
}
/// <summary>
/// Gets a value indicating whether the list supports searching.
/// </summary>
protected override bool SupportsSearchingCore
{
get { return true; }
}
/// <summary>
/// Applies the sort core.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="direction">The direction.</param>
protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)
{
var itemsList = (List<T>)this.Items;
if (this.comparers == null)
{
return;
}
Type propertyType = property.PropertyType;
if (!this.comparers.TryGetValue(propertyType, out PropertyComparer<T> comparer))
{
comparer = new PropertyComparer<T>(property, direction);
this.comparers.Add(propertyType, comparer);
}
comparer.SetPropertyAndDirection(property, direction);
itemsList.Sort(comparer);
this.propertyDescriptor = property;
this.listSortDirection = direction;
this.isSorted = true;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
/// <summary>
/// Removes any sort applied with <see cref="M:System.ComponentModel.BindingList`1.ApplySortCore(System.ComponentModel.PropertyDescriptor,System.ComponentModel.ListSortDirection)" />
/// if sorting is implemented in a derived class; otherwise, raises <see cref="T:System.NotSupportedException" />.
/// </summary>
protected override void RemoveSortCore()
{
this.isSorted = false;
this.propertyDescriptor = base.SortPropertyCore;
this.listSortDirection = base.SortDirectionCore;
this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
}
/// <summary>
/// Finds the core.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="key">The key.</param>
/// <returns>The core value.</returns>
protected override int FindCore(PropertyDescriptor property, object key)
{
int count = this.Count;
for (int i = 0; i < count; ++i)
{
T element = this[i];
if (property?.GetValue(element)?.Equals(key) ?? false)
{
return i;
}
}
return -1;
}
}
}
Basic: PropertyComparer.cs
namespace WPFTestProject.Model
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
/// <summary>
/// Property comparer class.
/// </summary>
/// <typeparam name="T">The type.</typeparam>
/// <seealso cref="System.Collections.Generic.IComparer<T>" />
public class PropertyComparer<T> : IComparer<T>
{
private readonly IComparer comparer;
private PropertyDescriptor propertyDescriptor;
private int reverse;
/// <summary>
/// Initializes a new instance of the <see cref="PropertyComparer{T}"/> class.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="direction">The direction.</param>
public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
{
this.propertyDescriptor = property;
Type comparerForPropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);
this.comparer = comparerForPropertyType.InvokeMember("Default", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, null, null, null) as IComparer;
this.SetListSortDirection(direction);
}
/// <summary>
/// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
/// </summary>
/// <param name="x">The first object to compare.</param>
/// <param name="y">The second object to compare.</param>
/// <returns>
/// A signed integer that indicates the relative values of <paramref name="x" /> and <paramref name="y" />, as shown in the following table.
/// <list type="table"><listheader><term> Value</term><description> Meaning</description></listheader><item><term> Less than zero</term><description><paramref name="x" /> is less than <paramref name="y" />.</description></item><item><term> Zero</term><description><paramref name="x" /> equals <paramref name="y" />.</description></item><item><term> Greater than zero</term><description><paramref name="x" /> is greater than <paramref name="y" />.</description></item></list>
/// </returns>
public int Compare(T x, T y)
{
if (this.comparer == null)
{
return this.reverse;
}
else
{
return this.reverse * this.comparer.Compare(this.propertyDescriptor.GetValue(x), this.propertyDescriptor.GetValue(y));
}
}
/// <summary>
/// Sets the property and direction.
/// </summary>
/// <param name="descriptor">The descriptor.</param>
/// <param name="direction">The direction.</param>
public void SetPropertyAndDirection(PropertyDescriptor descriptor, ListSortDirection direction)
{
this.SetPropertyDescriptor(descriptor);
this.SetListSortDirection(direction);
}
private void SetPropertyDescriptor(PropertyDescriptor descriptor)
{
this.propertyDescriptor = descriptor;
}
private void SetListSortDirection(ListSortDirection direction)
{
this.reverse = direction == ListSortDirection.Ascending ? 1 : -1;
}
}
}
My solution is based on BionicCodes answer: I added a HashSet to my Tournament
object which holds the namens of the changed properties. Below is my solution:
MainWindow.xaml
<Window x:Class="WPFTestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:conv="clr-namespace:WPFTestProject.Converter"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<conv:PropertiesUpdatesSetToBoolConverter x:Key="PropertiesUpdatesSetToBoolConverter" />
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource PropertiesUpdatesSetToBoolConverter}">
<Binding Path="Column.Binding.Path.Path" RelativeSource="{RelativeSource Self}" />
<Binding Path="PropertiesUpdatedSet" />
</MultiBinding>
</DataTrigger.Binding>
<DataTrigger.EnterActions >
<BeginStoryboard Name="BlinkingAnimation">
<Storyboard>
<ColorAnimation Duration="00:00:03" RepeatBehavior="Forever" AutoReverse="True" Storyboard.TargetProperty="(DataGridCell.Foreground).(SolidColorBrush.Color)" From="Red" To="Black" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="BlinkingAnimation"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" FlowDirection="LeftToRight" Orientation="Horizontal">
<Button x:Name="AddTournamentButton" Grid.Row="0" Content="Add" Width="100" Margin="10,10,10,10" Click="AddTournamentButton_Click" />
<Button x:Name="ChangeButton" Grid.Row="0" Content="Change" Width="100" Margin="10,10,10,10" Click="ChangeButton_Click" />
<Button x:Name="ApplyButton" Grid.Row="0" Content="Apply" Width="100" Margin="10,10,10,10" Click="ApplyButton_Click" />
</StackPanel>
<DataGrid x:Name="TournamentGrid" ItemsSource="{Binding}" Grid.Row="1" AlternationCount="2" IsReadOnly="True" HeadersVisibility="Column" AutoGenerateColumns="False" VerticalScrollBarVisibility="Auto" RowHeight="28" SelectionUnit="FullRow">
<DataGrid.Columns>
<!--Tournament Date-->
<DataGridTextColumn Binding="{Binding Date, StringFormat=\{0: ddd dd.MM.yy HH:mm U\\hr\}, ConverterCulture=de-DE}" Header="Datum" Width="160" MinWidth="170" SortDirection="Ascending"/>
<!--Tournament Series-->
<DataGridTextColumn Binding="{Binding Series}" Header="Serie" Width="410" MinWidth="395" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Linq;
using System.Windows;
using WPFTestProject.Model;
namespace WPFTestProject
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Initial loading of data.
this.TournamentList = new SortableBindingList<Tournament>();
// tie View with ViewModel
this.TournamentGrid.DataContext = this.TournamentList;
}
public SortableBindingList<Tournament> TournamentList { get; private set; }
/// <summary>
/// Handles the Click event of the AddTournamentButton control. Adds a tournament.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
private void AddTournamentButton_Click(object sender, RoutedEventArgs e)
{
Tournament tmnt = new Tournament();
tmnt.Date = DateTime.Now;
tmnt.Series = "Sample Changing Series Name Nr. " + new Random().Next(1, 10);
this.TournamentList.Add(tmnt);
}
/// <summary>
/// Handles the Click event of the ChangeButton control. Changes a random tournament data.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
private void ChangeButton_Click(object sender, RoutedEventArgs e)
{
int cnt = this.TournamentList.Count();
if (cnt < 1) { return; }
switch (new Random().Next(0,2))
{
case 0:
this.TournamentList[new Random().Next(0, cnt - 1)].Date = DateTime.Now;
break;
case 1:
this.TournamentList[new Random().Next(0, cnt - 1)].Series = "Sample Changing Series Name Nr. " + new Random().Next(1, 10);
break;
}
}
/// <summary>
/// Handles the Click event of the ApplyButton control. Should remove the updated highlight of a cell.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
private void ApplyButton_Click(object sender, RoutedEventArgs e)
{
foreach (Tournament tmnt in this.TournamentList)
{
tmnt.PropertiesUpdatedSet.Clear();
tmnt.OnPropertyChanged(nameof(Tournament.PropertiesUpdatedSet));
}
}
}
}
Model: Tournament.cs
namespace WPFTestProject.Model
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
/// <summary>
/// The tournament model.
/// </summary>
public class Tournament : INotifyPropertyChanged
{
/// <summary>
/// The date and time of the tournament.
/// </summary>
private DateTime? date;
/// <summary>
/// The series of the tournament.
/// </summary>
private string series;
/// <summary>
/// Initializes a new instance of the <see cref="Tournament"/> class.
/// </summary>
public Tournament()
{
PropertiesUpdatedSet = new HashSet<string>();
}
/// <summary>
/// Tritt ein, wenn sich ein Eigenschaftswert ändert.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Gets or sets the date and time of the tournament.
/// </summary>
/// <value>
/// The date and time.
/// </value>
public DateTime? Date
{
get => this.date;
set => this.SetField(ref this.date, value);
}
/// <summary>
/// Gets or sets the series of the tournament.
/// </summary>
/// <value>
/// The series.
/// </value>
public string Series
{
get => this.series;
set => this.SetField(ref this.series, value);
}
public HashSet<string> PropertiesUpdatedSet { get; }
/// <summary>
/// Called when [property changed].
/// </summary>
/// <param name="propertyName">Name of the property.</param>
public void OnPropertyChanged(string propertyName) => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
/// <summary>
/// Sets the field.
/// </summary>
/// <typeparam name="T">The property type.</typeparam>
/// <param name="field">The field.</param>
/// <param name="value">The value.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns>Returns true if the property was changed.</returns>
private bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
this.OnPropertyChanged(propertyName);
if (!PropertiesUpdatedSet.Contains(propertyName))
{
PropertiesUpdatedSet.Add(propertyName);
this.OnPropertyChanged(nameof(PropertiesUpdatedSet));
}
return true;
}
}
}
Converter: PropertiesUpdatesSetToBoolConverter.cs
namespace WPFTestProject.Converter
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Data;
/// <summary>
/// Converts a string value to visibility property.
/// </summary>
/// <seealso cref="IMultiValueConverter" />
public class PropertiesUpdatesSetToBoolConverter : IMultiValueConverter
{
/// <summary>
/// Converts a string value to visibility property.
/// </summary>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value. If the method returns <see langword="null" />, the valid null value is used.
/// </returns>
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value[1] is HashSet<string> flags))
{
return false;
}
if (string.IsNullOrEmpty(value[0]?.ToString())) {
return false;
}
bool result = flags.Contains(value[0].ToString());
return flags.Contains(value[0].ToString());
}
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value that is produced by the binding target.</param>
/// <param name="targetType">The type to convert to.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value. If the method returns <see langword="null" />, the valid null value is used.
/// </returns>
/// <exception cref="NotImplementedException">Not implemented</exception>
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}