Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Silverlight, M-V-VM … and IoC – part 2

DZone's Guide to

Silverlight, M-V-VM … and IoC – part 2

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

In the previous post I’ve presented a very fast introduction of what MVVM is and I’ve defined the two basic interfaces for the view and the viewmodel; I’m not going to implement a ‘pure’ version of the pattern itself because I consider a pattern just a guideline solution to a problem, not something that have to lock me in a cage.

It’s now time to write some infrastructural code that will work together with the two afore mentioned interfaces, we’ve already said that the ViewModel should expose bindable properties that the View will use to display the data.

To obtain that you can use (or combine) two techniques: derive a basic class for your ViewModel from the DependencyObject class and use the dependency and attached property that the framework already provide, or you can choose a more lightweight approach and implement the INotifyPropertyChanged interface in your base class.

Also remember you will have to deal with asynchronous operations too, so maybe the data on your bindable properties can be updated in a background thread (and changing a bound property from there can result in an AccessViolationException…because you cannot alter anything that involves the UI or the control status from there: WPF and Silverlight objects belong to the thread on which they are created and cannot be accessed by any other thread directly).

To keep things simple in my current implementation I’ve followed the second approach, so my infrastructure code base when dealing with the MVVM pattern and asynchronous operations looks like this:

MVVM_Scheme2

Let’s take a look at the classes and their purposes:

Model: the base class of the whole infrastructure, it can be used to derive Domain Model/DTO and ViewModel classes, it just implement the IDisposable and the INotifyPropertyChanged interfaces to enable the derived class for effective data binding. To allow you to change the bound properties even in background threads internally it uses the UiDispatcher utility class.

/// <summary>
/// base class for Domain Model, DTO and ViewModel classes
/// </summary>
public class Model : INotifyPropertyChanged, IDisposable
{
	/// <summary>
	/// a dictionary to cache property changed event args generated for each property
	/// </summary>
	private static readonly Dictionary<string, PropertyChangedEventArgs> _eventArgsMap =
		 new Dictionary<string, PropertyChangedEventArgs>();

	/// <summary>
	/// function to assign the value of a property to an internal member
	/// and to raid the corresponding property chanhed event
	/// </summary>
	/// <typeparam name="T">Type of the property to set</typeparam>
	/// <param name="field">internal variable that holds the value</param>
	/// <param name="value">new value to set</param>
	/// <param name="propName">name of the property</param>
	protected void InnerSet<T>(ref T field, T value, string propName)
	{
		if ((field == null) && (value == null)) return;
		if ((field != null) && (field.Equals(value))) return;
		field = value;
		RaisePropertyChanged(propName);
	}

	protected void InnerSet<T>(ref T field, T value, params string[] propsName)
	{
		if ((field == null) && (value == null)) return;
		if ((field != null) && (field.Equals(value))) return;
		field = value;
		RaisePropertyChanged(propsName);
	}

	/// <summary>
	/// Get a PropertyChangedEventArgs instance fromt he dictionary or
	/// create a new one if not present
	/// </summary>
	/// <param name="propertyName">name of the property</param>
	/// <returns>Instance of the class</returns>
	private static PropertyChangedEventArgs GetEventArgs(string propertyName)
	{
		PropertyChangedEventArgs pe;
		if (_eventArgsMap.TryGetValue(propertyName, out pe) == false)
		{
			pe = new PropertyChangedEventArgs(propertyName);
			_eventArgsMap[propertyName] = pe;
		}
		return pe;
	}

	/// <summary>
	/// Raises a change notification event to signal a change in the
	/// specified property's value.
	/// </summary>
	/// <param name="propertyName">The property that has changed.</param>
	protected void RaisePropertyChanged(string propertyName)
	{
		if (String.IsNullOrEmpty(propertyName))
			throw new ArgumentNullException("propertyName");
		if (PropertyChanged == null) return;
		if (SynchronizationContext.Current != null)
			SynchronizationContext.Current.Post(delegate { OnPropertyChanged(propertyName); }, null);
		else
			UiDispatcher.Run(() => OnPropertyChanged(propertyName));
	}

	/// <summary>
	/// Raises a change notification event to signal a change in the
	/// specified properties.
	/// </summary>
	/// <param name="propertyNames">The properties that have changed.</param>
	protected void RaisePropertyChanged(params string[] propertyNames)
	{
		if ((propertyNames == null) || (propertyNames.Length == 0))
			throw new ArgumentNullException("propertyNames");

		if (SynchronizationContext.Current != null)
			SynchronizationContext.Current.Post(state =>
			{
				OnPropertiesChanged(propertyNames);
			}, null);
		else
			UiDispatcher.Run(() =>
			{
				OnPropertiesChanged(propertyNames);
			});
	}

	#region Implementation of INotifyPropertyChanged

	/// <summary>
	/// lets make it virtual to be used with ORMs proxies
	/// </summary>
	public virtual event PropertyChangedEventHandler PropertyChanged;

	protected void OnPropertyChanged(string propertyName)
	{
		if (PropertyChanged != null)
			PropertyChanged(this, GetEventArgs(propertyName));
	}

	private void OnPropertiesChanged(string[] propertyNames)
	{
		foreach (string propertyName in propertyNames)
			OnPropertyChanged(propertyName);
	}

	#endregion

	#region IDisposable Members

	public void Dispose()
	{
		Dispose(true);
		GC.SuppressFinalize(this);
	}

	protected virtual void Dispose(bool disposing)
	{
		if (mDisposed) return;
		mDisposed = true;
		if (disposing)
		{
			// TODO: free other state (managed objects).
		}
		// TODO: free your own state (unmanaged objects).
		// TODO: set large fields to null.
	}
	private Boolean mDisposed = false;

	#endregion

}

ViewModel: directly inherits from Model class and implement the IViewModel interface we saw last time, all our view-model classes will derive from this one.

public class ViewModel : Model, IViewModel
{
	public IView View { get; set; }

	public bool IsBusy
	{
		get { return _isBusy; }
		protected set { InnerSet(ref _isBusy, value, "IsBusy"); }
	}
	private bool _isBusy;
}

UiDispatcher: A static class that holds a reference to an IDispatcher object, this is basically just a wrapper around the System.Windows.Threading.Dispatcher object that is associated with the UI thread. I actually have just two implementation of this class: InvokeDispatcher that just execute the delegate passed in to the Run() methods and WIndowsDispatcher that executes the delegate through the dispatcher to allow you to alter the UI in the correct thread avoiding the AccessViolationException.

/// <summary>
/// interface for a generic dispatcher
/// </summary>
public interface IDispatcher
{
  Dispatcher Dispatcher { get; }

  void Run(Action a);

  void Run(Delegate d, params object[] args);
}

public static class UiDispatcher
{
	public static void SetDispatcher(IDispatcher dispatcher)
	{
		Dispatcher = dispatcher;
	}

	private static IDispatcher Dispatcher = new InvokeDispatcher();

	public static void Run(Action a)
	{
		Dispatcher.Run(a);
	}

	public static void Run(Delegate d, params object[] args)
	{
		Dispatcher.Run(d, args);
	}
}

/// <summary>
/// used on the UI projects to let the UI binding works when the properties are
/// changed by background threads.
/// </summary>
public class WindowsDispatcher : IDispatcher
{
	public WindowsDispatcher(Dispatcher dispatcher)
	{
		Dispatcher = dispatcher;
	}

	public Dispatcher Dispatcher { get; private set; }

	public void Run(Action a)
	{
		Dispatcher.BeginInvoke(a);
	}

	public void Run(Delegate d, params object[] args)
	{
		Dispatcher.BeginInvoke(d, args);
	}
}

/// <summary>
/// used on the test classes
/// </summary>
public class InvokeDispatcher : IDispatcher
{
	public Dispatcher Dispatcher
	{
		get { return null; }
	}

	public void Run(Action a)
	{
		a.Invoke();
	}

	public void Run(Delegate d, params object[] args)
	{
		d.DynamicInvoke(args);
	}
}

The UiDispatcher class will use the InvokeDIspatcher as his default choice (mainly because when doing Unit Tests you usually do not have a UI nor a dispatcher), to change the behavior you need to configure it right after the creation of the Application shell, with something like this:

// set the dispatcher
MainPage p = ServiceLocator.Resolve<MainPage>();
UiDispatcher.SetDispatcher(new WindowsDispatcher(p.Dispatcher));

As an alternative to use the Dispatcher object directly we could have saved the DispatcherSynchronizationContext that is associated with the UI thread and use that to make the calls.

It’s starting to have a shape isn’t it ?! By the way, the techniques presented here as you can imagine works in both Silverlight and WPF.

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:

Published at DZone with permission of Alessandro Giorgetti, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}