All posts in Silverlight

In A different take on Deep Copy I talked a bit about the different approaches to how you can accomplish performing a Deep Copy of a model in C#. In this article I want to revisit the topic briefly and demonstrate two methods to handle this concern.

Q: Why not use Object.MemberwiseClone?
A: You can, but it only performs a shallow copy of your model. If you have a more complex model, you will need something that can dig deeper and map all your properties.

The first approach is our Deep Copy method done with serialization. If you have been around the Internet a bit, you will recognize it:


/// <summary>
/// Performs a Deep Copy of an object through serialization.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="oSource">The o source.</param>
/// <returns></returns>
public static T DeepCopy<T>(this T oSource)
{
    using (var ms = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(ms, oSource);
        ms.Position = 0;
        return (T)formatter.Deserialize(ms);
    }
}

This is the cleanest way to copy a model.

1) A MemoryStream is created.
2) A BinaryFormatter serializes the source into the MemoryStream.
3) The MemoryStream position is reset for reading purposes.
4) A deserialized object is cast to type T and returned.

A simple example:


var myNewObject = myObject.DeepCopy();

 
This works great in many cases but not in a Framework like Silverlight. Given, not a lot of us use that anymore, but you could still run into a scenario where serialization is not possible. In that case, we are going to create a new instance of the model we intend to copy. Then, we will map properties between the 2 models.


/// <summary>
/// Copies all public properties from one class to another.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
/// <exception cref="System.Exception">Source and destination cannot be null and must be 
/// of the same type!</exception>
public static void MapProperties<T>(this T source, T destination) where T : class
{
    // Source and destination must exist.
    if ((source == null || destination == null)) return;

    // Get properties
    var propertyInfos = source.GetType().GetProperties();
    if (!propertyInfos.Any()) return;

    // Process only public properties
    foreach (var propInfo in propertyInfos.Where(x => x.CanWrite))
    {
        // Get value from source and assign to destination.
        var value = propInfo.GetValue(source, null);
        if (value == null) continue;

        // Evaluate
        var valType = value.GetType();

        // Collections
        if (valType.InheritsFrom<ICollection>())
        {
            var sourceCollection = value as IList;
            if (sourceCollection == null) continue;

            // Create new instance of collection
            IList destinationCollection = null;
            destinationCollection = (valType.BaseType == typeof(Array))
                ? Array.CreateInstance(valType.GetElementType(), sourceCollection.Count)
                : (IList)Activator.CreateInstance(valType, null);
            if (destinationCollection == null) continue;

            // Map properties
            foreach (var item in sourceCollection)
            {
                // New item instance
                var newItem = HasDefaultConstructor(item.GetType()) 
                    ? Activator.CreateInstance(item.GetType(), null) 
                    : item;

                // Map properties
                item.MapProperties(newItem);

                // Add to destination collection
                if (valType.BaseType == typeof(Array))
                {
                    destinationCollection[sourceCollection.IndexOf(item)] = newItem;
                }
                else
                {
                    destinationCollection.Add(newItem);
                }
            }

            // Add new collection to destination
            propInfo.SetValue(destination, destinationCollection, null);
        }
        else
        {
            propInfo.SetValue(destination, value, null);
        }

        // Check for properties and propagate if they exist.
        var newPropInfos = value.GetType().GetProperties();
        if (!newPropInfos.Any()) continue;

        // Copy properties for each child where necessary.
        var childSource = source.GetType().GetProperty(propInfo.Name);
        var childDestination = destination.GetType().GetProperty(propInfo.Name);
        childSource.MapProperties(childDestination);
    }
}

/// <summary>
/// Determines whether the type has a default contructor.
/// </summary>
/// <param name="type">The type.</param>
/// <returns></returns>
private static bool HasDefaultConstructor(Type type)
{
    return
        type.GetConstructor(Type.EmptyTypes) != null ||
        type.GetConstructors(BindingFlags.Instance | BindingFlags.Public)
            .Any(x => x.GetParameters().All(p => p.IsOptional));
}

Here is what is going on:

1) We get the properties associated with the class type.
2) We evaluate the public properties.
3) Using reflection, we retrieve the value from the source and apply it to the destination.
4) If the value is not null, we drill down further for more public properties recursively.
Note: Collections need a bit of extra work to ensure we don’t simply copy over their object instances.
5) Repeat until the entire model has been traversed.

A simple example:


SomeType myNewObject = new SomeType();

// Assumption: "myObject" is of type "SomeType"
myObject.MapProperties(myNewObject);

In conclusion: if you can’t serialize, map the properties between the 2 models.

That’s all for now.

In Effective Extensions – Extending Types in C# we covered how to use a few useful methods to extend Types in C#. This time we are going to look at extending enums in C#.

Q: So, why extend enums?
A: Because they are typically inflexible and require some funky casting to get what you need from simple data types such as strings and integers.

Here is our example enum:


/// <summary>
/// Thread-state type.
/// </summary>
public enum ThreadStateType
{
    [Description("Initialized")]
    Started = 0,

    [Description("Ready")]
    Waiting = 1,

    [Description("Running")]
    Processor = 2,

    [Description("Standby")]
    PreProcessor = 3,

    [Description("Terminated")]
    Ended = 4,

    [Description("Wait")]
    NotReady = 5,

    [Description("Transition")]
    WaitingForResource = 6,

    [Description("Unknown")]
    UndeterminedState = 7
}

 

You will notice that each value in the enum has a Description attribute. This can be extremely effective in allowing us to get a more meaningful value or message from an enum without having to do complex conversions. Let’s look at those.

 
ToDescription

Q: So, how do we get those descriptions?
A: With a “ToDescription” extension like the one below:


/// <summary>
/// Return the description tied to an enum.
/// </summary>
/// <param name="en">The en.</param>
/// <returns></returns>
public static string ToDescription(this Enum en)
{
    // ext method
    var type = en.GetType();
    var memberInfo = type.GetMember(en.ToString());

    // No members
    if (memberInfo.Length <= 0) return en.ToString();

    // Get attributes
    var attributes =
        memberInfo.First().GetCustomAttributes(typeof(DescriptionAttribute), false);

    // Assess attributes
    return attributes.Length > 0 
        ? ((DescriptionAttribute)attributes.First()).Description : en.ToString();
}

 
It’s not pretty, but extremely useful. It can be used like this:


// Get enum
ThreadStateType myType = ThreadStateType.Processor;

// Get description from enum
Console.Write(myType.ToDescription());

// Prints: Running

 
GetEnumFromDescription

Q: Okay, so what if I only have the enum description and want the enum value back?
A: We can do that too:


/// <summary>
/// Process a string and return an Enum value that has that description.
/// </summary>
/// <param name="value">string representing the enum's description</param>
/// <typeparam name="T">The type of Enum</typeparam>
/// <returns>Enum value corresponding to the string description</returns>
/// <exception cref="ArgumentException">T must be an enumerated type</exception>
public static T GetEnumFromDescription<T>(string value) where T : struct, IConvertible
{
	// Must be an enum
	if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");

	// Evaluate
	foreach (var val in Enum.GetValues(typeof(T)))
	{
		if (((Enum)val).ToDescription() != value) continue;
		if (val != null) return ((T)val);
	}

	// Return
	return default(T);
}

 
And that can be used like this:


// Use GetEnumFromDescription to get an enum from a string representing its description.
ThreadStateType myType = EnumExtensions.GetEnumFromDescription<ThreadStateType>("Running");

// Returns: ThreadStateType.Processor

 
ToEnum

Q: And what if I have a string representing the name of the enum and want it’s value?
A: This isn’t typical unless you did a ToString() to the enum, but we can convert that back too:


/// <summary>
/// Process a string and return an Enum value for it
/// </summary>
/// <param name="str">string representing the enum</param>
/// <typeparam name="T">The type of Enum</typeparam>
/// <returns>Enum value corresponding to the string value</returns>
/// <exception cref="ArgumentException">T must be an enumerated type</exception>
public static T ToEnum<T>(this String str) where T : struct, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T must be an enumerated type");

    foreach (var value in Enum.GetValues(typeof(T)))
    {
        if (value.ToString() == str) return (T)value;
    }

    return default(T);
}

 
An example of this would be:


// Get the "Processor" enum from the string "Processor"
ThreadStateType myType = ("Processor").ToEnum<ThreadStateType>();

// Returns: ThreadStateType.Processor

 

And that’s really all there is to it. These are simple extensions for otherwise complex derivations but it should help you get over your fear of using enums in C#.

Until next time…

Welcome to Part 2 of our series Making a Better ObservableCollection. If you missed Making a Better ObservableCollection Part 1 – Extensions you can get to it here.

In this next section I am going to share a version of my ObservableCollectionEx that allows cross-threading. The idea here is to have an ObservableCollection which you can update from an Async thread so as not to impact the owning thread. This is especially useful in WPF when you don’t wish to block the UI thread while performing collection updates.

Let’s see the code:


/// <summary>
/// Initializes a new instance of the 
/// <see cref="ObservableCollectionEx{T}"/> class.
/// </summary> 
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
    #region Constructors

    /// <summary>
    /// Initializes a new instance of the
    /// <see cref="ObservableCollectionEx{T}" /> class.
    /// </summary>
    public ObservableCollectionEx()
    {
    }

    ///
    /// Initializes a new instance of the
    ///  class.
    ///
    ///The collection.
    public ObservableCollectionEx(IEnumerable<T> collection) : this()
    {
        this.AddRange(collection);
    }

    #endregion

    #region Events

    /// <summary>
    /// Source: New Things I Learned
    /// Title: Have worker thread update ObservableCollection that is bound to a ListCollectionView
    /// http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx
    /// Note: Improved for clarity and the following of proper coding standards.
    /// </summary>
    /// <param name="e"></param>
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        // Use BlockReentrancy
        using (BlockReentrancy())
        {
            var eventHandler = CollectionChanged;
            if (eventHandler == null) return;

            // Only proceed if handler exists.
            Delegate[] delegates = eventHandler.GetInvocationList();

            // Walk through invocation list.
            foreach (var @delegate in delegates)
            {
                var handler = (NotifyCollectionChangedEventHandler)@delegate;
                var currentDispatcher = handler.Target as DispatcherObject;

                // If the subscriber is a DispatcherObject and different thread.
                if ((currentDispatcher != null) &amp;&amp; (!currentDispatcher.CheckAccess()))
                {
                    // Invoke handler in the target dispatcher's thread.
                    currentDispatcher.Dispatcher.Invoke(
                        DispatcherPriority.DataBind, handler, this, e);
                }

                else
                {
                    // Execute as-is
                    handler(this, e);
                }
            }
        }
    }

    /// <summary>
    /// Overridden NotifyCollectionChangedEventHandler event.
    /// </summary>
    public override event NotifyCollectionChangedEventHandler CollectionChanged;

    #endregion
}

The constructors are pretty straight forward. We want to have an empty constructor and one that allows an immediate “AddRange” of an IEnumerable just like List and ObservableCollection allow, but that is not really the point of this post.

The main feature here is a slightly reformatted version of a wonderful post from a blog called New Things I Learned which covers cross-thread access with an ObservableCollection.

So, what does this code do?

  1. First we use BlockReentracy to prevent changes to the collection while we are evaluating it.
  2. Next, we get the Invocation List from the CollectionChanged event handler. This is the list of delegates subscribing to the event.
  3. Evaluate each delegate by retrieving it’s Target and casting it to a DispatcherObject.
  4. Make sure the DispatcherObject is valid and that the current thread has access.
  5. Invoke the delegate in the DispatcherObject’s thread.

It’s not the simplest code to follow when you aren’t overly familiar with working with event delegates but it gets the job done quite well.

Next time, we will talk about using a custom SortComparer to improve DataGrid performance.

Until next time.

One of the bigger annoyances dealing with programming in Silverlight is the deployment of XAP files. In order to properly update a XAP file you typically:

  1. Rename XAP file to a ZIP file.
  2. Extract the ServiceReferences.ClientConfig file.
  3. Update the configuration file with the proper IP information.
  4. Update the ZIP file and save.
  5. Rename ZIP file back to XAP.

Doesn’t that sound stupid? I think so. What the hell was Microsoft thinking?

Q: So, how do we do that with code so we can skip this frustration?
A: Let’s first look at a few factors:

  • We are using the .Net 4.0 Framework.
  • Don’t bother using System.IO.Packaging.ZipPackage. It thinks XAP files are always corrupt. It’s annoying.
  • We are just updating the IP information.

To solve the ZIP file library issue, I turned to DotNetZip: http://dotnetzip.codeplex.com/. It’s by far one of the most convenient libraries out there and it’s free.

First, let’s look at how we update the configuration file if it was committed to a MemoryStream. In this snippet we:

  1. Grab all the contents from the MemoryStream.
  2. Replace the IP information in the content.
  3. Clear the MemoryStream.
  4. Overwrite the stream contents with the new content.
  5. Reset the position in the stream to 0.

/// <summary>
/// Updates the configuration file.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="replacementIp">The replacement ip.</param>
/// <param name="destinationIp">The destination ip.</param>
/// <returns></returns>
private bool UpdateConfigurationFile(MemoryStream stream,
    string replacementIp, string destinationIp)
{
    bool isSuccessful = false;

    try
    {
        // Read current file
        var reader = new StreamReader(stream);
        stream.Position = 0;
        var contents = reader.ReadToEnd();
                
        // Update IP information
        var newContents = contents.Replace(replacementIp, destinationIp);

        // Reset contents of stream
        stream.SetLength(0);

        // Overwrite original configuration file
        var writer = new StreamWriter(stream);
        writer.Write(newContents);
        writer.Flush();

        // Set position in stream to 0.
        // This allows us to start writing from the beginning of the stream.
        stream.Seek(0, SeekOrigin.Begin);

        // Success
        isSuccessful = true;
    }
    catch (Exception)
    {
    }

    // return
    return isSuccessful;
}

Our main method below does this:

  1. Extract the ServiceReferences.ClientConfig file.
  2. Call the UpdateConfigurationFile method above to revise the IP information.
  3. Update the ZIP file and commit the changes.

/// <summary>
/// Updates the silverlight configuration file.
/// </summary>
/// <param name="configFileName">Name of the config file.</param>
/// <param name="xapFilePath">The xap file path.</param>
/// <param name="replacementIp">The replacement ip.</param>
/// <param name="destinationIp">The destination ip.</param>
/// <returns></returns>
private bool UpdateSilverlightConfigurationFile(string configFileName,
    string xapFilePath, string replacementIp, string destinationIp)
{
    // Check file path
    if (!File.Exists(xapFilePath)) { return false; }

    // Open XAP and modify configuration
    using (var zip = ZipFile.Read(xapFilePath))
    {
        // Get config file
        var entry = zip[configFileName];
        var stream = new MemoryStream();
        entry.Extract(stream);

        // Manipulate configuration
        var updated =
            UpdateConfigurationFile(stream, replacementIp, destinationIp);

        // Evaluate
        if (updated)
        {
            // Replace existing configuration file in XAP
            zip.UpdateEntry(configFileName, stream);
            zip.Save();
        }
    }

    // return
    return true;
}

So, let’s look at the code in it’s entirety so that we get an implementation example as well as the needed includes:


using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Ionic.Zip;

namespace XAPFileUpdaterTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            // Intialize UI
            InitializeComponent();

            // Parameters
            string configFile = "ServiceReferences.ClientConfig";
            string xap = @"MyAwesomeApp.xap";
            string replacementIp = "127.0.0.1";
            string destinationIp = "12.23.45.67";

            // Check
            var isClientConfigUpdated =
                UpdateSilverlightConfigurationFile(
                   configFile, xap, replacementIp, destinationIp);

            // Setup message
            var message =
                (isClientConfigUpdated) ? "was successful" : "failed";

            // Notify user
            MessageBox.Show("The current update " + message);
        }

        /// <summary>
        /// Updates the configuration file.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="replacementIp">The replacement ip.</param>
        /// <param name="destinationIp">The destination ip.</param>
        /// <returns></returns>
        private bool UpdateConfigurationFile(MemoryStream stream,
            string replacementIp, string destinationIp)
        {
            bool isSuccessful = false;

            try
            {
                // Read current file
                var reader = new StreamReader(stream);
                stream.Position = 0;
                var contents = reader.ReadToEnd();

                // Update IP information
                var newContents = contents.Replace(replacementIp, destinationIp);

                // Reset contents of stream
                stream.SetLength(0);

                // Overwrite original configuration file
                var writer = new StreamWriter(stream);
                writer.Write(newContents);
                writer.Flush();

                // Set position in stream to 0.
                // This allows us to start writing from the beginning of the stream.
                stream.Seek(0, SeekOrigin.Begin);

                // Success
                isSuccessful = true;
            }
            catch (Exception)
            {
            }

            // return
            return isSuccessful;
        }

        /// <summary>
        /// Updates the silverlight configuration file.
        /// </summary>
        /// <param name="configFileName">Name of the config file.</param>
        /// <param name="xapFilePath">The xap file path.</param>
        /// <param name="replacementIp">The replacement ip.</param>
        /// <param name="destinationIp">The destination ip.</param>
        /// <returns></returns>
        private bool UpdateSilverlightConfigurationFile(string configFileName,
            string xapFilePath, string replacementIp, string destinationIp)
        {
            // Check file path
            if (!File.Exists(xapFilePath)) { return false; }

            // Open XAP and modify configuration
            using (var zip = ZipFile.Read(xapFilePath))
            {
                // Get config file
                var entry = zip[configFileName];
                var stream = new MemoryStream();
                entry.Extract(stream);

                // Manipulate configuration
                var updated =
                    UpdateConfigurationFile(stream, replacementIp, destinationIp);

                // Evaluate
                if (updated)
                {
                    // Replace existing configuration file in XAP
                    zip.UpdateEntry(configFileName, stream);
                    zip.Save();
                }
            }

            // return
            return true;
        }
    }
}

With the help of DotNetZip we were able to update the XAP file with our revised IP information.

That’s all for now. I hope I helped you with this annoyance.

One of the issues I have seen around the web is in regard to TabControls and missing content. The “missing” content in this case is the content of tab items within a TabControl that are not in focus. By design, a TabControl will only load the content of a TabItem once it has been brought into focus. This is not bad design if you think about it for a moment.

Q: Shouldn’t we just load into memory what we need at the time we need it to minimize our footprint?
A: Yes, definitely. This is good application design.

But, what about the case where I need information from other tabs that have not yet been brought into focus? For example, what if I have a GridView in another tab and I want to show the row count right when the control is loaded? Well, the answer to that is pre-loading your tab items. And since the TabControl does not have this behavior built-in by default, we will have to do it ourselves.

Here is one way I saw on the web that I wanted to bring to your attention:


for (var i = 0; i < myTabControl.Items.Count; i++)
{
	myTabControl.SelectedIndex = i;
	myTabControl.UpdateLayout();
}

Well, this looks pretty good and it has very little code. This should work, right? No, not in all cases. The reason is that this will cycle through the tabs as fast as the UpdateLayout() call completes on each tab. Because this implementation will not necessarily wait until each tab is done loading, we cannot guarantee that the content of each tab has finished loading into the Visual Tree. What we need is a solution that waits until each tab item has completely loaded its content before we move to the next tab.

So, let’s state our list of objectives:

  • Objective 1: Each tab item should wait to complete loading before the next tab item is selected.
  • Objective 2: We should hide the Tab Control from view until it is done pre-loading.
  • Objective 3: We should return to the first tab in the sequence at completion.

The approach:

In order to effectively meet the first objective, we should chain the loading of each tab through recursion.

So, here are our 2 methods:


/// <summary>
/// Preloads tab items of a tab control in sequence.
/// </summary>
/// <param name="tabControl">The tab control.</param>
public static void PreloadTabs(TabControl tabControl)
{
    // Evaluate
    if (tabControl.Items != null)
    {
        // The first tab is already loaded
        // so, we will start from the second tab.
        if (tabControl.Items.Count > 1)
        {
            // Hide tabs
            tabControl.Opacity = 0.0;

            // Last action
            Action onComplete = () =>
            {
                // Set index to first tab
                tabControl.SelectedIndex = 0;

                // Show tabs
                tabControl.Opacity = 1.0;
            };

            // Second tab
            var firstTab = (tabControl.Items[1] as TabItem);
            if (firstTab != null)
            {
                PreloadTab(tabControl, firstTab, onComplete);
            }
        }
    }
}

/// <summary>
/// Preloads an individual tab item.
/// </summary>
/// <param name="tabControl">The tab control.</param>
/// <param name="tabItem">The tab item.</param>
/// <param name="onComplete">The onComplete action.</param>
private static void PreloadTab(TabControl tabControl, TabItem tabItem, Action onComplete = null)
{
    // On update complete
    tabItem.Loaded += delegate
    {
    	// Update if not the last tab
    	if (tabItem != tabControl.Items.Last())
    	{
    	    // Get next tab
            var nextIndex = tabControl.Items.IndexOf(tabItem) + 1;
            var nextTabItem = tabControl.Items[nextIndex] as TabItem;

            // Preload
            if (nextTabItem != null)
            {
                PreloadTab(tabControl, nextTabItem, onComplete);
            }
        }

        else
        {
            if (onComplete != null)
            {
                onComplete();
            }
        }
    };

    // Set current tab context
    tabControl.SelectedItem = tabItem;
}

So what’s going on here?

  1. PreloadTabs acts as our public method where we pass the TabControl.
  2. The opacity of the TabControl is set to 0 (Objective 2). We do not change the visibility in this case because the UI will not properly update if Visibility is Collapsed.
  3. PreloadTabs will make sure it has tab items and then call our private method PreloadTab for the second tab in the collection (since the first tab would already be loaded by the instantiation of the TabControl).
  4. PreloadTab evaluates the second tab item in the collection by setting the TabControl.SelectedItem property to the current tab.
  5. Once the tab item has completed loading, it will be evaluated. (Objective 1)
  6. If it is not the last tab item in the collection, the next tab item is retrieved and passed to the PreloadTab method.
  7. Note: This behavior will repeat until the last item in the tab item collection has been reached.
  8. Once the last item has been reached, the onComplete action is called.
  9. When the onComplete action is called, we set the SelectedIndex of the TabControl back to 0 (Objective 2), and then restore the opacity of the TabControl back to 1 (Objective 3).

And just like that we have a tab pre-loader for our TabControl.

That’s all for now. Happy coding.

A different take on Deep Copy

Categories: .Net, C#, Clone, Silverlight, WPF
Comments: 1

This article has been revised here.

I have seen several examples of different methods to perform a deep copy in C#. The most common one is with a Stream, implemented like this:


public static T DeepClone<T>(T obj)
{
 using (var ms = new MemoryStream())
 {
   var formatter = new BinaryFormatter();
   formatter.Serialize(ms, obj);
   ms.Position = 0;

   return (T) formatter.Deserialize(ms);
 }
}

That is certainly one way to do it but it won’t work in Silverlight.

The suggested Sliverlight approach:


public static T DeepCopy<T>(this T oSource)
{
    T oClone;
    DataContractSerializer dcs = new DataContractSerializer(typeof(T));

    using (MemoryStream ms = new MemoryStream())
    {
        dcs.WriteObject(ms, oSource);
        ms.Position = 0;
        oClone = (T)dcs.ReadObject(ms);
    }

    return oClone;
}

All right, that works in Silverlight but it requires that all objects passed are Serializable. That is actually a bit of a daunting task for custom objects at times, and we should try to use a simpler more universal approach.

So, I suggest using reflection:

/// <summary>
/// Copies all public properties from one object to another.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
/// <exception cref="System.Exception">Source and destination cannot be null and must be 
/// of the same type!</exception>
public static void DeepCopy(object source, object destination)
{
    if ((source != null &amp;&amp; destination != null) &amp;&amp; 
        (source.GetType() == destination.GetType()))
    {
        // Get properties
        var propertyInfos = source.GetType().GetProperties();
        if (propertyInfos.Length <= 0) return;

        // Evaluate
        foreach (var propInfo in propertyInfos)
        {
            // Process only public properties
            if (!propInfo.CanWrite) continue;

            // Get value from source and assign to destination
            object value = propInfo.GetValue(source, null);
            propInfo.SetValue(destination, value, null);
            if (value == null) continue;

            // Check for properties and propogate if they exist
            var newPropInfos = value.GetType().GetProperties();
            if (newPropInfos.Length > 0)
            {
                // Copy properties for each child where necessary
                DeepCopy(
                    source.GetType().GetProperty(propInfo.Name),
                    destination.GetType().GetProperty(propInfo.Name));
            }
        }
    }

    else
    {
        throw new Exception(
            "Source and destination cannot be null and must be of " +
            "the same type!");
    }
}

This will work in Silverlight because of the if block for propInfo.CanWrite. This is added because based on Silverlights rigid security constraints we can only copy public properties.

That’s all for now.

In this post I am going to introduce the idea of subscribing to property change events in our Model Base.

Note: Please read Part I before continuing here.
Note: Please read Part II before continuing here.

The purpose of this is to cover a potentially annoying situation:

Scenario: Let’s say you have a ViewModel, and inside that you have another ViewModel acting as a property like this:


    private MyCustomObject _customObjectInstance;

    public MyCustomObject CustomObjectInstance
    {
        get
        {
            return _customObjectInstance;
        }

        set
        {
            SetValue("CustomObjectInstance", ref _customObjectInstance, ref value);
        }
    }

Okay, now you want your UI bound to the current ViewModel to change every time CustomObjectInstance.MeterReading changes.

Q: (Panic moment) So, how do I do that without breaking my wonderful abstraction?
A: Implementing an ability to Subscribe to a nested property. All it takes is a little reflection and patience.

The idea is that we tell that property to fire a specific Action whenever it is changed in our ViewModelBase.

The first thing we will need to add is a private list of subscriptions:


/// <summary>
/// Subscription list.
/// </summary>
private readonly List<Tuple<string, Action<object>>> _subscriptions;

Instead of creating yet another custom object, I decided to use a Tuple because they are convenient.

  • The string value will serve as the name of the property you want to subscribe to.
  • The Action will serve as the Action you wish to call when the property is changed. The object parameter allows you to return an object if needed.

Next, we make sure to create a new instance of _subscriptions in the Constructor:


/// <summary>
/// Default constructor.
/// </summary>
protected ViewModelBase()
{
    _subscriptions = new List<Tuple<string, Action<object>>>();
}

Now we will expose a Subscribe method.

        /// <summary>
        /// Subscribes an action to a specific property that will be called
        /// during that property's OnPropertyChanged event.
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="onChange"></param>
        public void Subscribe(string propertyName, Action<object> onChange)
        {
            // Verify property
            var propInfo = this.GetType().GetProperty(propertyName);

            // If valid, add to subscription pool.
            if (propInfo != null)
            {
                _subscriptions.Add(
                    new Tuple<string, Action<object>>(propertyName, onChange));
            }
            else
            {
                // Invalid property name provided.
                throw new Exception(
                    "Property "" + propertyName + "" could not be " +
                    "found for type "" + this.GetType().ToString() + ""!");
            }
        }

This idea here is fairly simple:

  • We pass our property name and intended Action that will fire OnPropertyChanged.
  • If the property name is not valid, we will throw an exception to ensure we didn’t pass invalid information into our Subscribe method.

Q: Alright, now we have a nice Tuple-list full of property names and Actions. Now what?
A: Glad you asked. Here comes the hard part:


        /// <summary>
        /// Processes existing subscriptions matching the provided property name.
        /// </summary>
        /// <param name="propertyName"></param>
        private void ProcessSubscriptions(string propertyName)
        {
            // Get matching subscriptions
            var subList =
                (from p in _subscriptions
                 where p.Item1 == propertyName
                 select p).ToList();

            // Check if any matches were found.
            if (subList.Any())
            {
                // Process actions
                foreach (var sub in subList)
                {
                    // Evaluate action
                    var onChange = sub.Item2;
                    if (onChange != null)
                    {
                        // Get property value by name
                        var propInfo = this.GetType().GetProperty(propertyName);
                        var propValue = propInfo.GetValue(this, null);

                        // Invoke action
                        onChange(propValue);
                    }
                }
            }
        }

ProcessSubscriptions does the following:

  • Looks up a specific property by name in _subscriptions and gets a list of all entries that are registered for that property.
  • Loop: If a specific entry has a valid Action assigned to it, it will use reflection to get that property value and pass it to the action (as out object parameter mentioned earlier).

So, the last piece is making sure ProcessSubscriptions is fired when the property has been changed. And that is as easy as augmenting our trusted OnPropertyChanged method:


        /// <summary>
        /// Calls the PropertyChanged event
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="onChanged"></param>
        protected void OnPropertyChanged(string propertyName, Action onChanged = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                // Call handler
                handler(this, new PropertyChangedEventArgs(propertyName));

                // Subscriptions
                ProcessSubscriptions(propertyName);

                // On changed
                if (onChanged != null)
                {
                    onChanged();
                }
            }
        }

No worries if your specific property being changed is without entries. ProcessSubscriptions only acts on what is present in _subscriptions, so no entries means it just moves on.

Here is how you would use it in your parent ViewModel:


CustomObjectInstance.Subscribe("MeterReading", obj => MyActionThatDoesStuff());

Now, every time CustomObjectInstance.MeterReading is updated, the MyActionThatDoesStuff Action will be called allowing you to always have the latest values from your nested properties.

Here is our new ViewModelBase in it’s entirety:


    /// <summary>
    /// Extends the INotifyPropertyChanged interface to the class properties.
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region Members

        /// <summary>
        /// Subscription list.
        /// </summary>
        private readonly List<Tuple<string, Action<object>>> _subscriptions;

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        protected ViewModelBase()
        {
            _subscriptions = new List<Tuple<string, Action<object>>>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// To be used within the "set" accessor in each property.
        /// This invokes the OnPropertyChanged method.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="newValue"></param>
        /// <param name="onChanged"></param>
        protected void SetValue<T>(string name, ref T value, ref  T newValue,
            Action onChanged = null)
        {
            if (newValue != null)
            {
                if (!newValue.Equals(value))
                {
                    value = newValue;
                    OnPropertyChanged(name, onChanged);
                }
            }
            else
            {
                value = default(T);
            }
        }

        #endregion

        #region INotifyPropertyChanged

        /// <summary>
        /// The PropertyChanged event handler.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Calls the PropertyChanged event
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="onChanged"></param>
        protected void OnPropertyChanged(string propertyName, Action onChanged = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                // Call handler
                handler(this, new PropertyChangedEventArgs(propertyName));

                // Subscriptions
                ProcessSubscriptions(propertyName);

                // On changed
                if (onChanged != null)
                {
                    onChanged();
                }
            }
        }

        /// <summary>
        /// Subscribes an action to a specific property that will be called
        /// during that property's OnPropertyChanged event.
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="onChange"></param>
        public void Subscribe(string propertyName, Action<object> onChange)
        {
            // Verify property
            var propInfo = this.GetType().GetProperty(propertyName);

            // If valid, add to subscription pool.
            if (propInfo != null)
            {
                _subscriptions.Add(
                    new Tuple<string, Action<object>>(propertyName, onChange));
            }
            else
            {
                // Invalid property name provided.
                throw new Exception(
                    "Property "" + propertyName + "" could not be " +
                    "found for type "" + this.GetType().ToString() + ""!");
            }
        }
        
        /// <summary>
        /// Clears the subscriptions.
        /// </summary>
        public void ClearSubscriptions()
        {
            _subscriptions.Clear();
        }

        /// <summary>
        /// Processes existing subscriptions matching the provided property name.
        /// </summary>
        /// <param name="propertyName"></param>
        private void ProcessSubscriptions(string propertyName)
        {
            // Get matching subscriptions
            var subList =
                (from p in _subscriptions
                 where p.Item1 == propertyName
                 select p).ToList();

            // Check if any matches were found.
            if (subList.Any())
            {
                // Process actions
                foreach (var sub in subList)
                {
                    // Evaluate action
                    var onChange = sub.Item2;
                    if (onChange != null)
                    {
                        // Get property value by name
                        var propInfo = this.GetType().GetProperty(propertyName);
                        var propValue = propInfo.GetValue(this, null);

                        // Invoke action
                        onChange(propValue);
                    }
                }
            }
        }

        #endregion
    }

I hope this has been helpful for you.