Charting with WPF and Silverlight

Sometimes we need to decorate our WPF or Silverlight applications with things like bar charts or pie charts. There's no need to create these from scratch, since a lot of charting solutions are available, some of which are free while other are ... less free. On CodePlex you find the Silverlight Toolkit and the WPF Toolkit. The charting controls of these toolkits share the same object model -well, they actually have even the same source code. Programming against these controls is easy, but you should revisit your source code after each release. It's fast moving beta software, but fortunately it's moving in the right direction: some of the components will eventually become part of the .NET 4.x framework. In their current implementation, the charting controls behave maturely at run time, but at design time you might encounter some issues. Don't worry too much about these: it's safe to simply ignore most of the XAML warnings and errors. The Chart class allows you to build the following chart types: Bar Chart Column Chart Line Chart Pie Chart Scatter Chart Bubble Chart Area Chart Tree Map Examples of each chart can be found here. The fastest way to explore the charting controls is through the Chart Builder project. It's a wizard that allows you to generate the XAML for simple charts. Here's how it looks like: Your next step would be to download the Data Visualizations Demo solution to figure out how more sophisticated charts can be generated. From then on, regularly check Delay's Blog to keep in touch with the latest developments. Let's get our hands dirty and build two small samples. 1. Building a Pareto Chart in XAML A Chart Control instance is not much more than a container for data series and axes. So it's easy to build combined charts like a standard Pareto chart. A standard Pareto chart combines a column chart displaying absolute values with a line chart representing the cumulative percentage, like this one: A chart like this will certainly impress your end user! The corresponding XAML is amazingly straightforward. It's a chart with a column series and a line series that share the same X-axis. I'm just going to just let the XAML speak for itself: <Window x:Class="U2UConsult.DockOfTheBay.ParetoChartWindow"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:sys="clr-namespace:System;assembly=mscorlib"    xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"    xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"    Title="Data Visualization Sample"    Icon="/DataVisualizationSample;component/dotbay.png">     <Grid>         <!-- Pareto Chart -->         <charting:Chart            Title="A Pareto Chart"            LegendTitle="Legend" >             <!-- Common X axis -->             <charting:Chart.Axes>                 <charting:CategoryAxis Orientation="X" />             </charting:Chart.Axes>             <charting:Chart.Series>                 <!-- Column series with absolute values -->                 <charting:ColumnSeries Title="Absolute Values">                     <!-- Y axis on the left side -->                     <charting:ColumnSeries.DependentRangeAxis>                         <charting:LinearAxis                            Orientation="Y"                            Minimum="0"                            Maximum="50"                            Location="Left" />                     </charting:ColumnSeries.DependentRangeAxis>                     <!-- Data -->                     <charting:ColumnSeries.ItemsSource>                         <collections:ArrayList>                             <sys:Double>23</sys:Double>                             <sys:Double>15</sys:Double>                             <sys:Double>11</sys:Double>                             <sys:Double>10</sys:Double>                             <sys:Double>7</sys:Double>                             <sys:Double>5</sys:Double>                             <sys:Double>4</sys:Double>                         </collections:ArrayList>                     </charting:ColumnSeries.ItemsSource>                 </charting:ColumnSeries>                 <!-- Line series with cumulative percentage -->                 <charting:LineSeries                    Title="Cumulative Percentage"                    IndependentValueBinding="{Binding}" >                     <!-- Y axis on the right side -->                     <charting:LineSeries.DependentRangeAxis>                         <charting:LinearAxis                            Orientation="Y"                            Minimum="0"                            Maximum="100"                            Location="Right" />                     </charting:LineSeries.DependentRangeAxis>                     <!-- X axis reuses the same categories -->                     <charting:LineSeries.IndependentAxis>                         <charting:CategoryAxis                            Orientation="X" />                     </charting:LineSeries.IndependentAxis>                     <!-- Data -->                     <charting:LineSeries.ItemsSource>                         <collections:ArrayList>                             <sys:Double>31</sys:Double>                             <sys:Double>51</sys:Double>                             <sys:Double>65</sys:Double>                             <sys:Double>79</sys:Double>                             <sys:Double>88</sys:Double>                             <sys:Double>95</sys:Double>                             <sys:Double>100</sys:Double>                         </collections:ArrayList>                     </charting:LineSeries.ItemsSource>                 </charting:LineSeries>             </charting:Chart.Series>         </charting:Chart>     </Grid> </Window>   2. Building a Bubble Chart The bubble chart is one of my favorites, because it can easily display 4 values at a time: a value on the X axis, a value on the Y axis, the size of the bubble, and last but not least a value in the tooltip. Here's an example: For starters, let's build a class with four instance properties, and a static property returning a list: namespace U2UConsult.DockOfTheBay {     using System.Collections.Generic;     using System.Collections.ObjectModel;       /// <summary>     /// The starship that boldly went where nobody went before.     /// </summary>     public class Enterprise     {         /// <summary>         /// Gets a collection of all versions of the USS Enterprise.         /// </summary>         public static ObservableCollection<Enterprise> GetAll         {             get             {                 return new ObservableCollection<Enterprise>()                 {                     new Enterprise() {                         Name = "NCC-1701-A", Length = 305, CrewSize = 432, CommandingOfficer = "James T. Kirk"                     },                     new Enterprise() {                         Name = "NCC-1701-B", Length = 511, CrewSize = 750, CommandingOfficer = "John Harriman"                     },                     new Enterprise() {                         Name = "NCC-1701-C", Length = 526, CrewSize = 700, CommandingOfficer = "Rachel Garrett"                     },                     new Enterprise() {                         Name = "NCC-1701-D", Length = 642, CrewSize = 1012, CommandingOfficer = "Jean-Luc Picard"                     },                     new Enterprise() {                         Name = "NCC-1701-E", Length = 685, CrewSize = 855, CommandingOfficer = "Morgan Bateson"                     }                 };             }         }           /// <summary>         /// Gets or sets the registered name.         /// </summary>         public string Name { get; set; }           /// <summary>         /// Gets or sets the number of crew members.         /// </summary>         public int CrewSize { get; set; }           /// <summary>         /// Gets or sets the name of the initial commmanding officer.         /// </summary>         public string CommandingOfficer { get; set; }           /// <summary>         /// Gets or sets the lenght of the ship.         /// </summary>         /// <remarks>Expressed in metric meters.</remarks>         public int Length { get; set; }     } }   The Lenght, Name, and CrewSize properties are respectively bound through a DependentValueBinding (Y axis), a IndependentValueBinding (X axis), and a SizeValueBinding (size of the bubble). The initial version of the XAML looks like this: <Window x:Class="U2UConsult.DockOfTheBay.ChartWindow"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:sys="clr-namespace:System;assembly=mscorlib"    xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"    xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"    xmlns:local="clr-namespace:U2UConsult.DockOfTheBay"    Title="Data Visualization Sample"    Icon="/DataVisualizationSample;component/dotbay.png">     <Grid>         <charting:Chart            Title="Starship Dimensions" >             <charting:Chart.Series>                 <charting:BubbleSeries                    Title="USS Enterprise"                    ItemsSource="{x:Static local:Enterprise.GetAll}"                    DependentValueBinding="{Binding Length}"                    IndependentValueBinding="{Binding Name}"                    SizeValueBinding="{Binding CrewSize}" />             </charting:Chart.Series>             <charting:Chart.Axes>                 <charting:CategoryAxis                    Orientation="X"                    Title="Registration Number" />                 <charting:LinearAxis                    Orientation="Y"                    Title="Length in meter"                    Maximum="800"                    Minimum="0" />             </charting:Chart.Axes>         </charting:Chart>     </Grid> </Window>   If you also want to let the chart display a fourth property (say CommandingOfficer), then you should customize the template for the bubble itself. Unfortunately this will more than double the codebase. There is no TooltipValueBinding property or a stable style or template to inherit from (yet?). So if you want a customized tooltip then you have to override/duplicate the whole template. The safest option is to boldly copy/paste from the samples. First create a style, e.g. in Grid.Resources: <Grid.Resources>     <Style        x:Key="CustomBubbleDataPointStyle"        TargetType="charting:BubbleDataPoint" >         <!-- Pretty background brush -->         <Setter Property="Background">             <Setter.Value>                 <RadialGradientBrush>                     <RadialGradientBrush.RelativeTransform>                         <TransformGroup>                             <ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="2.09" ScaleY="1.819"/>                             <TranslateTransform X="-0.425" Y="-0.486"/>                         </TransformGroup>                     </RadialGradientBrush.RelativeTransform>                     <GradientStop Color="#FF9DC2B3"/>                     <GradientStop Color="#FF1D7554" Offset="1"/>                 </RadialGradientBrush>             </Setter.Value>         </Setter>         <!-- Template with custom ToolTip -->         <Setter Property="Template">             <Setter.Value>                 <ControlTemplate TargetType="charting:BubbleDataPoint">                     <Grid>                         <Ellipse                    Fill="{TemplateBinding Background}"                    Stroke="{TemplateBinding BorderBrush}"                    StrokeThickness="{TemplateBinding BorderThickness}"/>                         <Ellipse>                             <Ellipse.Fill>                                 <LinearGradientBrush>                                     <GradientStop                                        Color="#77ffffff"                                        Offset="0"/>                                     <GradientStop                                        Color="#00ffffff"                                        Offset="1"/>                                 </LinearGradientBrush>                             </Ellipse.Fill>                         </Ellipse>                         <ToolTipService.ToolTip>                             <StackPanel>                                 <TextBlock Text="{Binding Name}" FontWeight="Bold" />                                 <StackPanel Orientation="Horizontal">                                     <TextBlock Text="Length: " />                                     <ContentControl Content="{TemplateBinding FormattedDependentValue}"/>                                     <TextBlock Text=" meter" />                                 </StackPanel>                                 <StackPanel Orientation="Horizontal">                                     <TextBlock Text="Crew: " />                                     <ContentControl Content="{TemplateBinding Size}"/>                                 </StackPanel>                                 <StackPanel Orientation="Horizontal">                                     <TextBlock Text="Commanding Officer: " />                                     <TextBlock Text="{Binding CommandingOfficer}"/>                                 </StackPanel>                             </StackPanel>                         </ToolTipService.ToolTip>                     </Grid>                 </ControlTemplate>             </Setter.Value>         </Setter>     </Style> </Grid.Resources>   To make use of this style, just add this to the chart's properties: DataPointStyle="{StaticResource CustomBubbleDataPointStyle}" As you see the charting controls in both WPF and Siverlight toolkits allow you to rapidly embed powerful charting features into your application. To be honest: it actually took me more time to collect sample data than to build these charts.

Validation in a WPF DataGrid

In this article I will describe two options to implement validation on the cells and rows of a WPF DataGrid. On the architectural level you have indeed (at least) two options when it comes to validation. You can decide to validate through independent reusable logic captured in ValidationRules, or you can let the bound entities carry out the validation themselves. Let's first set up a mini-application, with a WPF DataGrid displaying a list of instances of a WeatherForecast class. It should look like this: Here's the WeatherForecast class: namespace U2UConsult.DockOfTheBay {     using System;     using System.Collections.ObjectModel;     using System.ComponentModel;       /// <summary>     /// Intergalactic Weather Forecast     /// </summary>     public class WeatherForecast     {         /// <summary>         /// Gets the list of weather forecasts for tomorrow.         /// </summary>         public static ObservableCollection<WeatherForecast> TomorrowsForecast         {             get             {                 return new ObservableCollection<WeatherForecast>()                 {                     new WeatherForecast()                     {                         Planet = "Alderaan",                         Conditions = "Risk of a severe lightning bolt",                         LowestTemp = 0,                         HighestTemp = 0                     },                     new WeatherForecast()                     {                         Planet = "Caprica",                         Conditions = "Acid rain - toasters better stay inside",                         LowestTemp = 24,                         HighestTemp = 28                     },                     new WeatherForecast()                     {                         Planet = "Earth",                         Conditions = "Globally warming",                          LowestTemp = 6,                         HighestTemp = 9                     },                     new WeatherForecast()                     {                         Planet = "Middle Earth",                         Conditions = "Cloudy over Mordor",                         LowestTemp = 24,                         HighestTemp = 28                     },                     new WeatherForecast()                     {                         Planet = "Tatooine",                         Conditions = "Heavy sand storms",                         LowestTemp = 3,                         HighestTemp = 8                     }                 };             }         }           /// <summary>         /// Gets or sets the name of the planet.         /// </summary>         public string Planet { get; set; }           /// <summary>         /// Gets or sets the description of the weather conditions.         /// </summary>         public string Conditions { get; set; }           /// <summary>         /// Gets or sets the lowest temperature during an interval.         /// </summary>         /// <remarks>Unit measure is °C.</remarks>         public int LowestTemp { get; set; }           /// <summary>         /// Gets or sets the highest temperature during an interval.         /// </summary>         /// <remarks>Unit measure is °C.</remarks>         public int HighestTemp { get; set; }     } }   And here's the XAML for the form: <Window x:Class="U2UConsult.DockOfTheBay.DataGridValidationSampleWindow"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"     xmlns:local="clr-namespace:U2UConsult.DockOfTheBay"     Icon="/DataGridValidationSample;component/dotbay.png"     SizeToContent="WidthAndHeight"     Title="DataGrid Validation Sample" >     <StackPanel>         <!-- Title -->         <TextBlock            Text="Intergalactic Weather Forecast"            HorizontalAlignment="Center"            FontWeight="Bold"            Margin="5" />         <!-- Weather Forecasts Grid -->         <toolkit:DataGrid             ItemsSource="{x:Static local:WeatherForecast.TomorrowsForecast}"             AutoGenerateColumns="False"             RowHeaderWidth="16">             <toolkit:DataGrid.Columns>                 <toolkit:DataGridTextColumn                    Header="Planet"                    Binding="{Binding Path=Planet}"/>                 <toolkit:DataGridTextColumn                    Header="Conditions"                    Binding="{Binding Path=Conditions}"/>                 <toolkit:DataGridTextColumn                    Header="Low Temperature"                    Binding="{Binding Path=LowestTemp}"/>                 <toolkit:DataGridTextColumn                    Header="High Temperature"                    Binding="{Binding Path=HighestTemp}"/>             </toolkit:DataGrid.Columns>         </toolkit:DataGrid>     </StackPanel> </Window>   1. Validation through ValidationRules A first way to perform validation is to store the rules in ValidationRule classes, and let the column or row bindings call that business logic at the appropriate moment (that moment is determined by the ValidationStep property of the rule). The bound entities themselves are unaware of this process. Cell validation You can build validation rule classes to validate a single value, e.g. a Temperature. First we check whether the input is a whole number (type check). Then we perform a range check to verify if the entered value is within the physical boundaries of temperature i.e. between absolute cold and absolute hot (no need to check the latter, because it's higher than Integer32.MaxValue anyway). Here's how this could look like: namespace U2UConsult.DockOfTheBay {     using System.Windows.Controls;       /// <summary>     /// Validates a temperature in °C.     /// </summary>     internal class TemperatureValidationRule : ValidationRule     {         /// <summary>         /// Validates the proposed value.         /// </summary>         /// <param name="value">The proposed value.</param>         /// <param name="cultureInfo">A CultureInfo.</param>         /// <returns>The result of the validation.</returns>         public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)         {             if (value != null)             {                 int proposedValue;                 if (!int.TryParse(value.ToString(), out proposedValue))                 {                     return new ValidationResult(false, "'" + value.ToString() + "' is not a whole number.");                 }                   if (proposedValue < -273)                 {                     // Something was wrong.                     return new ValidationResult(false, "Temperature can not be below the absolute cold (-273°C).");                 }             }               // Everything OK.             return new ValidationResult(true, null);         }     } }   All you need to do to trigger the validation, is registering the validation rules in the binding of the corresponding bound columns, like this: <toolkit:DataGridTextColumn Header="High Temperature">     <toolkit:DataGridTextColumn.Binding>         <Binding Path="HighestTemp">             <!-- Validating through independent rules -->             <Binding.ValidationRules>                 <local:TemperatureValidationRule />             </Binding.ValidationRules>         </Binding>     </toolkit:DataGridTextColumn.Binding> </toolkit:DataGridTextColumn>   If you run the application in this stage, you'll notice that the validation is executed. The invalid cell is presented through the default ErrorTemplate (a red border around the contents): You have no idea what went wrong, until you add you own error template. Let's display an icon in the row header, with the error message as tooltip: <!-- Validation Error Template for a DataGrid Row --> <Style TargetType="{x:Type toolkit:DataGridRow}">     <Setter Property="ValidationErrorTemplate">         <Setter.Value>             <ControlTemplate>                 <Image                    Source="/DataGridValidationSample;component/error.png"                    ToolTip="{Binding RelativeSource={                                          RelativeSource FindAncestor,                                          AncestorType={x:Type toolkit:DataGridRow}},                                      Path=(Validation.Errors)[0].ErrorContent}"                    Margin="0"                    Width="11" Height="11" />             </ControlTemplate>         </Setter.Value>     </Setter> </Style>   Now you get all the details when the validation rule is broken:   Row validation WPF 3.5 SP1 introduced the BindingGroup class. A BindingGroup represents a set of related Bindings -e.g. the bindings to different properties of the same entity. A BindingGroup can also span bindings to multiple entities -e.g. a list of travellers reserving a group ticket. Here's a validation rule that validates a WheaterForecast: namespace U2UConsult.DockOfTheBay {     using System.Windows.Controls;     using System.Windows.Data;       /// <summary>     /// Validation of WeatherForecast instances.     /// </summary>     public class WeatherForecastValidationRule : ValidationRule     {         /// <summary>         /// Validate a whole collection of binding sources.         /// </summary>         /// <param name="value">A BindingGroup.</param>         /// <param name="cultureInfo">A CultureInfo.</param>         /// <returns>The result of the validation.</returns>         public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)         {             // Get binding group.             BindingGroup bindingGroup = value as BindingGroup;               if (bindingGroup != null)             {                 // Loop through binding sources - could be multiple.                 foreach (var bindingSource in bindingGroup.Items)                 {                     // Get object.                     WeatherForecast forecast = bindingSource as WeatherForecast;                       // Validate object.                     if (forecast.HighestTemp < forecast.LowestTemp)                     {                         // Something was wrong.                         return new ValidationResult(false, "Why do you think we called it 'High' and 'Low' ?");                     }                 }             }               // Everything OK.             return ValidationResult.ValidResult;         }     } }   Note: this class is very tightly coupled to the WeatherForecast class itself. The validation rule is called from the datagrid's bindings via RoleValidationRules: <!-- Validating through independent rules --> <toolkit:DataGrid.RowValidationRules>     <local:WeatherForecastValidationRule ValidationStep="ConvertedProposedValue" /> </toolkit:DataGrid.RowValidationRules>   The Error Template that we defined earlier in this article, can be reused for row validation:  2. Validation through IDataErrorInfo A second way to perform validation is to store all the necessary business logic inside the entity, and expose it through the IDataErrorInfo interface. A DataErrorValidationRule at column and row level will call the methods on this interface. Cell validation An indexer with the property name as parameter will be called if a single property needs to be validated. Here's the code for the WeatherForecast class: /// <summary> /// Gets the result of a validation at Property level (from IDataErrorInfo). /// </summary> /// <param name="columnName">Name of the modified property.</param> /// <returns>A validation error message.</returns> /// <remarks>Called by DataErrorValidationRule at Column level.</remarks> public string this[string columnName] {     get     {         // Temperature range checks.         if ((columnName == "LowestTemp") || (columnName == "HighestTemp"))         {             if ((this.LowestTemp < -273) || (this.HighestTemp < -273))             {                 return "Temperature can not be below the absolute cold (-273°C).";             }         }           // All validations passed successfully.         return null;     } }   An alternative is to do the validation in the setter of the properties, and only define an ExceptionValidationRule at column level. Row validation A DataErrorValidationRule can also be instantiated from the RowValidationRules of the DataGrid: <!-- Validating through IDataErrorInfo --> <toolkit:DataGrid.RowValidationRules>     <DataErrorValidationRule /> </toolkit:DataGrid.RowValidationRules>   It will call the Error property on the bound entities: /// <summary> /// Gets the result of a validation at Entity level (from IDataErrorInfo). /// </summary> /// <remarks>Called by DataErrorValidationRule at Row level.</remarks> public string Error {     get     {         // Compare temperatures.         if (this.LowestTemp > this.HighestTemp)         {             return "Why do you think we called it 'High' and 'Low' ?";         }           // All validations passed successfully.         return null;     } } 

A minimalistic template for an editable WPF DataGrid

By default, a WPF DataGrid operates in its birthday suit, with no decorations at all. For your end user this is not intuitive, so you should provide some fig-leafs here and there. In my humble opinion, at least two rows should be easily identifiable in any editable grid: the 'new' row (generally at the bottom of the grid), and the row that is currently being edited. Both rows deserve their own template. As you certainly know, you can get very far with WPF templating. In this article however I'll go for the minimalistic approach and display an asterisk in front of the 'new' row, and a pencil in front of the row in edit mode. An asterisk for the 'New' row This is what we're trying to achieve: We will get this result by applying a data template to the row's header. So start with a data template in XAML, somewhere in a resource element: <DataTemplate x:Key="AsteriskTemplate" >     <TextBlock        Margin="0"        HorizontalAlignment="Center"        VerticalAlignment="Center"        ToolTip="New"        Text="*">     </TextBlock> </DataTemplate>   This template should be applied when loading the row, so hook an event handler to LoadingRow, also in XAML: <toolkit:DataGrid    x:Name="DriversDataGrid"    ItemsSource="{Binding Source={x:Static local:FormulaOneDriver.GetAll}}"    CommandManager.PreviewExecuted="DriversDataGrid_PreviewDeleteCommandHandler"    LoadingRow="DriversDataGrid_LoadingRow"    RowEditEnding="DriversDataGrid_RowEditEnding"   Here's the C# code for the event handler: /// <summary> /// Apply Asterisk DataTemplate to New Row /// </summary> /// <param name="sender">Sender of the event: the DataGrid.</param> /// <param name="e">Event arguments.</param> private void DriversDataGrid_LoadingRow(object sender, DataGridRowEventArgs e) {     if (e.Row.Item == CollectionView.NewItemPlaceholder)     {         e.Row.HeaderTemplate = (DataTemplate)DriversDataGrid.FindResource("AsteriskTemplate");         e.Row.UpdateLayout();     } } A pencil for the 'Edit' row This is what we're trying to achieve:  Again we define the look of the row header through a data template: <DataTemplate x:Key="PencilTemplate" >     <Image Source="/DataGridSample;component/pencil.png"           Margin="0"           Height="11" Width="11"           HorizontalAlignment="Center" VerticalAlignment="Center"            /> </DataTemplate>   The template is applied when we enter edit-mode. So you should handle the BeginningEdit event. When leaving edit mode, don't forget to revert to the default template, through the RowEditEnding event: <toolkit:DataGrid    x:Name="DriversDataGrid"    ItemsSource="{Binding Source={x:Static local:FormulaOneDriver.GetAll}}"    CommandManager.PreviewExecuted="DriversDataGrid_PreviewDeleteCommandHandler"    LoadingRow="DriversDataGrid_LoadingRow"    BeginningEdit="DriversDataGrid_BeginningEdit"    RowEditEnding="DriversDataGrid_RowEditEnding"   Here's the event handler to apply the template: /// <summary> /// A row goes in edit mode. So display the pencil in its header. /// </summary> /// <param name="sender">Sender of the event: the DataGrid.</param> /// <param name="e">Event arguments.</param> private void DriversDataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e) {     e.Row.HeaderTemplate = (DataTemplate)DriversDataGrid.FindResource("PencilTemplate");     e.Row.UpdateLayout(); }   And here's how to remove the template: /// <summary> /// A row leaves edit mode: persist it, and revert to the default header. /// </summary> /// <param name="sender">Sender of the event: the DataGrid.</param> /// <param name="e">Event arguments.</param> private void DriversDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e) {     [...]     e.Row.HeaderTemplate = null; }

Workaround: WPF DataGrid hangs Visual Studio.NET

Welcome to a WPF DataGrid crash course ... literally. It will show you how Cider can give you a hangover.  It took me 45 minutes, 10 process kills, and a full reboot to figure out what was going on in my application, so I gladly share my experience.  Part one: the bug Create a WPF Form with an empty DataGrid, like this: <Window x:Class="U2UConsult.DockOfTheBay.DataGridWorkaround"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"    Title="Bug Workaround" SizeToContent="WidthAndHeight">     <Grid>         <toolkit:DataGrid>             <toolkit:DataGrid.Columns>             </toolkit:DataGrid.Columns>         </toolkit:DataGrid>      </Grid> </Window>   Then, add a style that adds a Margin to the Button control, e.g. as a Resource for the Window:  <!-- Kaboom--> <Window.Resources>     <Style TargetType="{x:Type Button}">         <Setter Property="Margin" Value="3" />     </Style> </Window.Resources>   Now is a good time to save your solution. Add a column to the DataGrid: <toolkit:DataGridTextColumn Header="Test" />   You will probably see something like this now, with an ever increasing counter: Cider -the WPF Designer for Visual Studio.NET- entered an infinite loop. Start Task Manager and inspect Visual Studio.NET's process, it's consuming close to 100% CPU: Kill the process. What you just experienced is a confirmed bug. The current version of the WPF DataGrid hangs Visual Studio.NET's Designer when buttons are decorated with a margin. Part two: the Workaround So now you know what may cause this behavior. Fortunately this shouldn't stop you from using a DataGrid, because the workaround is simple. All you need to do is embed a style in your DataGrid that resets the button margin to zero: <toolkit:DataGrid>     <!-- Workaround for bug: No button margins allowed -->     <Style TargetType="{x:Type Button}">         <Setter Property="Margin" Value="0" />     </Style>     <!-- End of Workaround -->     <toolkit:DataGrid.Columns>         <toolkit:DataGridTextColumn Header="Test" />     </toolkit:DataGrid.Columns> </toolkit:DataGrid>   This is just one of the many inconveniences with the current version of the toolkit. I strongly advise you to regularly check the issue tracker if you're planning to use its components in production.

Inserting, Updating, and Deleting from a WPF DataGrid

You already know how easy it is to implement databinding in the WPF DataGrid from a previous article. Let's dive just a little bit deeper, and decorate this application with the code to trigger insert-, update- and delete-calls against the underlying Model and/or Data Access Layer. I'll stick to the M-V-VM approach where the View decides when to update the Model (usually via executing a Command), but the ViewModel decides how to update the Model (by implementing that same Command). For starters, decorate the Formula 1 Driver class with the corresponding -dummy- Save() and Delete() methods: /// <summary> /// Persists a Formula 1 Driver /// </summary> public void Save() {     // Ask the Model or the DAL to persist me... }   /// <summary> /// Deletes a Formula 1 Driver. /// </summary> public void Delete() {     // Ask the Model or the DAL to delete me... } Insert and Update Objects are persisted (inserted or updated) when the user leaves a row that he was editing. Moving to another cell in the same row updates the corresponding property through data binding, but doesn't signal the Model (or the Data Access Layer) yet. The only useful event is DataGrid.RowEditEnding. This is fired just before committing the modified row. Here's the registration of the event handler, in XAML: <toolkit:DataGrid    x:Name="DriversDataGrid"    ItemsSource="{Binding Source={x:Static local:FormulaOneDriver.GetAll}}"    RowEditEnding="DriversDataGrid_RowEditEnding"    AutoGenerateColumns="False"    CanUserAddRows="True"   The RowEditEnding event is called when the user leaves Edit-mode, and can be the result of Cancelling, or Committing. Of course you only need to react to a Commit. This is the even handler: /// <summary> /// Persists a row after editing (update or insert). /// </summary> /// <param name="sender">Sender of the event: the DataGrid.</param> /// <param name="e">Event arguments.</param> private void DriversDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e) {     // Only act on Commit     if (e.EditAction == DataGridEditAction.Commit)     {         FormulaOneDriver driver = e.Row.DataContext as FormulaOneDriver;         driver.Save();     } } Important remark In its current implementation, a DataGridTemplateColumn will NOT trigger any of the DataGrid's events. There seems to be no elegant work-around for this. In this sample, if you only change the LatestVictory date of a Formula 1 Driver, the RowEditEnding will not fire, hence the Save() method on the Formula 1 Driver will NOT be called. Needless to say that this may be a showstopper ! Delete Objects are deleted if the user selects one or multiple rows in the DataGrid and hits the Delete button. In most cases we would like to ask the user for a confirmation. We can do this by intercepting the Execute call via tunelling, and allow the user to cancel the delete command before it actually executes. This sounds pretty impressive, but it just involves writing an event handler for CommandManger.PreviewExecute. You can register this event handler in XAML: <toolkit:DataGrid    x:Name="DriversDataGrid"    ItemsSource="{Binding Source={x:Static local:FormulaOneDriver.GetAll}}"    CommandManager.PreviewExecuted="DriversDataGrid_PreviewDeleteCommandHandler"    RowEditEnding="DriversDataGrid_RowEditEnding"    AutoGenerateColumns="False"    CanUserAddRows="True"   This is the actual eventhandler code, in which we can cancel the event: /// <summary> /// Asks for confirmation of a delete. /// </summary> /// <param name="sender">Sender of the event: the DataGrid.</param> /// <param name="e">Event arguments.</param> private void DriversDataGrid_PreviewDeleteCommandHandler(object sender, ExecutedRoutedEventArgs e) {     if (e.Command == DataGrid.DeleteCommand)     {         if (!(MessageBox.Show("Are you sure you want to delete?", "Please confirm.", MessageBoxButton.YesNo) == MessageBoxResult.Yes))         {             // Cancel Delete.             e.Handled = true;         }     } } Here's how it looks like in action: If the Delete action is not cancelled, then the underlying collection is updated. This triggers its CollectionChanged event, in which you can call the Formula 1 Driver's Delete() method: /// <summary> /// The collection of drivers just changed: add or remove /// </summary> /// <param name="sender">Sernder of the Event.</param> /// <param name="e">Event Arguments.</param> private void Drivers_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {     // Only Delete     if (e.Action == NotifyCollectionChangedAction.Remove)     {         foreach (FormulaOneDriver driver in e.OldItems)         {             driver.Delete();         }     } }   Here's the registration of the event handler, put it e.g. in the constructor of the form: ObservableCollection<FormulaOneDriver> drivers = this.DriversDataGrid.ItemsSource as ObservableCollection<FormulaOneDriver>; drivers.CollectionChanged += new NotifyCollectionChangedEventHandler(this.Drivers_CollectionChanged);   For completeness, here's the XAML for the sample form: <Window    x:Class="U2UConsult.DockOfTheBay.DataGridSampleWindow"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="clr-namespace:U2UConsult.DockOfTheBay"    xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"    Title="WPF DataGrid CRUD Sample"    SizeToContent="WidthAndHeight"    Icon="/DataGridSample;component/dotbay.png" >     <Window.Resources>         <Style TargetType="{x:Type toolkit:DatePickerTextBox}">             <Setter Property="Text" Value="None" />             <Setter Property="Background" Value="#00000000" />         </Style>     </Window.Resources>     <Grid>         <Grid.ColumnDefinitions>             <ColumnDefinition Width="*"/>         </Grid.ColumnDefinitions>         <toolkit:DataGrid    x:Name="DriversDataGrid"    ItemsSource="{Binding Source={x:Static local:FormulaOneDriver.GetAll}}"    CommandManager.PreviewExecuted="DriversDataGrid_PreviewDeleteCommandHandler"    RowEditEnding="DriversDataGrid_RowEditEnding"    AutoGenerateColumns="False"    CanUserAddRows="True"            CanUserDeleteRows="True"            CanUserSortColumns="True"            CanUserReorderColumns="True"            AlternatingRowBackground="WhiteSmoke"            RowHeaderWidth="16"            Grid.Column="0" Grid.Row="0"            HorizontalAlignment="Center"            VerticalAlignment="Center">             <toolkit:DataGrid.Columns>                 <toolkit:DataGridTextColumn                    Header="Name"                     Binding="{Binding Name}"                    CanUserReorder="True"                    IsReadOnly="False"                    CanUserSort="True"                    SortMemberPath="Name"/>                 <toolkit:DataGridComboBoxColumn                    x:Name="TeamsCombo"                    Header="Team"                    ItemsSource="{Binding Source={x:Static local:FormulaOneTeam.GetAll}}"                    SelectedValueBinding="{Binding TeamId}"                    SelectedValuePath="Key"                    DisplayMemberPath="Value.Name"                    SortMemberPath="Team.Name" />                 <toolkit:DataGridTextColumn                    Header="Pole Positions"                    Binding="{Binding PolePositions, NotifyOnSourceUpdated=True}"                    CanUserSort="True" />                 <toolkit:DataGridTemplateColumn                    Header="Latest Victory"                    CanUserSort="True"                    SortMemberPath="LatestVictory">                     <toolkit:DataGridTemplateColumn.CellTemplate >                         <DataTemplate >                             <toolkit:DatePicker                                SelectedDate="{Binding LatestVictory}"                                BorderThickness="0" />                         </DataTemplate >                     </toolkit:DataGridTemplateColumn.CellTemplate >                     <toolkit:DataGridTemplateColumn.CellEditingTemplate >                         <DataTemplate >                             <toolkit:DatePicker                                SelectedDate="{Binding LatestVictory, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"                                BorderThickness="0"/>                         </DataTemplate >                     </toolkit:DataGridTemplateColumn.CellEditingTemplate >                 </toolkit:DataGridTemplateColumn>             </toolkit:DataGrid.Columns>         </toolkit:DataGrid>     </Grid> </Window>   And the C# as well: namespace U2UConsult.DockOfTheBay {     using System.Collections.ObjectModel;     using System.Collections.Specialized;     using System.Windows;     using System.Windows.Input;     using Microsoft.Windows.Controls;       /// <summary>     /// WPF DataGrid CRUD Sample.     /// </summary>     public partial class DataGridSampleWindow : Window     {         /// <summary>         /// Initializes a new instance of the DataGridSampleWindow class.         /// </summary>         public DataGridSampleWindow()         {             InitializeComponent();               ObservableCollection<FormulaOneDriver> drivers = this.DriversDataGrid.ItemsSource as ObservableCollection<FormulaOneDriver>;             drivers.CollectionChanged += new NotifyCollectionChangedEventHandler(this.Drivers_CollectionChanged);         }           /// <summary>         /// Persists a row after editing (update or insert).         /// </summary>         /// <param name="sender">Sender of the event: the DataGrid.</param>         /// <param name="e">Event arguments.</param>         private void DriversDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)         {             // Only act on Commit             if (e.EditAction == DataGridEditAction.Commit)             {                 FormulaOneDriver driver = e.Row.DataContext as FormulaOneDriver;                 driver.Save();             }         }           /// <summary>         /// Asks for confirmation of a delete.         /// </summary>         /// <param name="sender">Sender of the event: the DataGrid.</param>         /// <param name="e">Event arguments.</param>         private void DriversDataGrid_PreviewDeleteCommandHandler(object sender, ExecutedRoutedEventArgs e)         {             if (e.Command == DataGrid.DeleteCommand)             {                 if (!(MessageBox.Show("Are you sure you want to delete?", "Please confirm.", MessageBoxButton.YesNo) == MessageBoxResult.Yes))                 {                     // Cancel Delete.                     e.Handled = true;                 }             }         }           /// <summary>         /// The collection of drivers just changed: add or remove         /// </summary>         /// <param name="sender">Sernder of the Event.</param>         /// <param name="e">Event Arguments.</param>         private void Drivers_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)         {             // Only Delete             if (e.Action == NotifyCollectionChangedAction.Remove)             {                 foreach (FormulaOneDriver driver in e.OldItems)                 {                     driver.Delete();                 }             }         }     } }   The Formula 1 Driver and Formula 1 Team classes are still the same from the previous article -except for the dummy Save() and Delete() methods.

Codeless two-way data binding to a WPF DataGrid

WPF 4.0 will finally contain a DataGrid. If you can't wait for that one, then all you have to do is download the current release of the WPF Toolkit. The DataGrid control in this toolkit is considered as stable, so why not give it a test drive? Let's create a list  of Formula 1 Drivers and two-way data bind it to a WPF DataGrid. In our little object model -the ViewModel if you like- a Formula 1 Driver is associated to a Formula 1 Team: Here's the startup code for the Formula 1 Driver class: namespace U2UConsult.DockOfTheBay {     using System.Collections.Generic;       /// <summary>     /// A Formula1 Team.     /// </summary>     public class FormulaOneTeam     {         /// <summary>         /// Gets the entire list of Formula1 teams.         /// </summary>         public static Dictionary<int, FormulaOneTeam> GetAll         {             get             {                 return new Dictionary<int, FormulaOneTeam>()                 {                     { 0, new FormulaOneTeam { TeamId = 0, Name = "Unknown" } },                     { 1, new FormulaOneTeam { TeamId = 1, Name = "Nintendo" } },                     { 2, new FormulaOneTeam { TeamId = 2, Name = "Top Gear" } },                     { 3, new FormulaOneTeam { TeamId = 3, Name = "Wacky Races" } }                 };             }         }           /// <summary>         /// Gets or sets the id of the Formula1 team.         /// </summary>         public int TeamId { get; set; }           /// <summary>         /// Gets or sets the name of the Formula1 team.         /// </summary>         public string Name { get; set; }     } }   In a real life scenario a class that's involved in data binding should implement the INotifyPropertyChanged and IDataError interfaces. An example of the latter can be found in a previous article, an alternative for validating is the BindingGroup class, that I will discuss in a future article (no hyperlink yet ). In M-V-VM applications you will probably implement this behavior by inheriting from some ViewModel base class. Here's the implementation of the Formula 1 Team class: namespace U2UConsult.DockOfTheBay {     using System.Collections.Generic;       /// <summary>     /// A Formula1 Team.     /// </summary>     public class FormulaOneTeam     {         /// <summary>         /// The list of all Formula 1 Teams.         /// </summary>         private static Dictionary<int, FormulaOneTeam> getAll;           /// <summary>         /// Initializes static members of the FormulaOneTeam class.         /// </summary>         static FormulaOneTeam()         {             getAll = new Dictionary<int, FormulaOneTeam>()                 {                     { 0, new FormulaOneTeam { TeamId = 0, Name = "Unknown" } },                     { 1, new FormulaOneTeam { TeamId = 1, Name = "Nintendo" } },                     { 2, new FormulaOneTeam { TeamId = 2, Name = "Top Gear" } },                     { 3, new FormulaOneTeam { TeamId = 3, Name = "Wacky Races" } }                 };         }           /// <summary>         /// Gets the entire list of Formula 1 Teams.         /// </summary>         public static Dictionary<int, FormulaOneTeam> GetAll         {             get             {                 return getAll;             }         }           /// <summary>         /// Gets or sets the id of the Formula 1 Team.         /// </summary>         public int TeamId { get; set; }           /// <summary>         /// Gets or sets the name of the Formula 1 Team.         /// </summary>         public string Name { get; set; }     } }   The ideal collection type for complex data binding (that's binding one control to a collection of objects) is ObservableCollection(T). ObservableCollection(T) is to WPF what BindingList(T) is to WinForms. ObservableCollection(T) only implements the INotifyCollectionChanged interface. This is sufficient to do complex data binding -at least for WPF's ItemControl subclasses like ListView, ComboBox and DataGrid. In a WinForms application the ObservableCollection(T) class loses all its magic. To continue with the sample, add to the Formula 1 Driver class a method that returns such a collection: /// <summary> /// Gets a two-way bindable list of Formula 1 drivers. /// </summary> public static ObservableCollection<FormulaOneDriver> GetAll {     get     {         ObservableCollection<FormulaOneDriver> drivers =             new ObservableCollection<FormulaOneDriver>()             {                 new FormulaOneDriver(){ Name = "Super Mario",                                         TeamId = 1,                                         PolePositions = 2 },                 new FormulaOneDriver(){ Name = "The Stig",                                         TeamId = 2,                                         PolePositions = 20,                                         LatestVictory = DateTime.Today },                 new FormulaOneDriver(){ Name = "Dick Dastardley",                                         TeamId = 3,                                         PolePositions = 0 },                 new FormulaOneDriver(){ Name = "Luigi",                                         TeamId = 1,                                         PolePositions = 2 }             };           return drivers;     } }   If you use this collection as ItemSource of the DataGrid, then the result should look like this: The DataGrid has a couple of intuitive properties, as you can see in its XAML definition: <toolkit:DataGrid    x:Name="DriversDataGrid"    ItemsSource="{Binding Source={x:Static local:FormulaOneDriver.GetAll}}"    AutoGenerateColumns="False"    CanUserAddRows="True"    CanUserDeleteRows="True"    CanUserSortColumns="True"    CanUserReorderColumns="True"    AlternatingRowBackground="WhiteSmoke"    RowHeaderWidth="16"    Grid.Column="0" Grid.Row="0"    HorizontalAlignment="Center"    VerticalAlignment="Center">     <!-- toolkit:DataGrid.Columns [...] --> </toolkit:DataGrid>   The DataGrid can be populated with four column types: DataGridTextColumn, DataGridCheckBoxColumn, DataGridComboBoxColumn, DataGridHyperlinkColumn, and DataGridTemplateColumn. This is an example of a DataGridTextColumn: <toolkit:DataGridTextColumn    Header="Name"     Binding="{Binding Name}"    CanUserReorder="True"    IsReadOnly="False"    CanUserSort="True"    SortMemberPath="Name"/>   Let's look for an excuse to use a DataGridComboBoxColumn. It's not a good idea to confront end users with technical keys, so instead of showing the team's identity we'll display its name. When the grid cell is in edit mode, we let the user select from a ComboBox: The embedded ComboBox is bound to a Dictionary, its citizens have a Key and a Value property that you should respectively bind to SelectedValuePath and DisplayMemberPath: <toolkit:DataGridComboBoxColumn    x:Name="TeamsCombo"    Header="Team"    ItemsSource="{Binding Source={x:Static local:FormulaOneTeam.GetAll}}"    SelectedValueBinding="{Binding TeamId}"    SelectedValuePath="Key"    DisplayMemberPath="Value.Name"    SortMemberPath="Team.Name" />   Make sure to specify the correct SortMemberPath. Users can sort the rows by clicking on the column header(s). The 'Team' column is bound to the TeamId, but it displays the team's name, so it should sort by name. The following screenshot shows that the grid is sorted on the Team column (notice the sort icon in the column header): The LatestVictory property of the Formula 1 Driver is of the type DateTime. In edit mode, it makes sense to  use a DatePicker control to let the user select the date. This control can also be found in the WPF Toolkit. Here's how it can be used in a DataGridTemplateColumn:  <toolkit:DataGridTemplateColumn    Header="Latest Victory"    CanUserSort="True"    SortMemberPath="LatestVictory">     <toolkit:DataGridTemplateColumn.CellTemplate >         <DataTemplate >             <toolkit:DatePicker                SelectedDate="{Binding LatestVictory}"                BorderThickness="0"/>         </DataTemplate >     </toolkit:DataGridTemplateColumn.CellTemplate > </toolkit:DataGridTemplateColumn>   Just like any WPF control the DataPicker is über-stylable. I don't like the default GUI settings for it, so I tweaked the GUI a little bit by hiding its border and giving the embedded TextBox a transparent backcolor. You have access to this via a Style. That's also the place to override the default watermark (through the Text property):  <Style TargetType="{x:Type toolkit:DatePickerTextBox}">     <Setter Property="Text" Value="None" />     <Setter Property="Background" Value="#00000000" /> </Style>   Here's how the DatePicker looks like when it's expanded: When inserting is allowed, then the DataGrid displays an empty row at the bottom. Unfortunately there seems to be no way to display the intuitive asterisk in its row header. When you start editing this row, the default constructor of the bound type is called to initialize the cells. Here's how the one for the Formula 1 driver looks like: /// <summary> /// Initializes a new instance of the FormulaOneDriver class. /// </summary> public FormulaOneDriver() {     this.Name = "<Name>"; }   For completeness' sake, here's the full XAML for the sample form: <Window    x:Class="U2UConsult.DockOfTheBay.DataGridSampleWindow"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="clr-namespace:U2UConsult.DockOfTheBay"    xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"    Title="WPF DataGrid Sample"    SizeToContent="WidthAndHeight"    Icon="/DataGridSample;component/dotbay.png" >     <Window.Resources>         <Style TargetType="{x:Type toolkit:DatePickerTextBox}">             <Setter Property="Text" Value="None" />             <Setter Property="Background" Value="#00000000" />         </Style>     </Window.Resources>     <Grid>         <toolkit:DataGrid            x:Name="DriversDataGrid"            ItemsSource="{Binding Source={x:Static local:FormulaOneDriver.GetAll}}"            AutoGenerateColumns="False"            CanUserAddRows="True"            CanUserDeleteRows="True"            CanUserSortColumns="True"            CanUserReorderColumns="True"            AlternatingRowBackground="WhiteSmoke"            RowHeaderWidth="16"            Grid.Column="0" Grid.Row="0"            HorizontalAlignment="Center"            VerticalAlignment="Center">             <toolkit:DataGrid.Columns>                 <toolkit:DataGridTextColumn                    Header="Name"                     Binding="{Binding Name}"                    CanUserReorder="True"                    IsReadOnly="False"                    CanUserSort="True"                    SortMemberPath="Name"/>                 <toolkit:DataGridComboBoxColumn                    x:Name="TeamsCombo"                    Header="Team"                    ItemsSource="{Binding Source={x:Static local:FormulaOneTeam.GetAll}}"                    SelectedValueBinding="{Binding TeamId}"                    SelectedValuePath="Key"                    DisplayMemberPath="Value.Name"                    SortMemberPath="Team.Name" />                 <toolkit:DataGridTextColumn                    Header="Pole Positions"                    Binding="{Binding PolePositions}"                    CanUserSort="True" />                 <toolkit:DataGridTemplateColumn                    Header="Latest Victory"                    CanUserSort="True"                    SortMemberPath="LatestVictory">                     <toolkit:DataGridTemplateColumn.CellTemplate >                         <DataTemplate >                             <toolkit:DatePicker                                SelectedDate="{Binding LatestVictory}"                                BorderThickness="0"/>                         </DataTemplate >                     </toolkit:DataGridTemplateColumn.CellTemplate >                 </toolkit:DataGridTemplateColumn>             </toolkit:DataGrid.Columns>         </toolkit:DataGrid>     </Grid> </Window>   And here's the C# code: namespace U2UConsult.DockOfTheBay {     using System.Windows;       /// <summary>     /// Two-way binding to a Data Grid Sample.     /// </summary>     /// <remarks>Not much to see here: it's all in the XAML.</remarks>     public partial class DataGridSampleWindow : Window     {         /// <summary>         /// Initializes a new instance of the DataGridSampleWindow class.         /// </summary>         public DataGridSampleWindow()         {             InitializeComponent();         }     } }