I’m creating a simple database application in C# WPF using MVVM as Relay Commands and databinding. For in-memory storage of database content I use ObservableCollection, which is binded to the Datagrid as follows:
<DataGrid ItemsSource="{Binding Path=Softwares, Mode=OneWay}" SelectedItem="{Binding Path=SoftwareSelection, Mode=TwoWay}">
when the item is selected user can chose to edit it. For editation a form is opened with a bunch of textboxes with the data of given entity. All the fields are validated using IDataErrorInfo, unless all textboxes are valid, the ok button is not enabled, and therefore no changes can be saved to the collection and to the database.
Here is how the example textbox looks like:
<TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
But the tricky part is, in case I change some values in textboxes and then close the window, the new values are propagated to the ObservableCollection, which I don’t want to. Do you have any idea, how to prevent such behaviour? I would like the databinding work only after clicking the button. Otherwise the databindng works well, so as the button (dis/en)abling and reflecting changes to the database and to the collection after clicking. Both views are serviced by different ViewModels, data between views are passed by firing events.
I tried to add to the DataGrid UpdateSourceTrigger=Explicit to the ItemsSource binding, but didn’t help. Perhaps, I’m missing some application logic?
Thank you very much for your help.
This is where most WPF developers make mistakes of assumptions!
In MVVM dirty data can be stored in the
ViewModeland that’s what the layer of VM is for! It mimics theViewfromModel‘s perspective and becauseViewis in error, theViewModelwould also be in the error. Thats perfectly valid.So having said that, the question remains
Two ways…
If your
ObservableCollectionis specific to your model class (sayMyItem) then if your Model class (MyItem) is an Entity class \ DAL class \ NHibernate class create a wrapper ofMyItemclass calledViewModelMyItemand then instead ofObservableCollection<MyItem>useObservableCollection<ViewModelMyItem>.This way dirty data from your
Viewwould be insideViewModelMyItemand it can only be legitimately flown back to your model class (MyItem) ONLY whenSavebutton is clicked. So that means inSave Command‘sExecute()delegate you can copy \ clone theViewModelMyItem‘s properties intoItem‘s properties, if validations inViewModelMyItemare fine.So if
Itemis anEntityTypeclass /NHibernateclass /WCFclient model class, it would always only valid data asViewModelMyItemis filtering the temporary / dirty information upfront.You could use
Explicitbinding model. It stops theTwoWaydata to flow back to the sorceItemunlessBindingExpressions.UpdateSource()is explicitly called.But according to me, this defeats MVVM in straightforward way because
ViewModelwill not have what UI is showing! Still however you can use *Attached Behavior * to govern explicit binding by staying in MVVM space!Let me know if this helps!