0

I have seen the other questions:

ObservableCollection dependency property does not update when item in collection is deleted

MVVM binding to a User Control with an ObservableCollection dependency property

... an even...

https://go4answers.webhost4life.com/Example/databinding-observable-collection-196835.aspx

But they are either doing something I'm not or I just ain't getting it.

  • I am using MVVM.
  • I have a DataGrid on a View that holds a list of Members.
  • When the user right-clicks on the DataGrid I have a menu of RelayCommands (bound from the ViewModel) that opens.
  • If the user selects more than one Member I want MergeMember.CanExecute to return true.
  • Since I can't bind to the SelectedItems collection I have a DependencyProperty in the View that I fill when the selection changes.

My problem is that the DependencyProperty fires a change when the property itself changes (i.e. the ObservableCollection gets "newed") but not when the items in the collection get changed.

The other solutions I've seen catch the change in the View, I'm trying to notify the ViewModel of the change.

How do I notify the ViewModel of changes to the DependencyProperty collection?

I can post code examples if you feel the need but it's a mess from all the things I've been trying.

Community
  • 1
  • 1
Tom Padilla
  • 924
  • 10
  • 30
  • Nope. The VM should expose the OC as a read only property. If the VM needs to know if the collection changes, then it should subscribe to the CollectionChanged event. If it needs to know about changes of items inside the OC, it should sub/unsub their INPC as they are added/removed from the collection. Ain't no magic to it. –  Jan 27 '15 at 17:24
  • You're saying the View can just change the collection directly? No need to bind? The View can know about the VM but the VM still doesn't need to know about the View...? Hmmm. I'll see how that pans out. Thanks. – Tom Padilla Jan 27 '15 at 19:42
  • Am not clear on what's going on here, but that's normally how things work. Not sure what you're doing on your data grid that can't be accomplished in your VM. –  Jan 27 '15 at 19:45
  • The DataGrid.SelectedItems collection is not a dependency property so I can't bind it to the VM. It's a simple case of getting the info from the View to the VM in an acceptable manner. I got stuck on binding because that's how DataGrid.SelectedItem object and a few other pieces of info get from the View to the VM. But I suppose I could just set the VM property directly from the View codebehind. – Tom Padilla Jan 27 '15 at 19:57
  • If I were in your situ, I'd simply wrap the DataGrid and closely related UI (CRUD buttons, labels, etc) into a user control. Hack and slash your way through the pain via codebehind (it's all UI work, so it's fine! Trust me.), and bind your way to bliss. Expose everything you need via DPs on the surface of the UC. Blam. Done. Move on to the next story. –  Jan 27 '15 at 20:05
  • I tried that and got to the same place: I can tell if the collection surrounding the Items changes but not if the items IN the collection change. – Tom Padilla Jan 28 '15 at 13:47
  • Well, I've been there before. The solution is to have the collection items implement notification and watch both the collections and items. When new items are added, subscribe to their PropertyChanged event. When removed, unsub. It's messy, but it's doable. –  Jan 28 '15 at 14:32

1 Answers1

1

Normally in the situation you're describing I use this solution. In order to know which items in your DataGrid are selected (in a MVVM application) you don't need to expose an ObservableCollection as a DependencyProperty.

In your DataGridRow model you add a property:

public bool IsSelected
{
    get
    {
        return isSelected;
    }
    set
    {
        if (isSelected != value)
        {
            isSelected = value;
            OnPropertyChanged("IsSelected"); // if you are implementing INotifyPropertyChanged
        }
    }
}

Regarding the XAML, in your DataGrid you can use a Style to bind the IsSelected property:

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=People}">
    <DataGrid.Columns>
        <!-- your columns are here -->
    </DataGrid.Columns>

    <DataGrid.ItemContainerStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected}" />
        </Style>
    </DataGrid.ItemContainerStyle>
</DataGrid>

In this way, in the ViewModel you are always aware about which items are selected without subscribing events and you can write your logic in the CanExecute method of your MergeMember RelayCommand.

Il Vic
  • 5,576
  • 4
  • 26
  • 37
  • You say "DataGridRow model" in my case that would be my Member class, right? That's what the rows of the DataGrid are, Members. I tried something like this but I think I got it mungled with other stuff I was trying at the time. I'll give this a clean try when I get home, thanks. I will comeback and mark it "answered" if it works. Don't worry. – Tom Padilla Jan 28 '15 at 13:49
  • Yes, I mean the object which is the model of each DataGridRow, in your case the Member class. Let me know if your code will be able to work. – Il Vic Jan 28 '15 at 15:25