Abhi.Net Abhi.Net - 3 months ago 8
C# Question

Only last control in Data Template column getting updated

I have a DataTemplate Column with 2 DatePickers that are bound to 2 properties. When the data in these control is changed only last control gets updated

<sdk:DataGridTemplateColumn Width="300" CanUserReorder="False" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid MouseRightButtonDown="ActionsGrid_MouseRightButtonDown" Width="300" Height="40" MouseLeftButtonDown="ActionsGrid_MouseLeftButtonDown">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Stretch" Width="100" Text="{Binding Start, Converter={StaticResource DateConverter}}"
Padding="2" HorizontalAlignment="Center" />
<TextBlock VerticalAlignment="Stretch" Width="100" Text="{Binding Due, Converter={StaticResource DateConverter}}"
Padding="2" HorizontalAlignment="Center" />
</StackPanel>
</Grid>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<sdk:DatePicker VerticalAlignment="Top" Width="100" SelectedDate="{Binding Start, Mode=TwoWay,}" Padding="2" />
<sdk:DatePicker VerticalAlignment="Top" Width="100" SelectedDate="{Binding Due, Mode=TwoWay, ValidatesOnDataErrors=True}" Padding="2" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>


In this case if I update both Start and Due Only Due gets updated. Also the binding works fine because if I put a breakPoint on Start in my Model class it gets hit but the value passed is the original value of Start

EDIT 1

After some debugging I found out that If I only have one control inside my DataTemplate it works Fine. Also When I change the Date The break point is hit straightaway. But if I have more than one control the break point is not hit until I focus out of column and then only the last binding works.

EDIT 2

After some mroe debugging I noticed that it will work fine if I only use CellTemplate and discard cell EditTemplate

<sdk:DataGridTemplateColumn Width="300" CanUserReorder="False" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<sdk:DatePicker VerticalAlignment="Top" Width="100" SelectedDate="{Binding Start, Mode=TwoWay,}" Padding="2" />
<sdk:DatePicker VerticalAlignment="Top" Width="100" SelectedDate="{Binding Due, Mode=TwoWay, ValidatesOnDataErrors=True}" Padding="2" />
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>


EDIT 3

private void DatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
{
(sender as DatePicker).GetBindingExpression(DatePicker.SelectedDateProperty).UpdateSource();
}


I was able to refresh binding on both the control using the selectedDatechange event and then refreshing the binding on the sender.

I am still not sure why the 2 way binding working won't work.

Can anyone explain why this is happening?

EDIT 4

Model and Properties

public DateTime? Start
{
get { return _Start; }
set
{
_Start = value; Dirty = true;

if (_Start.HasValue && _Due.HasValue && _Start.Value > _Due.Value)
_dataErrors["Start"] = "Start date cannot be greater than the Due date";
else
if (_dataErrors.ContainsKey("Start"))
_dataErrors.Remove("Start");
NotifyPropertyChanged(); NotifyPropertyChanged("CalcStatus");
}
}
public DateTime? Due
{
get { return _Due; }
set
{
_Due = value; Dirty = true;
if (_Start.HasValue && _Due.HasValue && _Start.Value > _Due.Value)
_dataErrors["Start"] = "Start date cannot be greater than the Due date";
else
if (_dataErrors.ContainsKey("Start"))
_dataErrors.Remove("Start");
NotifyPropertyChanged("Due"); NotifyPropertyChanged("CalcStatus");
}
}

Answer

Alright I think I finally have fixed it. I am still not 100% sure why it wasnt working but I'll create a new small project and try to find out the reason.

What happened was that I modified my NoitifyPropertyCHangedEvent by passing it[CallerMemberName] so that the name of the property calling it is passed automatically. Which means if I change the name property for example "Start" I don't have to worry about updating NotifyPropertyChanged("Start"). public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged([CallerMemberName] string propertyName =null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

This worked fine for all properties except for when I had a DataTemplateColumn. Converting it back to standard code fixed my issue.

public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }