Problems binding to SelectedValue with Microsoft’s WPF DataGrid

I had been seeing some odd exceptions being thrown by the WPF DataGrid code when interacting with the “new row” place holder.

GridEditing - SelectedItem FormatException

I could identify that the error was occurring because I had data-bound to the SelectedItem property on the DataGrid like so:

<toolkit:DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False"
                  SelectedItem="{Binding SelectedPerson}"
IsSynchronizedWithCurrentItem="True">

Both the Persons collection and SelectedPerson are properties on my ViewModel (VM). Its possible to use CollectionViewSource.GetDefaultView(Persons).CurrentItem – but I find it useful to expose and bind a simple read/write property. I’ve used this previously for ListView and ListBox without a problem.

I spent some time debugging this right down through BindingExpression and DependencyObject.SetValue. As far as I can tell the exception is thrown because a ConvertBack method (on the default converter) fails when dealing with the MS.Internal.NamedObject that represents the NewItemPlaceholder. This instance is used to represent the blank “new row” if CanUserAddRows is set to True (and the collection supports it). In fact it appears as if the FormatException is actually being thrown within an exception handler whilst attempting to Trace the binding failure. Whoops!

Initially I tried simply putting an try/catch block around the DataGrid code shown above. However, the exception occurred under various conditions – focus on new row, begin edit on a new row and rollback on a new row. Not all of these could be easily caught because they would leave the grid in an invalid state. Eventually the answer (HACK) became obvious – to use a converter on the binding.

using System;
using System.Windows;
using System.Windows.Data;
namespace GridEditing.Converters
{
public class IgnoreNewItemPlaceHolderConverter : IValueConverter
{
private const string NewItemPlaceholderName = "{NewItemPlaceholder}";
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
return value;
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
if ( value != null && value.ToString() == NewItemPlaceholderName )
return DependencyProperty.UnsetValue;
return value;
}
}
}

All we are doing here is not binding when we encounter the “new row” instance. Notice the curly braces in the NewItemPlaceholder ToString() representation? This, I believe, is why it causes the FormatException since the ToString() is used to construct a formatString which is then passed to the TraceEvent method. However, because the curly braces aren’t escaped it expects a string token number, e.g. {0} as per string.Format().

Anyhow, using the converter above means that binding to DataGrid.SelectedValue works as expected with the “new row” place holder.

<Window.Resources>
<converters:IgnoreNewItemPlaceHolderConverter x:Key="ignoreNewItemPlaceHolderConverter"/>
</Window.Resources>
<toolkit:DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False"
SelectedItem="{Binding SelectedPerson,Converter={StaticResource ignoreNewItemPlaceHolderConverter
}}" IsSynchronizedWithCurrentItem="True">

WPF Charting

Yesterday, I received an e-mail from a developer who has been working on a set of WPF charting controls called amCharts for WPF. I was intrigued so I went over to the website to have a look around. Suffice to say I was easily impressed enough by the demos on the website to download myself a copy of the free (link ware) version.

The download, if anything, was even more impressive. The class library is concise, consistent and obviously well thought through (or evolved). Also, unlike other “bloatware” libraries this one weighs in at only just over 200Kb!

amCharts Torus

If you like what you see over at amCharts and are considering purchasing the Pro version then you may want to take advantage of a 50% discount code “spencen” when placing your order. Thanks go to Alan from amCharts for making me aware of his product and providing the discount which should be good till the end of May 2009.

Editing Indicator in DataGrid Row Header

Editable grids will quite commonly show an indicator in the row header area to indicate that a row is currently being edited. This is trivial to achieve using Microsoft’s WPF DataGrid.

 GridEditing - Edit Indicator

All that is needed is a DataTemplate assigned to the RowHeaderTemplate property of the DataGrid. The template simply shows or hides the editing image based upon whether the current row is being edited.

<SolidColorBrush x:Key="gridLineBrush" Color="#FFCDEFFE"/>
<DataTemplate x:Key="rowHeaderTemplate">
<StackPanel Orientation="Horizontal">
<Image x:Name="editImage" Source="Images/Edit.png" Width="16" Margin="1,0" Visibility="Hidden"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type toolkit:DataGridRow}},Path
=Item.IsEditing}"
Value
="True"> <Setter TargetName="editImage" Property="Visibility" Value="Visible"/> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> <Style TargetType="{x:Type toolkit:DataGrid}"> <Setter Property="GridLinesVisibility" Value="All"/> <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource gridLineBrush}"/> <Setter Property="VerticalGridLinesBrush" Value="{StaticResource gridLineBrush}"/> <Setter Property="RowHeaderTemplate" Value="{StaticResource rowHeaderTemplate}"/> <Style.Resources> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/> <SolidColorBrush x:Key="{x:Static toolkit:DataGrid.FocusBorderBrushKey}" Color="{StaticResource gridLineBrush}"/> </Style.Resources> </Style>

There is an IsEditingRowItem property on the DataGrid but unfortunately its private. As it happens my base model class has an IsEditing property as part of its IEditableObject implementation. So I simply bind the visibility of the image to that.

#region IEditableObject Members
public void BeginEdit()
{
IsEditing = true;
}
public void CancelEdit()
{
IsEditing = false;
    // RollbackPropertyValues( _preEditValues );
}
public void EndEdit()
{
IsEditing = false;
}
#endregion

ReadOnly Rows and Cells in a DataGrid

A common requirement for a DataGrid control is to have cells, or entire rows and/or columns that are read-only, or in other words non-editable. My requirements for this are as follows:

  1. ReadOnly can be applied to the entire grid, a column, a row, or an individual cell.
  2. The cell(s) must not allow the cell value to be modified.
  3. The cell(s) must be highlighted in some manner (e.g. background colour) to indicate that they are different to the editable cells.
  4. ReadOnly columns require only single direction data-binding (i.e. Mode=OneWay to read-only properties).

GridEditing - ReadOnly Rows

The Microsoft WPF DataGrid meets these requirements via:

  • DataGrid.IsReadOnly property
<toolkit:DataGrid IsReadOnly="True"

  • DataColumn.IsReadOnly property
<toolkit:DataGridTextColumn Binding="{Binding FullName,Mode=OneWay}" IsReadOnly="True"/>

We can use a simple style targeting all DataGridCells to change the background colour.

<Style TargetType="{x:Type toolkit:DataGridCell}">
    <Style.Triggers>
        <Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
</Style>

So the only thing that’s really missing here is the ability to mark an entire row as read-only. In my experience this is a common requirement – we have a list of records displayed in the grid some of which are locked/completed/secured, whilst others can be edited.

One solution is to override the OnBeginningEdit method of the DataGrid. The following example assumes that I have an attached property ControlSupport.IsReadOnly.

protected override void OnBeginningEdit( DataGridBeginningEditEventArgs e )
{
base.OnBeginningEdit( e );
bool isReadOnlyRow = ControlSupport.GetIsReadOnly( e.Row );
if ( isReadOnlyRow )
e.Cancel = true;
}

However, since I’ve got used to “tweaking” some of the DataGrid code I decided to instead to simply add an IsReadOnly property to the DataGridRow class.

public bool IsReadOnly
{
get { return (bool) GetValue( IsReadOnlyProperty ); }
set { SetValue( IsReadOnlyProperty, value ); }
}
// Using a DependencyProperty as the backing store for IsReadOnly.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register( "IsReadOnly", typeof( bool ), typeof( DataGridRow ), 
new FrameworkPropertyMetadata( false, OnNotifyRowAndCellsPropertyChanged ) );

private static void OnNotifyRowAndCellsPropertyChanged( DependencyObject d, 
DependencyPropertyChangedEventArgs e ) { ( d as DataGridRow ).NotifyPropertyChanged( d, e, NotificationTarget.Rows | NotificationTarget.Cells ); }

Then I just needed to make sure that the read-only property DataGridCell.IsReadOnly would correctly return the right value when its row was marked as read-only.

private static object OnCoerceIsReadOnly(DependencyObject d, object baseValue)
{
var cell = d as DataGridCell;
var column = cell.Column;
var row = cell.RowOwner;
var dataGrid = cell.DataGridOwner;
return DataGridHelper.GetCoercedTransferPropertyValue(
cell,
baseValue,
IsReadOnlyProperty,
row,
DataGridRow.IsReadOnlyProperty,
column,
DataGridColumn.IsReadOnlyProperty,
dataGrid,
DataGrid.IsReadOnlyProperty);
}

There’s a fairly complex series of notification propagation calls going on within the DataGrid classes. For this solution to work it requires that the DataGridRow.IsReadOnly property changing flows down and causes the read-only DataGridCell.IsReadOnly property to be re-evaulated (via the coerce method above). I had to add another GetCoervedTransferPropertyValue method that took another pair of object/property parameters, and also tweaked the DataGridCell.NotifyPropertyChanged as follows:

else if (e.Property == DataGrid.IsReadOnlyProperty || 
e.Property == DataGridColumn.IsReadOnlyProperty ||
e.Property == DataGridRow.IsReadOnlyProperty ||
e.Property == IsReadOnlyProperty) { DataGridHelper.TransferProperty(this, IsReadOnlyProperty); }

Now in my XAML I can do the following (assuming I have an IsReadOnly property on my business objects):

<Style TargetType="{x:Type toolkit:DataGridRow}">
<Setter Property="IsReadOnly" Value="{Binding IsReadOnly}"/>
</Style>

When is a WPF DataGrid read-only CheckBox not read-only?

I found the answer to this riddle when I decided to style the DataGridCheckBoxColumn of Microsoft’s WPF DataGrid. By default the CheckBox displayed by the column template is not centered horizontally or vertically. I thought this looked at little tacky so I decided to apply a custom Style to the ElementStyle (and EditElementStyle) property.

<Style  x:Key="CheckBoxStyle" TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
    <Setter Property="HorizontalAlignment" Value="Center"/> 
<Setter Property="Margin" Value="0,2,0,0"/> </Style>
<toolkit:DataGridCheckBoxColumn Binding="{Binding IsPensioner}" 
Header
="Pensioner?"
ElementStyle="{StaticResource CheckBoxStyle}"
EditingElementStyle="{StaticResource CheckBoxStyle
}"/> <toolkit:DataGridCheckBoxColumn Binding="{Binding IsEditing,Mode=OneWay}"
Header="Is Editing"
ElementStyle="{StaticResource CheckBoxStyle}"

IsReadOnly="True"
/>

What I later discovered is that applying this style has somehow made my read-only CheckBox editable. But only via mouse clicks! Using the keyboard to focus to the cell and pressing Space didn’t cause the CheckBox to toggle, but left clicking on the CheckBox did. What’s going on?

My guess is that the default style applied to the DataGridCheckBoxColumn’s CheckBox in non-edit mode (ElementStyle) sets the IsHitTestVisible property to False to disable clicking on the cell. The keyboard events are swallowed by the DataGrid using Preview events – so no styling is required to prevent keyboard access.

The rule would therefore appear to be that if you set ElementStyle on the DataGridCheckBoxColumn you must include IsHitTestVisible=”False” to prevent it from “seeming” that the control allows edits.

<Style  x:Key="CheckBoxStyle" TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,2,0,0"/>
</Style>
<Style  x:Key="ReadOnlyCheckBoxStyle" TargetType="{x:Type CheckBox}" BasedOn="{StaticResource CheckBoxStyle}">
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
<toolkit:DataGridCheckBoxColumn Binding="{Binding IsPensioner}"
Header="Pensioner?"
ElementStyle="{StaticResource ReadOnlyCheckBoxStyle}"
EditingElementStyle="{StaticResource CheckBoxStyle}"/>
<toolkit:DataGridCheckBoxColumn Binding="{Binding IsEditing,Mode=OneWay}"
Header="Is Editing"
ElementStyle="{StaticResource ReadOnlyCheckBoxStyle}"
IsReadOnly="True"/>

Binding an Enum Property to a ComboBox using customized text

The problem

I want to data bind a property on my Model to a ComboBox that allows selection from a list of Enum values. For example, my Person class has a HighestEducationLevel property of type EducationLevel.

 GridEditing

The second part of this problem is that I want to provide an optional customized text description for each of my enumeration values. For example, the enumeration value EducationLevel.PreSchool should be displayed as “Pre-school” in the ComboBox.

GridEditing - TypeConverter ComboBox

Solution 1 – Bind to Enum.GetValues()

There are plenty of blog posts and forum answers that show the following technique that can be accomplished in XAML alone. I first saw this on a post by Karl Schifflet.

You define a static resource as an ObjectDataProvider that simply uses a method call to get an array of the enumerated values.

<ObjectDataProvider x:Key="EducationLevelList" MethodName="GetValues" ObjectType="{x:Type local:EducationLevel}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:EducationLevel"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

This can then be data bound as the ItemsSource for a ComboBox – in my case its a ComboBox column of a WPF DataGrid.

<toolkit:DataGridComboBoxColumn Header="Education Level"
SelectedValueBinding="{Binding HighestEducationLevel}"
ItemsSource="{Binding Source={StaticResource EducationLevelList}}"/>

Solution 2 – Bind to Custom Method

This technique can be taken a step further by providing your own method to be used by the ObjectDataProvider rather than relying on Enum.GetValues(Type). This then provides the opportunity to provide custom sorting, filtering and text for the list of enumeration values.

One way to achieve the custom text values is to have the method return a list of “wrapper” objects that provide access to both the underlying enumeration value and the custom text.

public class EnumMapper
{
public EnumMapper( object enumValue, string enumDescription )
{
Enum = enumValue;
Description = enumDescription;
}
public object Enum { get; private set; }
public string Description { get; private set; }
}

The enum type can then have each of its members (fields) that require a custom text decorated with a custom attribute as follows.

public enum EducationLevel
{
None,
[EnumDisplayName("Pre-school")]
PreSchool,
[EnumDisplayName( "Junior school" )]
JuniorSchool,
[EnumDisplayName( "Senior School" )]
SeniorSchool,
Graduate,
[EnumDisplayName( "Post Graduate" )]
PostGraduate,
Professor
}

The new attribute class itself is trivial…

[AttributeUsage(AttributeTargets.Field, AllowMultiple=false)]
public class EnumDisplayNameAttribute : Attribute
{
public EnumDisplayNameAttribute( string displayName )
{
DisplayName = displayName;
}
public string DisplayName { get; set; }
}

The custom method to generate the list then becomes…

public static IList<EnumMapper> GetEnumDescriptions( Type enumType )
{
if ( !enumType.IsEnum )
throw new ArgumentException( "This method can only be called for enum types." );
var list = new List<EnumMapper>();
foreach ( var enumValue in Enum.GetValues( enumType ) )
list.Add( new EnumMapper( enumValue, enumType.GetDisplayName( enumValue ) ) );
return list;
}
public static string GetDisplayName( this Type enumType, object enumValue )
{
if ( !enumType.IsEnum )
throw new ArgumentException( "This method can only be called for enum types." );
var displayNameAttribute = enumType.GetField( enumValue.ToString() )
.GetCustomAttributes( typeof( EnumDisplayNameAttribute ), false )
.FirstOrDefault() as EnumDisplayNameAttribute; if ( displayNameAttribute != null ) return displayNameAttribute.DisplayName; return Enum.GetName( enumType, enumValue ); }

The XAML has to change a little. First the ObjectDataProvider must use the new method, and secondly because the ItemsSource is now a list of EnumMapper instances we must provide DisplayMemberPath and SelectedValuePath properties for the ComboBox.

<ObjectDataProvider x:Key="EducationLevelList" MethodName="GetEnumDescriptions" ObjectType="{x:Type local:BindingSupport}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:EducationList"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

<toolkit:DataGridComboBoxColumn Header="Highest Education Level"
                                SelectedValueBinding="{Binding HighestEducationLevel}"
ItemsSource="{Binding Source={StaticResource EducationLevelList}}"
DisplayMemberPath="Description"
SelectedValuePath="Enum"/>

Solution 3 – Use a customized TypeConverter

Solution 2 provides quite a lot of flexibility but it does mean a couple of extra property setters are required in the XAML (though I guess these could go into a Style). The third approach is to use a TypeConverter to “magically” convert enum values to strings. The major benefit of this approach is that it will work not just for ComboBoxs but anywhere an enum is bound to text property, e.g. in a TextBlock or TextBox.

First we declare a new TypeConverter that has some special processing that allows its to generate the custom text. All enums by default use the EnumConverter anyway – we are just providing an extra lookup to check for a custom attribute.

public class EnumTypeConverter : EnumConverter
{
public EnumTypeConverter( Type enumType ) : base( enumType ) { }
public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType )
{
if ( destinationType == typeof(string) && value != null )
{
var enumType = value.GetType();
if ( enumType.IsEnum )
return GetDisplayName( value );
}
return base.ConvertTo( context, culture, value, destinationType );
}
    private string GetDisplayName( object enumValue )
{
var displayNameAttribute = EnumType.GetField( enumValue.ToString() )
.GetCustomAttributes( typeof( EnumDisplayNameAttribute ), false )
.FirstOrDefault() as EnumDisplayNameAttribute; if ( displayNameAttribute != null ) return displayNameAttribute.DisplayName; return Enum.GetName( EnumType, enumValue ); } }

The next step is to make sure that all our enums use the new TypeConverter. This is done by decorating the enum with a TypeConverter attribute.

[TypeConverter(typeof(EnumTypeConverter))]
public enum EducationLevel
{
None,
[EnumDisplayName("Pre-school")]
PreSchool,
[EnumDisplayName( "Junior school" )]
JuniorSchool,
[EnumDisplayName( "Senior School" )]
SeniorSchool,
Graduate,
[EnumDisplayName( "Post Graduate" )]
PostGraduate,
Professor
}

Now we can change our XAML back to its original simplified form (as per Solution 1) and yet we still get our customized text appearing.

<ObjectDataProvider x:Key="EducationLevelList" MethodName="GetValues" ObjectType="{x:Type local:EducationLevel}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:EducationLevel"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

<toolkit:DataGridComboBoxColumn Header="Education Level"

                               
SelectedValueBinding="{Binding HighestEducationLevel
}"

                               
ItemsSource="{Binding Source={StaticResource EducationLevelList}}"/>

Other Considerations

In the example here I’ve just used hard-coded strings for the EnumDisplayName attributes. However, there is no reason these couldn’t be resource IDs or the like and the GetDisplayName method changed accordingly.

Also, if we want the TypeConverter to have the ability to ConvertFrom the customized text then we need to do a little more work. This is handy in the scenarios where the user may be able to type (as opposed to select from a list) the enum values. So the EnumTypeConverter changes to the following.

public class EnumTypeConverter : EnumConverter
{
private IEnumerable<EnumMapper> _mappings;
public EnumTypeConverter( Type enumType ) : base( enumType )
{
_mappings = from object enumValue in Enum.GetValues(enumType)
select new EnumMapper( enumValue, GetDisplayName(enumValue) );
}
public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType )
{
if ( destinationType == typeof(string) && value != null )
{
var enumType = value.GetType();
if ( enumType.IsEnum )
return GetDisplayName( value );
}
return base.ConvertTo( context, culture, value, destinationType );
}
public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value )
{
if ( value is string )
{
var match = _mappings.FirstOrDefault( mapping => string.Compare( mapping.Description, (string) value, true, culture ) == 0 );
if ( match != null )
return match.Enum;
}
return base.ConvertFrom( context, culture, value );
}

private string
GetDisplayName( object enumValue )
{
var displayNameAttribute = EnumType.GetField( enumValue.ToString() )
.GetCustomAttributes( typeof( EnumDisplayNameAttribute ), false )
.FirstOrDefault() as EnumDisplayNameAttribute;

if ( displayNameAttribute != null )
return displayNameAttribute.DisplayName;

return Enum.GetName( EnumType, enumValue );
} }

WPF DataGrid Tips

I’ve been struggling at work to use Microsoft’s WPF DataGrid (from their WPF Toolkit) to fulfil a fairly basic set of requirement. The following is simply a list of lessons learned.

  1. Remember to set the SortMemberPath for all DataGridTemplateColumns. Otherwise the column header is “inactive” and doesn’t allow sorting regardless of setting CanUserSort.
  2. Remember to set the ClipboardContentBinding for all DataGridTemplateColumns. Otherwise the column data will be copied to the clipboard as an empty string.

    <toolkit:DataGridTemplateColumn Header="Date of Birth"
                                                    
    SortMemberPath="DateOfBirth"
                                                    
    ClipboardContentBinding="{Binding DateOfBirth
    }">
          <
    toolkit:DataGridTemplateColumn.CellTemplate
    >
              <
    DataTemplate
    >
                  <
    TextBlock Text="{Binding DateOfBirth,Mode=OneWay,StringFormat=d}" Margin
    ="2,0,2,2"/>
              </
    DataTemplate
    >                    
          </
    toolkit:DataGridTemplateColumn.CellTemplate
    >
          <
    toolkit:DataGridTemplateColumn.CellEditingTemplate
    >
              <
    DataTemplate
    >
                  <
    toolkit:DatePicker SelectedDate="{Binding DateOfBirth,Mode
    =TwoWay}"/>
              </
    DataTemplate
    >
          </
    toolkit:DataGridTemplateColumn.CellEditingTemplate
    >
      </
    toolkit:DataGridTemplateColumn>

  3. As with other ItemsControls you will most likely want to redefine HighlightBrush and HighlightTextBrush to avoid the high contrast (and very old fashioned) row selection colours.
  4. Use Styles embedded in the DataGrid’s style’s Resources collection to override attributes of controls that will be used for editing. For example, setting the BorderThickness=”0” and Padding=”0” on the DatePicker.
  5. Watch out for implicit Styles that effect Button. The grid is made up of lots of buttons (grid, row and column headers) so having an implicit style define MinWidth or Margins can lead to some unsightly grid layouts.
  6. DataGridCheckBoxColumn doesn’t centre vertically and its default margin doesn’t seem to match the DataGridTextColumn. Setting the Margin for DataGridCheckBoxColumns to  “2”, or at least “0,2,0,0” seems to do the trick.
  7. Setting an EditingElementStyle for a DataGridTextBoxColumn to CharacterCasing=”Upper” is not honoured if the keystroke is used to enter edit mode. Requires a simple fix to the PrepareCellForEdit method in DataGridTextBoxColumn. Refer http://www.codeplex.com/wpf/Thread/View.aspx?ThreadId=36985.

                        // If text input started the edit, then replace the text with what was typed.
                    string inputText;
                    switch (textBox.CharacterCasing)
                    {
                        case CharacterCasing.Upper:
                            inputText = textArgs.Text.ToUpper();
                            b
    reak
    ;
                        case CharacterCasing.Lower:
                            inputText = textArgs.Text.ToLower();
                            break;
                        default:
                            inputText = textArgs.Text;
                            break;
                    }
                    textBox.Text = inputText;

  8. Placing a DatePicker in a DataGridTemplateColumn doesn’t cause the DatePIcker to automatically gain focus when pressing F2 (enter edit). To get around that I overrode PrepareCellForEdit in DataGridTemplateColumn as follows:

        protected override object PrepareCellForEdit(FrameworkElement editingElement,
                                                                      RoutedEventArgs editingEventArgs)
        {
            editingElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
            return base.PrepareCellForEdit(editingElement, editingEventArgs);
        }

  9. The DatePicker uses the Enter key to highlight the date within its embedded TextBox. This is annoying when used in a DataGridTemplateColumn since the standard behaviour for the Enter key is to commit edits and move down a row. Commenting out this functionality in the DatePicker (within ProcessDatePickerKey) does the trick. 

            private bool ProcessDatePickerKey(KeyEventArgs e)
            {
                switch (e.Key)
                {
                    case Key.System:
                    {
                        switch (e.SystemKey)
                        {
                            case Key.Down: { if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
                                {
                                    TogglePopUp();
                                    return true;
                                }
                                break;
                            }
                        }
                        break;
                    }
                  
    // Removing this functionality makes the control work better in the grid – ENTER goes to next row.
                  
    //case Key.Enter:
                  
    //{
                  
    //    SetSelectedDate();
                  
    //    return true;
                  
    //}
                }
                return false;
            }

Othe
r Resources