WPF, DataBinding, DataGrid and simple conditional 'higher than' using IValueConverter
The other day I wanted to highlight some rows in a datagrid in a WPF project.
This is not hard to accomplish in a “normal” Win Form situation, but in in WPF it needed a bit more work (not much to be honest).
So, the scenario in this example is the following. We have some people with their respective sales.
The sales target is > 62, if this is the case, then set the background of the row in the datagrid to green.
Create a new WPF application and set the code to be the code below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DataBindingRowValueBinding
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Load initial sales
GetSalesList();
}
public void GetSalesList()
{
Random r = new Random();
List<Sale> sales = new List<Sale>()
{
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="John", SaleArea="UK"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Paul", SaleArea="FR"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Mary", SaleArea="UK"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Eric", SaleArea="US"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Stan", SaleArea="SE"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Tina", SaleArea="UK"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Peta", SaleArea="FI"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Tess", SaleArea="IT"},
new Sale{SaleAmt = r.Next(0, 100), SaleAgent ="Nick", SaleArea="UK"}
};
dgSales.ItemsSource = sales.ToList();
}
// Class used for populating the DataGrid with fictional Sales.
public class Sale
{
public int SaleAmt { get; set; }
public string SaleAgent { get; set; }
public string SaleArea { get; set; }
}
// Just reload sales list with random values
private void Button_Click(object sender, RoutedEventArgs e)
{
GetSalesList();
}
}
// This returns true if sale is on or above targe, otherwise false
public class SalesTargetConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int sale = System.Convert.ToInt32(value);
int target = System.Convert.ToInt32(parameter);
return (sale >= target);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
The above should be self-explanatory. There is one method that creates a list with random sales values.
We also have created one class that inherits the IValueConverter. This interface has a method called Convert and to this method we pass the sale (from the list) as the
value and the target as the parameter. If sale is above target it returns true, otherwise false.
Now, replace the XAML with the below.
<Window x:Class="DataBindingRowValueBinding.MainWindow"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:DataBindingRowValueBinding"
Title="MainWindow" Height="350" Width="350">
<Window.Resources>
<src:SalesTargetConverter x:Key="SalesTargetConverter" />
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding SaleAmt, Converter={StaticResource SalesTargetConverter}, ConverterParameter=62}" Value="True">
<Setter Property="Background" Value="LawnGreen"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<!--This is just GUI stuff, change as you wish-->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.Column="0" Content="Get Sales" Margin="3,3" Click="Button_Click" />
<DataGrid Grid.Row="1" Grid.Column="0" Margin="3,3" AutoGenerateColumns="True" Name="dgSales" />
</Grid>
<!--EOF GUI stuff-->
</Window>
Again, should be self explanatory. There is the GUI part at the end.
The magic happens in the Window Resources. We import the name space, then map to the method (SalesTargetConverter).
Finally we set the binding to use SaleAmt which is passed to the Converter, we have also supplied the parameter. Which you can supply from somewhere else if needed.
So it is really simple to create a “higher than” or “lower than” functionality. Of all the code above most of it is for GUI or for creating the fake data.
If we wish to create a different condition with multiple parameters, for example “… where x > 5 AND x < 50” then we need to use the IMultiValueConverter
I will create an example of that later.
Comments
Anonymous
December 06, 2011
Thanks. It works! However, is there a way to use a conditional background on individual cells?Anonymous
April 10, 2012
Thanks for such a valuable blog on conditional data binding.I got many important tips and ideas today from your blog. Thanks.for more information regarding data binding visit on http://www.dapfor.com/en