1
\$\begingroup\$

-I have a ListView, and its SelectedItem property is bound to EmployeeModel SelectedEmployee in my VM, and it implements the Set method from MVVM Light. (Basically, OnPropertyChanged, but the MVVM Light version.)

-I have three more ListViews (more, but for simplicity's sake, we'll say three.) They are bound to the following properties in my VM: ObservableCollection<EquipmentAssignmentModel>EquipmentAssignments_StandardIssue, ObservableCollection<EquipmentAssignmentModel>EquipmentAssignments_AdHoc, and <VehicleAssignmentModel>VehicleAssignments.

-EmployeeModel has as these properties: ObservableCollection<EquipmentAssignmentModel>EquipmentAssignments and ObservableCollection<VehicleAssignmentModel>VehicleAssignments.

-When I select a new person in my Employee ListView, SelectedEmployee in my VM is updated. I also want to update the other collections, so that the ListViews display the respective collections. I achieved this by setting the EquipmentAssignment_AdHoc, EquipmentAssignment_StandardIssue, and VehicleAssignment properties in the setter of the SelectedEmployee property. It looks like this:

        private EmployeeModel _selectedEmployee;
        public EmployeeModel SelectedEmployee
        {
            get { return _selectedEmployee; }
            set
            {
                if (Set(ref _selectedEmployee, value))
                {
                    Messenger.Default.Send(new EmployeeToken(value));
                    if (EquipmentAssignments_StandardIssue != null)
                    {
                        EquipmentAssignments_StandardIssue.Clear();
                    }
                    if (EquipmentAssignments_AdHoc != null)
                    {
                        EquipmentAssignments_AdHoc.Clear();
                    }
                    if (SelectedEmployee.EquipmentAssignments != null)
                    {
                        var resultFalse = SelectedEmployee.EquipmentAssignments.Where(x => x.IsStandardIssue == false);
                        var resultTrue = SelectedEmployee.EquipmentAssignments.Where(x => x.IsStandardIssue == true);
                        if (resultFalse != null )
                        {
                            foreach(EquipmentAssignmentRecordModel record in resultFalse)
                            {
                                EquipmentAssignments_AdHoc.Add(record);
                            }
                        }
                        if (resultTrue !=null)
                           foreach (EquipmentAssignmentRecordModel record in resultTrue)
                            {
                                EquipmentAssignments_StandardIssue.Add(record);
                            }
                    }
                }
            }
        }

        public ObservableCollection<VehicleAssignmentRecordModel> VehicleAssignments { get; set; }
        public ObservableCollection<EquipmentAssignmentRecordModel> EquipmentAssignments_StandardIssue { get; private set; }
        public ObservableCollection<EquipmentAssignmentRecordModel> EquipmentAssignments_AdHoc { get; private set; }

And it works great. Still, since I haven't seen this technique used anywhere else, I'm guessing there is a "right" way to do it that I've not been able to find through Googling.

My first attempt was to use the setters of the three properties to set their own values, so for instance:

private ObservableCollection<EquipmentAssignmentRecordModel>_equipmentAssignments_StandardIssue; 
public ObservableCollection<EquipmentAssignmentRecordModel> EquipmentAssignments_StandardIssue
        {
            get { return _equipmentAssignments_StandardIssue); }
            set { _equipmentAssignments_StandardIssue == SelectedEmployee.EquipmentAssignments.Where(x => x.IsStandardIssue == true); }
        }

This did not work because even though the SelectedEmployee changed (and indeed it did change in the EquipmentAssignments_StandardIssue setter when I stepped through the code), it didn't notify the ObservableCollections of the change.

So, should I rewrite this code to follow some best practice?

\$\endgroup\$
1
  • \$\begingroup\$ Please tag the appropriate language. \$\endgroup\$
    – BCdotWEB
    May 13, 2021 at 5:58

1 Answer 1

1
\$\begingroup\$

Few syntax improvements first:

private EmployeeModel _selectedEmployee;
public EmployeeModel SelectedEmployee
{
    get => _selectedEmployee;
    set
    {
        if (Set(ref _selectedEmployee, value))
        {
             Messenger.Default.Send(new EmployeeToken(value)); // ensure that you don't block the UI Thread for a long time
             EquipmentAssignments_StandardIssue?.Clear();
             EquipmentAssignments_AdHoc?.Clear();
             if (SelectedEmployee?.EquipmentAssignments != null)
             {
                 foreach (EquipmentAssignmentRecordModel model in SelectedEmployee.EquipmentAssignments)
                 {
                     if (model.IsStandardIssue)
                         EquipmentAssignments_StandardIssue.Add(model);
                     else
                         EquipmentAssignments_AdHoc.Add(model);
                 }
             }
        }
    }
}

But better to use a couple of ICollectionView as views for SelectedEmployee.EquipmentAssignments. Basically you can create a CollectionView from ObservableCollection, assign a filtering predicate to it and expose it as public property. Then only one ObservableCollection will be in use instead of 3.

Fore example

public ICollectionView EquipmentAssignments_StandardIssue
{ 
    get
    {
         if (SelectedEmployee?.EquipmentAssignments == null)
             return null;
         var view = new CollectionViewSource { Source = SelectedEmployee.EquipmentAssignments }.View;
         view.Filter = item => item is EquipmentAssignmentRecordModel model && model.IsStandardIssue;
         return view; 
    } 
}

public ICollectionView EquipmentAssignments_AdHoc
{ 
    get
    {
         if (SelectedEmployee?.EquipmentAssignments == null)
             return null;
         var view = new CollectionViewSource { Source = SelectedEmployee.EquipmentAssignments }.View;
         view.Filter = item => item is EquipmentAssignmentRecordModel model && !model.IsStandardIssue;
         return view; 
    } 
}

Then the updating would look like this

public EmployeeModel SelectedEmployee
{
    get => _selectedEmployee;
    set
    {
        if (Set(ref _selectedEmployee, value))
        {
             Messenger.Default.Send(new EmployeeToken(value));
             OnPropertyChanged(nameof(EquipmentAssignments_StandardIssue));
             OnPropertyChanged(nameof(EquipmentAssignments_AdHoc));
        }
    }
}

The change doesn't affect XAML. Probably there's a better way to do that but I'm not enough strong in collection views. In particular I don't like twice creating CollectionViewSource from the same source in the above code. But the idea might be correct. The main profit of this approach is when you modifying the source collection, both filtered views being updated automatically.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Thanks so much for taking the time to help. \$\endgroup\$ May 14, 2021 at 13:53
  • \$\begingroup\$ I was following along till the end there, when you used OnPropertyChanged. I had written that method in my base vm class, but when I implemented MVVM Light, I discarded it, since MVVMLight uses Set(ref _field, value) instead. Could you help me out with your definition of OnPropertyChanged? Also, could you explain the purpose of nameof in this context? Thank you very much. \$\endgroup\$ May 14, 2021 at 17:40
  • \$\begingroup\$ @JoshuaWhite Mvvm light also has that method but with different name RaisePropertyChanged, you don't need Set there. nameof \$\endgroup\$
    – aepot
    May 14, 2021 at 17:58
  • \$\begingroup\$ @JoshuaWhite you don't need Set because there's nothing to set. Just fire PropertyChanged event causing UI to update data from Property getter. \$\endgroup\$
    – aepot
    May 14, 2021 at 18:06
  • 1
    \$\begingroup\$ That makes sense, and yes, RaisePropertyChanged worked just fine. Everything is working properly, and with much more readable code. Thank you. \$\endgroup\$ May 14, 2021 at 18:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.