13

i've a problem updating my datagrid when clicking the button by using NotifyPropertyChanged. It works if i set the DataGrid.ItemsSource in code behind, but it doesn't if i set it in xaml. here's some code of code behind & xaml:

namespace MyWpfDataBindingLab
{
public partial class NpcWindow : Window
{
    DataCollection dc = new DataCollection();

    public NpcWindow()
    {
        InitializeComponent();
        //command binding code
        //...
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        //if i set the ItemsSource here, updating of the UI works
        //dataGrid1.ItemsSource = dc;
    }

    private void CmdCollectionChangedExecute(object sender, ExecutedRoutedEventArgs e)
    {
        foreach (SampleClass s in dc)
        {
            s.Property1 = "changed";
            s.Property3 = "changed";
            s.Property3 = "changed";
            break;
        }

        dc.Add(new SampleClass("new sample 1", "new sample 2", "new sample 3"));
    }
}
}

<Window x:Class="WPFDataBinding.NpcWindow"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:npc="clr-namespace:WPFDataBinding.NotifyPropChanged"
    Title="MainWindow" Height="189" Width="459" Loaded="Window_Loaded">
<Window.Resources>
    <npc:DataCollection x:Key="dataCol"/>
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
    </Grid.ColumnDefinitions>
    <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="349,110,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
    <!-- if i set the ItemsSource here, updating of the UI doesn't work -->
    <DataGrid ItemsSource="{Binding Source={StaticResource dataCol}, Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
              AutoGenerateColumns="True" Height="103" HorizontalAlignment="Left" Margin="12,12,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="331" />
</Grid>

my data & NotifyPropertyChanged implementation:

namespace MyWpfDataBindingLab.NotifyPropChanged
{    
public class SampleClass : NotifyPropertyChanged
{
    private string _field1;
    private string _field2;
    private string _field3;

    public string Property1
    { 
        get { return _field1; } 
        set 
        {
            _field1 = value;
            OnPropertyChanged("Property1");
        }
    }

    public string Property2
    { 
        get { return _field2; } 
        set 
        {
            _field2 = value;
            OnPropertyChanged("Property2");
        }
    }

    public string Property3
    { 
        get { return _field3; } 
        set 
        {
            _field3 = value;
            OnPropertyChanged("Property3");
        }
    }

    public SampleClass()
    {
        _field1 = "value1";
        _field2 = "value2";
        _field3 = "value3";
    }

    public SampleClass(string p1, string p2, string p3)
    {
        _field1 = p1;
        _field2 = p2;
        _field3 = p3;
    }
}
}

namespace MyWpfDataBindingLab.NotifyPropChanged
{
public abstract class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
}

namespace MyWpfDataBindingLab.NotifyPropChanged
{
public class DataCollection : ObservableCollection<SampleClass> 
{
    public DataCollection()
    {
        this.Add(new SampleClass());
        this.Add(new SampleClass());
        this.Add(new SampleClass());
    }
}
}

i have no idea what the problem is. i'd appreciate it if someone can help solving my problem.

nllpntr
  • 131
  • 1
  • 1
  • 4
  • Do you have any code that actually adds items to the instance of `DataCollection`? If you add nothing then the `CmdCollectionChangedExecute` handler won't fire. – slugster Sep 08 '12 at 08:42
  • the collection is updated via CmdCollectionChangedExecute when clicking the button. the method name is a little confusing. it shoud be CmdCollectionChangeExecute. updating works fine, but the ui is only updating if set the ItemsSource in code behind. i like to do it only in the xaml file. – nllpntr Sep 08 '12 at 09:39

3 Answers3

15

In your codebehind .xaml.cs create property

   public ObservableCollection<SampleClass> MyCollection {get; set;}

   private void Window_Loaded(object sender, RoutedEventArgs e)
   {
    //if i set the ItemsSource here, updating of the UI works
      dataGrid1.ItemsSource = MyCollection;
   }

In XAML:

   <DataGrid ItemsSource="{Binding Path=., Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"/>
syned
  • 2,201
  • 19
  • 22
  • thanks for the quick answer. your code is working well. is it possible to get rid of the dataGrid1.ItemsSource = MyCollection; in code behind, and do the complete binding in xaml? – nllpntr Sep 08 '12 at 09:45
  • You can use this.DataContext = MyCollection; – syned Sep 08 '12 at 14:00
  • Thanks! This is just what I was looking for - solved my problem quite nicely. – Fred Mar 08 '17 at 19:25
10

I followed up on syned's tip. For me I had to us the Mode as

Mode=TwoWay

The key here was the

UpdateSourceTrigger

property.

Thanks a lot...!

sm2mafaz
  • 392
  • 3
  • 15
2

When you go crazy (like me) because it doesn't work this time (while it always worked!) Check the order of the calls. The OnPropertyChanged() must be called after the value was assigned.

public string Property1
{ 
    get { return _field1; } 
    set 
    {
        // assign the value first ...
        _field1 = value;

        // ... then call the property changed
        OnPropertyChanged(nameof(Property1));
    }
}
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52