1

I'm working on a small WPF application and I'm having some troubles properly keeping my models and viewmodels in sync. Basically, the models implement self-contained business logic, updating the collections they hold as needed and I need some way or method to propagate these changes to the viewmodels.

After reading some similar questions like this one I managed to implement a simple pattern that manages to do the job, but it seems rather inefficient in terms of maintainability and feels more like a workaround than actual solution.

Below a simplified example for the classes I have so far:

A basic sample class containing data and some simple logic

public class FileHash
{
    public long Length { get; set; }
    public string Name { get; set; }
    public DateTime CreationTime { get; set; }
    public string Checksum { get; set; }
}

A class holding several types of collections and business logic to manage these classes

public class FileIndex : INotifyPropertyChanged
{
    public Dictionary<string, FileHash> Hashes { get; private set; } // Hashes is 

    public void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public UpdateFiles()
    {
        // Perform some logic to add/remove elements to the Hashes collections
        // or modify some of its elements 
        NotifyPropertyChanged("Hashes");
    }
}

The viewmodel representing the FileIndex model containing application logic to communicate between model and view

class FileIndexViewModel : ViewModelBase.ViewModelBase
{       
    private FileIndex index;

    private ObservableCollection<FileHashViewModel> hashes;
    public ObservableCollection<FileHashViewModel> Hashes;
    {
        get { return hashes; }
        set
        {
            if (value != hashes)
            {
                hashes = value;
                OnPropertyChanged("");
            }
        }
    }

    public FileIndexViewModel(FileIndex index)
    {
        this.BackupSets = new ObservableCollection<FileHashViewModel>();
        UpdateBackupSets();

        index.PropertyChanged += new PropertyChangedEventHandler(Index_PropertyChanged);
    }


    private void Index_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(e.PropertyName == "Hashes")
        {
            UpdateHashCollection();
        }
    }

    public UpdateHashCollection()
    {
        // Iterate through the Hashes collection of the current viewmodel
        // and its related FileIndex instance to update the local observable collection
    }

    public UpdateFiles()
    {
        // This would be called from the view, initiating an update in the model
        index.UpdateFiles();
    }
}

I basically implemented INotifyPropertyChanged in the model, subscribe to the events in the viewmodel and update the collections accordingly.

The issue I'm having with this is that I need to enumerate every item in both collectios after every change. Considering that some of the model classes have nested collections, this cascades down to quite a number of loops. This becomes most apparent running an update operation on the whole collection that takes between 0.5 to 3 seconds on each element. I want to present a live status of each element in the UI, which means that I have to potentially check several thousand elements every few seconds to find out which element was changed.

Since the viewmodels implement some additional modifications to display data correctly, I also can't just directly pass through the collections of the model classes (at least not for all classes).

Additionally, with this I need to manually fire the correct event every time I modify the model. Currently, this is not much of an issue since I only have a couple of methods that modify the elements, but it's not ideal in terms of scalability and prone to errors.

Does anybody know how I could improve this pattern?

Il Vic
  • 5,576
  • 4
  • 26
  • 37
mmuffins
  • 33
  • 6
  • why you need collection of viewmodels ? – Eldho Jan 28 '18 at 15:10
  • Some of the classes, which I left out in the description for the sake of simplicity, contain sub-collections which I want to display in the view, so I'm wrapping these collections in observable collections to notify of changes to the object.And in some cases the model has properties which I want to expose in the model but not necessarily in the view, and a wrapper is a simple way to control what data I pass through. That said, I'm not doing this for every single class, only the ones where the conditions above apply. – mmuffins Jan 28 '18 at 15:43
  • 1
    are you aware of https://github.com/ismell/Continuous-LINQ? unless i missunderstood you, that library might be quite useful – Milan Jan 28 '18 at 20:19
  • That looks useful, I'm going to have a look at that! – mmuffins Jan 28 '18 at 20:50

0 Answers0