I've narrowed down the problem to the following example that has a DataGrid with three columns.
XAML:
<Window x:Class="DataGridColumnTemplate_NotFiringAddingNewItem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="dg" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="299" AutoGenerateColumns="False" Width="497" AddingNewItem="dg_AddingNewItem" CanUserAddRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="DateWorks">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding InvoiceDate}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="DateDoesn'tWork">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding InvoiceDate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding InvoiceDate}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Text" Binding="{Binding Description}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<JobCostEntity> l = new List<JobCostEntity>()
{
new JobCostEntity() { Id = 0, InvoiceDate = DateTime.Now, Description = "A"},
new JobCostEntity() { Id = 0, InvoiceDate = DateTime.Now, Description = "B"}
};
dg.ItemsSource = l;
}
private void dg_AddingNewItem(object sender, AddingNewItemEventArgs e)
{
MessageBox.Show("AddingNewItem");
}
}
public partial class JobCostEntity
{
public int Id { get; set; }
public int JobId { get; set; }
public Nullable<int> JobItemId { get; set; }
public Nullable<System.DateTime> InvoiceDate { get; set; }
public Nullable<System.DateTime> ProcessedDate { get; set; }
public int PackageId { get; set; }
public int DelegateId { get; set; }
public string Description { get; set; }
public Nullable<decimal> LabourCost { get; set; }
public Nullable<decimal> PlantOrMaterialCost { get; set; }
public Nullable<decimal> SubcontractorCost { get; set; }
public Nullable<decimal> TotalCost { get; set; }
public bool Paid { get; set; }
}
If the first column you click on in the new item row is 'DateWorks' or 'Text', then you will raise the AddingNewItem event.
If instead you click the 'DateDoesntWork' column first, you can select a date, but no new item is added until you move to one of the other columns, at which point the value in the 'DateDoesntWork' DatePicker gets cleared.
What on earth is going on?
It's arguably(!) desirable to have the DatePicker already visible to the user (hence both a CellTemplate and a CellEditingTemplate), rather than them have to click the cell to 'reveal' the control.
Is there some way I have to inform the DataGrid that my DataGridTemplateColumn Control has just set a value on a new row? If so, how so?!
EDIT:
Inspired by this post: https://social.msdn.microsoft.com/Forums/vstudio/en-US/93d66047-1469-4bed-8fc8-fa5f9bdd2166/programmatically-beginning-edit-in-datagrid-cell?forum=wpf
I have tried to hack my way around the problem by adding the following to the 'DateDoesntWork' column DatePicker, which does cause the AddingNewItem event to fire, but the selected date still doesn't get added to the underlying entity.
private void DatePicker_GotFocus(object sender, RoutedEventArgs e)
{
if (dg.SelectedIndex == dg.Items.Count - 1)
{
DataGridCellInfo dgci = dg.SelectedCells[0];
DataGridCell dgc = DataGridHelper.GetCell(dg, GetRowIndex(dg, dgci), GetColIndex(dg, dgci));
dgc.Focus();
dg.BeginEdit();
}
}
It seems like the DatePicker is still trying to target the NewItemPlaceholder, if that makes any sense?!
Stranger still, if you select a date in the DateDoesntWork column on the new row, then start editing the Text column on the new row, then without entering any text, select the row above ... now another new row is added and that newly added row shows the date i selected for the row before!!!
Total. Madness.
As Maxime Tremblay-Savard has metioned, it seems like the CellTemplate
is blocking the 'layer' below and stopping the AddingNewItem
event firing, though the built in DataGridColumn
types don't suffer from this problem.
IsHitTestVisible="False"
on theDateDoesntWork
<DataGridTemplateColumn.CellTemplate>
then you'll get theAddingNewItem
event firing when you want and the date persists as you would expect. However you've now got a new problem which is that you have to click on the date picker three times to change the date, I'm thinking that might be an easier problem to fix though, so I though I'd add this suggestion. Maybe try settingIsHitTestVisible="True"
on the fly on some mouse preview event. – EmaliaIsHitTestVisible="False"
should only make it require 2 clicks to open the date picker. I just tested to confirm this. The standard controls, such as checkbox also require two clicks, so this would be in line with the anticipated behavior of anyone using the control. IMO, your solution is the correct one if we are comparing the functionality of this template column to the built in controls. – Overblouse