0

I have the following code:

public class ViewModel
{
    private IServiceAccess _svcAccess;

     public ViewModel(IServiceAccess svcAccess)
     {
        _svcAccess = svcAccess;

     }

    public ObservableCollection<Item> ExistingItems
    {
        get
        {
            return new ObservableCollection<Item>(_svcAccess.GetExistingItems());
        }
    }

}

<DataGridTemplateColumn.CellTemplate>
  <DataTemplate>
    <CheckBox IsChecked="{Binding Path=Ignore, UpdateSourceTrigger=PropertyChanged}" />
  </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

I want to be able to instantly responsd when the User checks the box - Everywhere I've read this says it "updates the source", but how do I actually respond to that? The only other examples I've found have been the other way around, i.e. a change in the ViewModel raises the event to notify the View.

At the moment I've got an ObservableCollection in my ViewModel that is bound to the datagrid. Ignore is a field on my Item object, stored in the DB as a bool.

What I'd like to happen is checking the box triggers an event I can respond to in the ViewModel.

Note - I was going to map my EF entities into separate VM entities for the WPF layer, but was advised it was unecessary and overkill.

tonydev314
  • 241
  • 1
  • 2
  • 10
  • Does this help? https://stackoverflow.com/questions/15480279/wpf-check-box-check-changed-handling – Nicholas Jul 08 '20 at 16:35
  • No - he is binding a static field to a checkbox and planning on doing something with the VM when it is clicked via an Event - which is an anti-pattern I believe. I've got checkboxes bound to a field in the VM and I'd like the VM to react when the value changes. – tonydev314 Jul 08 '20 at 16:56

2 Answers2

2

In your Item view model you have a property Ignore. When the checkbox is clicked in the user interface, the binding will set the changed value on the Ignore property in your view model. There you can respond to the change in the setter of the property. The below code is just an example of an Ignore property with a backing field.

private bool _ignore;

public bool Ignore
{
    get => _ignore;
    set
    {
        if (_ignore != value)
        {
            _ignore = value;
               
            // Do Something here reacting to the changed checkbox state

            OnPropertyChanged(nameof(Ignore));
        }
    }
}
thatguy
  • 21,059
  • 6
  • 30
  • 40
  • I don't have an Item ViewModel I have a collection of Items in my ViewModel that are created by EF - all I'm doing in my ViewModel is converting the ICollection from my DataLayer into an ObservableCollection – tonydev314 Jul 08 '20 at 17:13
  • 1
    Your collection contains items and an item has an `Ignore` property that you bind to. You need to be able to change the setter of that property in your item class to respond to the property change. If those are auto-generated and you cannot change them, you will need to wrap the items to expose an `Ignore` property that you can access. Alternatively you can handle the `Checked` and `Unchecked` events, but that is not the preferred way in MVVM. – thatguy Jul 08 '20 at 17:20
  • Yes I understand, I'm just trying to grasp the ramifications of that - I'm using code-first so the class is not auto-generated, but it lives in my DAL. The approach you seem to be suggesting (please correct me if I'm mistaken) is for this class to KNOW about my ViewModel which lives in my FrontEnd? – tonydev314 Jul 08 '20 at 17:24
  • OK - with some guidance, I've figured it out :) Thanks for the help. – tonydev314 Jul 08 '20 at 17:44
1

I'm slightly confused by your use of "ViewModel" in the question

I've got an ObservableCollection in my ViewModel

versus in the comment

I've got checkboxes bound to a field in the VM

Presumably these are 2 different VMs: a parent VM containing an observable collection of child VMs.

I think you are stuck on thinking that the action has to take place in the parent VM. Simply change the field on the child VM to a property and do what you want in that property's setter. Of course if you want to call code in the parent from the child's setter, you can.

ShawnMartin
  • 282
  • 2
  • 7
  • @thatguy 's answer does a nice job showing the actual code that's needed in the child VM. – ShawnMartin Jul 08 '20 at 17:10
  • No my viewmodel contains ObservableCollection A field on Item is bool Ignore. – tonydev314 Jul 08 '20 at 17:11
  • I've updated the OP with the code for my VIewModel if it makes it clearer. – tonydev314 Jul 08 '20 at 17:19
  • 1
    You haven't shown the code for the Item class, but presumably it is not a VM. The classes that participate in update-able binding need to be VMs. Typically you would do this by creating an ItemViewModel class and feeding the Item in to its constructor. That way you keep your Item class ignorant of the UI. – ShawnMartin Jul 08 '20 at 17:28
  • OK - I understand how to do that, but then in the ItemViewModel class, I'd need a reference to the DAL AND to the parent ViewModel - the former to update the Item in the DB and the latter to remove the Item from the Collection (which presumably would then automatically be reflected in the Grid). Is this OK? – tonydev314 Jul 08 '20 at 17:31
  • Apologies if I'm a bit slow, I've had a 7 year break from coding, and things have changed a bit! – tonydev314 Jul 08 '20 at 17:32
  • 1
    No worries! Yes, you could simply pass both the parent VM and the DAL in to the child in the constructor as well.Or you could create a function in the parent that does the DB and collection work, then only pass that function as an Action to the child VM's constructor. – ShawnMartin Jul 08 '20 at 17:39
  • Thanks - that's really helpful - I like the Action approach! – tonydev314 Jul 08 '20 at 17:43
  • I've got that working happily thank you! How would I go about properly handling an event that DIDN'T change any data though? For example, clicking on a row to open a separate view that contained further details for the clicked element? – tonydev314 Jul 08 '20 at 18:38
  • OK - figured it out from here: https://stackoverflow.com/questions/18595654/wpf-datagrid-double-click-cell-mvvm-design – tonydev314 Jul 08 '20 at 19:14