I have very simlistic (partof) data-bound ViewModel that exposes a Nullable property, which is later rendered in a DataGrid
:
public class MyViewModel : ViewModelBase
{
private DateTime? _date;
public DateTime? Date {
get => _date;
set => Set(ref _date, value);
}
}
<DataGrid ItemsSource="{Binding MyViewModels}">
<DataGrid.Columns>
<DataGridTextColumn Header="Date" Binding="{Binding Date}"/>
</DataGrid.Columns>
</DataGrid>
Everything works as expected, Dates which has a value are displayed, cells for null
values are completely blank.
However, how can I prefill bound null
values with DateTime.Now
when entering cell edit mode? Bonus point: the DateTime.Now
is reverted back to null
in case cell edit was aborted.
Attempt 2 (based on comments), using DataGridTemplateColumn
and swich TextBlock
without TargetNullValue
for a TextBox
with one, sadly that is not a valid binding:
TargetNullValue '6/25/2019 0:00:00' (type 'DateTime') cannot be converted for use in 'Text'
<DataGridTemplateColumn SortMemberPath="Date" Header="Date">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Date}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Date, TargetNullValue={x:Static sys:DateTime.Today}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
You could use the TargetNullValue
property if you bind to the SelectedDate
property of an invisible DatePicker
:
<DataGridTemplateColumn SortMemberPath="Date" Header="Date">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Date}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<DatePicker x:Name="dp" SelectedDate="{Binding Date, TargetNullValue={x:Static sys:DateTime.Today}}" Visibility="Collapsed" />
<TextBox Text="{Binding Text, ElementName=dp}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The other option would be to implement a value converter that converts DateTime.Today
to a string
.
Thanks for the answer, its definitely much simpler plus it allows non-static values. However, it is not possible to accept the pre-filled DateTime.Today unless user changes it to a different date and back ...
If you want to persist the value, you should set the source property explicitly. You could do this by handling the CellEditEnding
event. Something like this:
private void Dgm_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
ContentPresenter cp = e.EditingElement as ContentPresenter;
if (cp != null)
{
Panel panel = VisualTreeHelper.GetChild(cp, 0) as Panel;
if (panel != null)
{
TextBox tb = panel.Children.OfType<TextBox>().FirstOrDefault();
if (tb != null)
{
DateTime dt;
if (DateTime.TryParse(tb.Text, out dt))
{
e.Row.DataContext.GetType().GetProperty("Date").SetValue(e.Row.DataContext, dt);
}
}
}
}
}