2

I'm curious how this works, because I have a MainViewModel, which has Property say called SubViewModel which has a Property of ObservableCollection (we'll call it Property1.)

I've implemented INotifyChangedProperty on everything.

My Main Window

<Window ..
    DataContext="{Binding MainViewModel}" />
...
    <StackPanel DataContext="{Binding SubViewModel}">
        <local:SomeControl DataContext="{Binding}" />
    </StackPanel>
</Window>

And my UserControl

<UserControl Name="SomeControl">
    <DataGrid Name="MyDataGrid" ItemSource="{Binding Property1, Mode=TwoWay}" CurrentCellChanged="TestMethod" />
    ...
</UserControl>

In my test method, just as a test to figure out why the changes are not propegating up to the main view model I do something like this

private void TestMethod()
{
    var vm = this.DataContext as SubViewModel;

    var itemSourceObservableCollection = MyDataGrid.ItemsSource as ObservableCollection<MyType>;

    //I thought vm.Property1 would be equal to itemSourceObservableCollection
    //but they are not, itemSourceObservableCollection shows the changes I've made
    //vm.Property1 has not reflected any changes made, even though I though they were the same item
}

So I figured out that ItemSource must create a copy of the item you bind it to? I'm stuck here, how do manually notify the viewModel that this property has changed and it needs to update? I thought that was INotifyPropertyChanged's job?

I think part of my problem is I lack the understanding of how this kinda works internally. If anyone can point to a good blog post, or documentation to help me understand why my code isn't working the way I expected, that would be great.

Kyle Gobel
  • 5,530
  • 9
  • 45
  • 68
  • 2
    _the changes are not propegating up to the main view model_ - what kind of changes? Afaik `Mode=TwoWay` is not supported for `ItemsSource` . – H H Jul 31 '13 at 11:26
  • 1
    _I thought that was INotifyPropertyChanged's job?_ No, that only works in the other direction (ViewModel -> View). – H H Jul 31 '13 at 11:27
  • @HenkHolterman, wadr, it is supported on templated items – Gayot Fow Jul 31 '13 at 12:56
  • @GarryVass - TwoWay works for the individual Items but afaik you cannot Insert/Remove through ItemsSource. – H H Jul 31 '13 at 13:28
  • @HenkHolterman, When this property is set to true a blank row is displayed at the bottom of the DataGrid. A user can enter a new item into the blank row. Adding a new row adds an item to the ItemsSource. You can set default values for the new item by handling the InitializingNewItem event and setting the values programmatically. http://msdn.microsoft.com/en-us/library/system.windows.controls.datagrid.canuseraddrows.aspx – Gayot Fow Jul 31 '13 at 13:42
  • @blindmeis, Please take that up with Microsoft, I'm just relaying their what their documentation says... And appears to work quite well based upon observation. – Gayot Fow Jul 31 '13 at 15:41

2 Answers2

1

1) No copy is made.

2) ObservableCollection will propogate changes made to the collection, not the items within the collection. So you'll see additions, deletions etc. but NOT property changes to items within the collection.

3) If you want to see changes made to individual items in the ObservableCollection, you need to implement INotifyPropertyChanged on those items.

Barracoder
  • 3,696
  • 2
  • 28
  • 31
0

There's actually TWO different issues here. What happens internally when you bind to a collection? AND why changes on the user surface are not propagated back to your View Model. Based upon what you wrote, the two issues are not connected, but let's take them one at a time...

For the first issue... When you bind a collection, the WPF binding engine creates a "CollectionView" class that mediates between your object store and the logical tree. You can, if needed, get a copy of the the "CollectionView" using a static method on CollectionViewSource...

var cvs = CollectionViewSource.GetDefaultView(MyCollectionOfThings);

There are several interesting properties in the result, and some of them contain write accessors which allow you to directory modify the CollectionView.

For the second issue... The business classes in your SubViewModel need to inherit from INotifyPropertyChanged such that changes are 'announced' via the WPF binding engine. Your VM should be a publisher, but can also be a subscriber. A property that participates in the INotifyPropertyChanged plumbing gets declared like this...

    private string _name;
    [Description("Name of the driver")]
    public string Name
    {
        [DebuggerStepThrough]
        get { return _name; }
        [DebuggerStepThrough]
        set
        {
            if (value != _name)
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }

This code publishes changes, but can also subscribe to changes made on the user surface by setting the appropriate attributes in your Xaml.

Background reading: What is a CollectionView? Also, Similar question

Community
  • 1
  • 1
Gayot Fow
  • 8,710
  • 1
  • 35
  • 48