WPF – Editing Mode with Save and Cancel Capability – Serialization

August 9, 2010

tags: ,
one comment

In continuation of the previous posts –
WPF – Editing Mode with Save and Cancel Capability

WPF – Editing Mode with Save and Cancel Capability – Dynamic ViewModelProxy

In this post I will demonstrate an elegant and simple solution that you can use regarding the second option presented in the first post series (cloning via serialization).

The Use-Case

Often, in more advanced scenarios, you need to duplicate your object for a different view. (read the first post for more detail)

A commonly used technique is using serialization to clone the object. Unfortunately, in many times, our view models aren’t cloneable easily in their nature by using serialization, especially when we use PRISM within our view models. When using PRISM, your view models may contain references to all sorts of CAL services for example, which are usually non-serializable.

The common approach for dealing with this is using serialization events. You can set the fields not be serialized (or simply set them to null before serializing) and set their values after deserialization is complete.
You need to design your object to fit such cloning technique. For example, where would you register/instantiate your commands? constructor alone is no good due to the fact the we need to support duplication via serialization.

What I have to offer is..

  1. ViewModelBase – My ViewModelBase provides a method that you can override – InitializeCore(bool deserializing)
    1. This method occurs only once!
      1. If the object is being instantiated normally – part of the constructor
      2. If the object is being serialized – after deserialization completes
    2. This method provides easy access for implementing things needed either in cases of instantiation or serialization

One more thing..

I mentioned this above – in PRISM (and other cases), your view models are usually not easy to duplicate, look at the following example –

Note: The code here and in my samples are using the BinaryFormatter.

Code Snippet
public class MyViewModel : ViewModelBase
{
    IEventAggregator _eventAggregator;
    IUnityContainer _container;

    public MyViewModel(IUnityContainer container)
    {
        _container = container;
        _eventAggregator = _container.Resolve<IEventAggregator>();

        //Use the event aggregator to subscribe to events..
    }
}

Currently, MyViewModel is not serialiable.
In order to make it serializable, I need to decorate my class with the Serializable attribute, but that is not enough.
The serialization will fail because the fields _eventAggregator and _container are not serializable too.

In order to make the serialization work, here is what I need to do –

Code Snippet
[Serializable]
public class MyViewModel : ViewModelBase
{
    [NonSerialized]
    IEventAggregator _eventAggregator;

    [NonSerialized]
    IUnityContainer _container;

    public MyViewModel(IUnityContainer container)
    {
        _container = container;
        _eventAggregator = _container.Resolve<IEventAggregator>();

        //Use the event aggregator to subscribe to events..
    }
}

2 things have been made – 1) I set my class to be serializable 2) Marked the fields to not participate in the serialization process.

Is that all? Well, no.
The serialization and deserialization back will work fine and I will have a duplicate object. However, the state of the duplicate object would be incomplete – the _eventAggregator and _container would be nulls and no processing had been done.

Now what? well, in order to make all things work properly, I would have to encapsulate the duplication in one method (be that in my view model or somewhere else) to do the following –
Serialize the view model, call an exposed method to complete operation, return the duplicate.

For example –

Code Snippet
[Serializable]
public class MyViewModel : ViewModelBase
{
    [NonSerialized]
    IEventAggregator _eventAggregator;

    [NonSerialized]
    IUnityContainer _container;

    public MyViewModel(IUnityContainer container)
    {
        LoadState(container);
    }

    public void LoadState(IUnityContainer container)
    {
        _container = container;
        _eventAggregator = _container.Resolve<IEventAggregator>();

        //Use the event aggregator to subscribe to events..
    }

    public MyViewModel Duplicate()
    {
        MyViewModel other = Helpers.CloneBySerializing(this);

        other.LoadState(_container);

        return other;
    }
}

This is quite fine and gives us a neat solution.
My goal was to make such cases simpler though, since it is quite common in PRISM-based business applications.

Here is the solution

I built a nice wrapping on top of the binary serialization that you can use for such cases. (you can switch the actual serialization provider as you may need)
You can instruct it to serialize fields by ref.

Furthermore, it supports the entire object graph. If your view model contains other view models which have such decorated fields, it will process them as well.

This means, that upon serialization, it will set null to these fields and set their value back both in the duplicate and the original object.
So, using that, my view model looks as follows – (note the use of the InitializeCore I mentioned in the beginning of the post)

Code Snippet
[Serializable]
public class MyViewModel : ViewModelBase
{
    [NonSerialized, SerializeByRef]
    IEventAggregator _eventAggregator;

    [NonSerialized, SerializeByRef]
    IUnityContainer _container;

    public MyViewModel(IUnityContainer container)
    {
        _container = container;
        _eventAggregator = _container.Resolve<IEventAggregator>();

        //need to call it once more because in the base ctor the fields are null
        InitializeCore(false);
    }

    protected override void InitializeCore(bool deserializing)
    {
        if (_eventAggregator != null)
        {
            //Use the event aggregator to subscribe to events..
        }
    }
}

As you can see, I no longer need to worry about state preserving. I simply tag the fields I need to be set as references and do what I need in the InitializeCore implementation which occurs at the constructor or after deserialization when the fields already have their by-ref values.

While in such a simple case it is hard to see the benefit, when it comes to more complicated classes with deeper object graphs, it becomes much easier using this approach.

So.. how do you get the actual duplicate?
You need to call my wrapper in order to generate the duplicate. the internal implementation uses the BinaryFormatter but you can change that to NetDataContractSerializer/DataContractSerializer/XmlSerializer if you need.

Code Snippet
MyViewModel other = ObjectProducer.CloneByBinarySerialize(myViewModel);

Important Note – this serialization technique goes through the entire object graph, so it is advisable to use that in scenarios where you need to serialize a single object at a certain given time. (in this example, when the user edits an employee, the performance hit isn’t an issue for the benefit of using that)

You can download the source here – Zuker.WpfSamples.zip. (Edit State Preserve – EditWithCloneSerialize)
The sample shows a case of a really simple view model, but you can go ahead and try it with the example shown here, with the use of ‘SerializeByRef’.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

one comment

  1. justinfloydMarch 20, 2013 ב 11:03

    Federal Contracts Awarded to Companies in Hawaii (March 19)Targeted News Serviceby DONABEL HARMSTargeted News ServiceWASHINGTON, March 19 — The following federal contracts were announced by federal agencies as having been awarded to companies operating in Hawaii.***MILITARY $47.26 Million Federal Contract Awarded to LMS ChemicalWASHINGTON, March 19 — LMS Chemical Ltd., Honolulu, won a $47,257,587.58 federal contract from the U.S. Army Medical Command, Honolulu, for hospital housekeeping services at Tripler Army Medical Center. Place of performance will be in Island of Oahu, Hawaii.Contact: Linda Naeko Oshiro, 808/433-7434. MIL5FCA5. ClassS;***MILITARY $2,807 Federal Contract Awarded to Hawaiian TelecomWASHINGTON, March 19 — Hawaiian Telecom Inc., Honolulu, won a $2,807.03 federal contract from the Defense Information Systems Agency’s Procurement Directorate, Pearl Harbor, Hawaii, for telecommunications services.Contacts: David Ogawa, 808/472-0286; or Darlene Arakaki, 808/472-0565. MIL5FCA5. ClassD;***MILITARY $2,807 Federal Contract Awarded to Hawaiian TelecomWASHINGTON, March 19 — Hawaiian Telecom Inc., Honolulu, won a $2,807.03 federal contract from the Defense Information Systems Agency’s Procurement Directorate, Pearl Harbor, Hawaii, for telecommunications services.Contacts: David Ogawa, 808/472-0286; or Darlene Arakaki, 808/472-0565. MIL5FCA5. ClassD;***MILITARY $2,807 Federal Contract Awarded to Hawaiian TelecomWASHINGTON, March 19 — Hawaiian Telecom Inc., Honolulu, won a $2,807.03 federal contract from the Defense Information Systems Agency’s Procurement Directorate, Pearl Harbor, Hawaii, for telecommunications services.Contacts: David Ogawa, 808/472-0286; or Darlene Arakaki, 808/472-0565. MIL5FCA5. ClassD;***MILITARY $2,807 Federal Contract Awarded to Hawaiian TelecomWASHINGTON, March 19 — Hawaiian Telecom Inc., Honolulu, won a $2,807.03 federal contract from the Defense Information Systems Agency’s Procurement Directorate, Pearl Harbor, Hawaii, for telecommunications services.Contacts: David Ogawa, 808/472-0286; or Darlene Arakaki, 808/472-0565. MIL5FCA5. ClassD;***MILITARY $2,807 Federal Contract Awarded to Hawaiian TelecomWASHINGTON, March 19 — Hawaiian Telecom Inc., Honolulu, won a $2,807.03 federal contract from the Defense Information Systems Agency’s Procurement Directorate, Pearl Harbor, Hawaii, for telecommunications services.Contacts: David Ogawa, 808/472-0286; or Darlene Arakaki, 808/472-0565. MIL5FCA5. ClassD;For more information about Targeted News Service, including its daily federal contract report NewsFocus Newsletters, contact: Myron Struck, Editor, Targeted News Service, Springfield, Va. 703/866-4708, Cell: 703/304-1897, myron@targetednews.com.-1118355

    Reply