Overview
I am using CompositeWPF to create an app using C#. This really should make a difference to the answer as my problem would exist outside of Prism.
I have an ItemsControl which is bound to an ObservableCollection containing my ViewModels. This is working fine. In my DataTemplate I have my required controls bound in XAML. One of these controls is a button called "Configure." When clicked the button issues a DelegateCommand which passes the ViewModel as a parameter.
The DelegateCommand opens a modal dialog showing the VM looks as follows.
private void ShowDialog(object obj)
{
ComPortPropertiesPresenter presenter = _container.Resolve<ComPortPropertiesPresenter>();
ComPortViewModel vm = obj as ComPortViewModel;
presenter.ComPort = vm.Clone() as ComPortViewModel;
DialogOptions options = new DialogOptions();
options.DialogTitle = presenter.View.DisplayName;
options.HideOkCancelButtons = true;
bool? result = DialogWorkspace.ShowView(presenter.View, options, () =>
{
return true;
});
if (result == true)
{
// TODO: There must be a better way of doing this. The problem is if you bind the object the
// automated bindings cause a realtime update. If you clone the object and then set it to become obj then
// the bindings do not update. Need to investigate how an observablecollection triggers an update.
int position = ComPorts.IndexOf(obj as ComPortViewModel);
ComPorts.Remove(obj as ComPortViewModel);
ComPorts.Insert(position, presenter.ComPort);
}
My original code passed the obj to the presenter without a clone. The problem with that was that the value was being changed in real time. If you made a change and then hit cancel the dialog would be closed although because of the bindings the changes would have already happened.
I decided to clone the vm and pass that to the view. If the dialog result was then true I tried copying the cloned vm over the original. EG: obj = presenter.ComPort;
This didn't then update the values on the original view which contained the button.
I then tried things like... obj.BaudRate = presenter.ComPort.BaudRate which worked although my fear is it is long winded and if the vm was ever extended things could get missed.
My final solution was to remove the original vm and add the new one in the location of the original. This works 100% although I feel it is somewhat clumsy. Am I being overly critical or is there a better way?
My guess is that the ObservableCollection fires an INotify event when something is added/removed. The same in my vm when a property is updated it works because I raise an event.
So could the problem be that if you overwrite something in an ObservableCollection no event is raised?
There must be some clever cloggs out there who knows.