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?