-1

I am implementing Undo/Redo for my .NET 5 application. I have an ObservableCollection of Activity objects (the collection is named Activities). Each Activity object contains two ObservableCollections "ActionItems" and "Notes". The Activities collection is displayed using a ListBox, and the ActionItems and Notes collections are displayed using two respective ItemsControls/ScrollViewers. The Activities ListBox is IsSynchronizedWithCurrentItem, which keeps the ItemsControls in synch.

After each change to an object anywhere in my application, I store a clone on the Undo/Redo stack. When it's time to unto an action on the higher level objects, e.g. an Activity, I replace the Activity object in the ObservableCollection directly:

Activities[0] = activityCloneFromUndoStack;

After this replacement, the UI updates and everything is just fine. However, when I subsequently add a new ActionItem or Note to their respective ObservableCollections on this particular Activity instance, their ItemsControls on the UI do not update. The items are successfully added to the model, but the ItemsControl UI is not reflecting the change.

I have tried refreshing the Items collection:

ItemsControlActivitiesActionItems.Items.Refresh();

But that has no effect. Any other ideas or advice would be appreciated.

UPDATE:

I can see that the Activity object that the new Note/ActionItem is being added to successfully is the Activity object PRIOR to the Undo operation. So even though the parent Activites ListBox control contains the latest Activity object and its synched properties are displaying correctly in the UI, the Notes and ActionItems ItemsControls are still pointing to the original Activity object before the Undo operation. So now the question is

"How do I force the 'child' ItemsControls to recognize the newly replaced object in the 'parent' (IsSynchronizedWithCurrentItem) ListBox control?"

1 Answers1

0

So I was finally able to trace the problem back to the way I was cloning the objects. I was using the .MemberwiseClone method to make a shallow copy, and then turn that into a deep copy by manually copying all of the reference types. But somehow the WPF engine seemed to be holding onto a reference to the last object before the undo operation.

So I change my method of cloning to use a constructor that accepts the object to be copied as an argument. This is one of the other approaches suggested in the documentation:

There are numerous ways to implement a deep copy operation if the shallow copy operation performed by the MemberwiseClone method does not meet your needs. These include the following:

Call a class constructor of the object to be copied to create a second object with property values taken from the first object. This assumes that the values of an object are entirely defined by its class constructor.

Call the MemberwiseClone method to create a shallow copy of an object, and then assign new objects whose values are the same as the original object to any properties or fields whose values are reference types. The DeepCopy method in the example illustrates this approach.

Serialize the object to be deep copied, and then restore the serialized data to a different object variable.

Use reflection with recursion to perform the deep copy operation.