canahari
canahari

Reputation: 522

WPF - how to add/delete items to databound ItemsControl when UpdateSourceTrigger=Explicit

I have a window which is basically a dialog box showing all the data of a contact. The user can edit the data and press "SAVE" to save the changes. UpdateSourceTrigger is explicit for all the data bindings, for the user to be able to cancel all their modifications.

Now, a Contact has some Addresses and I bound these Addresses to a ListBox's ItemsSource. Now I must be able to add/delete Addresses, but I would like to do it without modifying the underlying collection because I do not want any modifications to be done to my Contact object prior to the user's "SAVE" button click.

Is there a best practice for this?

Upvotes: 2

Views: 470

Answers (2)

Dean Kuga
Dean Kuga

Reputation: 12119

You should store the read-only copy of the persisted state of the object and allow user to modify any property participating in binding and editable in the UI of the object being edited in the UI. You can use the stored read-only persisted state copy of the object for comparing the object being modified in the UI to the persisted values, restoring the original values if necessary and establishing if the object is modified and "persistable"...

Here is how I do it:

public class SomeBusinessObject : INotifyPropertyChanged
{
    private int id;
    public int Id
    {
        get { return id; }
        set { id = value; OnPropertyChanged("Id"); }
    }
    private int property1;
    public int Property1
    {
        get { return property1; }
        set { property1 = value; OnPropertyChanged("Property1"); }
    }
    private string property2;
    public string Property2
    {
        get { return property2; }
        set { property2 = value; OnPropertyChanged("Property2"); }
    }
    //... Other properties

    public bool IsModified { get; set; }
    public bool IsPersistable { get; set; }
    public SomeBusinessObject PersistedState { get; private set; }

    public SomeBusinessObject(int id, int p1, string p2, savePersistedState = false)
    {
        Id = id;
        Property1 = p1;
        Property2 = p2;
        //Set other properties
        if (savePersistedState) PersistedState = new SomeBusinessObject(id, p1, p2)
    }
}

As you can see the object is not saving its persisted state by default allowing you to keep a persisted state copy of the object as just another property of the object only when required (e.g. when edited from within a UI).

This approach in combination with implementing the INotifyPropertyChanged interface allows you to subscribe to PropertyChanged event of the object and set the IsModified and IsPersistable flags based on BI rules and to restore the persisted state of the object very easily from the read-only (notice the private set; property setter) PersistedState copy created when the object was first instantiated.

It also allows you to very easily implement the CanExecuteChanged events of the WPF commands. For example the SaveCommand of the Save button on your form could just check the IsPersistable flag of the object to establish if the object is "persistable" and if the button should be enabled or not (obviously you'd change the flag when handling the PropertyChanged event based on some business logic and comparing it to the persisted state object...

Upvotes: 2

McGarnagle
McGarnagle

Reputation: 102753

If I understand, you have set up a mechanism, using UpdateSourceTrigger=Explicit, where UI changes are postponed.

But this mechanism is not going to work for a collection that can be added to/removed from, because now you're dealing with a reference type. That means its value will be shared between the binding source and target, so to change one is, by definition, to change the other. So one way or another, you're going to have to create a separate copy of the collection for the UI.

I would suggest considering a different approach altogether than explicit source updates -- this seems like a dicey approach in more ways than one (for example, you can't do any per-property validations if the source model doesn't get updated immediately).

For example, maybe you could maintain two separate objects, and use a "Copy" method on the class that copies property values (except for the identity properties) from one to the other.

Upvotes: 1

Related Questions