I have converter for applying background color for DataGrid rows based on values in one column. It is working fine and is applying background color "on load". However I decided to dive deeper into WPF and MVVM and try to attach this event to CheckBox, but failed at this point. I am not getting any errors but my CheckBox does not work either. Any suggestions what should be edited? I guess I need to attach Convert
event somehow to BacgroundColorBool
?
IDToBackgroundConverter.cs:
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace Inspector_FilterTest
{
class IDToBackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string)
{
if (value.ToString().Trim().StartsWith("7")) return Brushes.DarkSlateBlue;
if (value.ToString().Trim().StartsWith("6")) return Brushes.Peru;
}
// value is not an integer. Do not throw an exception
// in the converter, but return something that is obviously wrong
return Brushes.Firebrick;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I use it in XAML:
<Window.Resources>
<Inspector_FilterTest:IDToBackgroundConverter x:Key="IDToBackgroundConverter"/>
</Window.Resources>
...
<DataGrid x:Name="DataGrid1" ItemsSource="{Binding MainDataTable}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" >
<Setter Property="Background" Value="{Binding YRNRO, Converter={StaticResource IDToBackgroundConverter}}" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
This is working fine and background colors are set (based on starting number in YRNRO) when I am loading my DataGrid. However I would like to be able to control this with CheckBox.
I have created a CheckBox:
ViewModel_Main.cs:
// Binding checkbox background color
private bool _BacgroundColorBool;
public bool BacgroundColorBool
{
get => this._BacgroundColorBool;
set
{
this._BacgroundColorBool = value;
OnPropertyChanged();
// Refresh the DataTable filter expression
EnableRowFiltering();
}
}
XAML:
<CheckBox Style="{StaticResource MyCheckBox}" IsChecked="{Binding BacgroundColorBool}" x:Name="ActiveCustomer_Copy" Content="" HorizontalAlignment="Left" Margin="221,55,0,0" VerticalAlignment="Top"/>
but I don't understand how to connect this all together in order to be able to control "background fill applied"/"background fill not applied" with CheckBox.
EDIT:
Some corrections done to code originally provided by BionicCode (no errors in debugger anymore, I hope this is correct?). In order to get color back to transparent in Datagrid after CheckBox is unchecked pay attention to return Brushes.Transparent;
. That is where you can apply "revertBack" logic.
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace Liinos_inspector_FilterTest
{
class IDToBackgroundConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// The order of the parameters in the 'values' array is equal to the order
// of the input binding as they are defined in the MultiBinding
var isBackgroundEnabled = (bool)values[0];
if (!isBackgroundEnabled)
{
return Brushes.Transparent;
}
if (values[1] is string stringValue)
{
return stringValue.Trim().StartsWith("7")
? Brushes.DarkSlateBlue
: stringValue.Trim().StartsWith("6")
? Brushes.Peru
: Brushes.Firebrick;
}
return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
One solution, that doesn't require modification of your view model, is to use a MultiBinding
with a IMultiValueConverter
. A IMultiValueConverter
accepts multiple inputs returned from a MultiBinding
, to convert them to a single output (and reverse):
First, turn the IValueConverter
into a IMultiValueConverter
.
It's best practice to throw the exception that describes the cause of the error the best.
The NotImplementedException
is primarily intended to notify the developer that he forgot to implement a relevant and referenced method. It's like a 'TODO'. Since you deliberately decided not to implement the ConvertBack
member, because you decided not to support the backwards conversion, you should throw a NotSupportedException
instead. This notifies the consumer of your type that the method is not supported instead of implying that the author simply forgot to implement it.
class IDToBackgroundConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// The order of the parameters in the 'values' array is equal to the order
// of the input binding as they are defined in the MultiBinding
var isBackgroundEnabled = (bool) values[0];
if (!isBackgroundEnabled)
{
return Brushes.Transparent;
}
if (values[1] is string stringValue)
{
return stringValue.Trim().StartsWith("7")
? Brushes.DarkSlateBlue
: stringValue.Trim().StartsWith("6")
? Brushes.Peru
: Brushes.Firebrick;
}
return Binding.DoNothing;
}
// Throw a NotSupportedException instead of a NotImplementedException
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
=> throw new NotSupportedException();
}
Setup the MultiBinding
:
<CheckBox IsChecked="{Binding BackgroundColorBool}" />
<DataGrid>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background">
<Setter.Value>
<MultiBinding>
<MultiBinding.Converter>
<IDToBackgroundConverter />
</MultiBinding.Converter>
<Binding Path="BackgroundColorBool" />
<Binding Path="YRNRO" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
</DataGrid>
Because the purpose of the logic is to handle the coloring or visuals of the view, you should not implement this logic or store related data in the view model.
View and view model should never mix!
Whether to use the previous example or to eliminate the BackgroundColorBool
property in the view model, depends on the the purpose of the CheckBox
. Its name suggests a data related purpose ("ActiveCustomer...") and of course could bind to the view model.
But the name of the source property ("BackgroundColor..."), the CheckBox
binds to, suggests a merely view related purpose. In this case the property should not be in the view model. Instead move it as a DependencyProperty
to the hosting view or bind the CheckBox
directly:
<CheckBox x:Name="ActiveCustomer_Copy" />
<DataGrid>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background">
<Setter.Value>
<MultiBinding>
<MultiBinding.Converter>
<IDToBackgroundConverter />
</MultiBinding.Converter>
<Binding ElementName="ActiveCustomer_Copy"
Path="IsChecked" />
<Binding Path="YRNRO" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
</DataGrid>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.