Click here to Skip to main content
15,896,493 members
Articles / Desktop Programming / WPF

Catel - Part 4 of n: Unit testing with Catel

Rate me:
Please Sign up or sign in to vote.
4.55/5 (10 votes)
28 Jan 2011CPOL11 min read 49.5K   572   11  
This article explains how to write unit tests for MVVM using Catel.
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ManagedViewModel.cs" company="Catel development team">
//   Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
//   Represents a managed view model. A managed view model is watched for property changes. As soon as a change occurs in one of the
//   managed view models, all other interested view models are notified of the changes.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Catel.Properties;
using log4net;

namespace Catel.MVVM
{
	/// <summary>
	/// Represents a managed view model. A managed view model is watched for property changes. As soon as a change occurs in one of the
	/// managed view models, all other interested view models are notified of the changes.
	/// </summary>
	internal class ManagedViewModel
	{
		#region Variables
        /// <summary>
        /// The <see cref="ILog">log</see> object.
        /// </summary>
		private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// List of alive view model instances.
        /// </summary>
        private readonly List<IViewModel> _viewModelInstances = new List<IViewModel>();

        /// <summary>
        /// List of alive view model instances that are interested in other view models.
        /// </summary>
        private readonly List<IViewModel> _interestedViewModels = new List<IViewModel>();
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new instance of the <see cref="ManagedViewModel"/> class.
		/// </summary>
		/// <param name="viewModelType">Type of the view model.</param>
		public ManagedViewModel(Type viewModelType)
		{
			ViewModelType = viewModelType;
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the type of the view model.
		/// </summary>
		/// <value>The type of the view model.</value>
		public Type ViewModelType { get; private set; }
		#endregion

		#region Methods
		/// <summary>
		/// Adds a view model instance to the list of instances.
		/// </summary>
		/// <param name="viewModel">The view model instance to add.</param>
		/// <exception cref="ArgumentNullException">When <paramref name="viewModel"/> is <c>null</c>.</exception>
		/// <exception cref="WrongViewModelTypeException">When <paramref name="viewModel"/> is not of the right type.</exception>
        public void AddViewModelInstance(IViewModel viewModel)
		{
			if (viewModel == null)
			{
			    throw new ArgumentNullException("viewModel");
			}

			if (viewModel.GetType() != ViewModelType)
			{
			    throw new WrongViewModelTypeException(viewModel.GetType(), ViewModelType);
			}

			lock (_viewModelInstances)
			{
				if (!_viewModelInstances.Contains(viewModel))
				{
					_viewModelInstances.Add(viewModel);

					viewModel.PropertyChanged += ViewModel_PropertyChanged;

					Log.Debug(TraceMessages.AddedViewModelInstance, _viewModelInstances.Count, ViewModelType);
				}
			}
		}

		/// <summary>
		/// Removes a view model instance from the list of instances.
		/// </summary>
		/// <param name="viewModel">The view model instance to remove.</param>
		/// <exception cref="ArgumentNullException">When <paramref name="viewModel"/> is <c>null</c>.</exception>
        public void RemoveViewModelInstance(IViewModel viewModel)
		{
			if (viewModel == null)
			{
			    throw new ArgumentNullException("viewModel");
			}

			lock (_viewModelInstances)
			{
				viewModel.PropertyChanged -= ViewModel_PropertyChanged;

				_viewModelInstances.Remove(viewModel);

				Log.Debug(TraceMessages.RemovedViewModelInstance, _viewModelInstances.Count, ViewModelType);
			}
		}

		/// <summary>
		/// Adds a view model to the list of interested view models for this view model type.
		/// </summary>
		/// <param name="viewModel">The view model instance that is interested in changes.</param>
		/// <exception cref="ArgumentNullException">When <paramref name="viewModel"/> is <c>null</c>.</exception>
        public void AddInterestedViewModel(IViewModel viewModel)
		{
			if (viewModel == null)
			{
			    throw new ArgumentNullException("viewModel");
			}

			lock (_interestedViewModels)
			{
				_interestedViewModels.Add(viewModel);

				viewModel.Closed += InterestedViewModel_Closed;

				Log.Debug(TraceMessages.AddedInterestedViewModel, viewModel.GetType(), ViewModelType, _interestedViewModels.Count);
			}
		}

		/// <summary>
		/// Removes a view model from the list of interested view models for this view model type.
		/// </summary>
		/// <param name="viewModel">The view model instance that is interested in changes.</param>
		/// <exception cref="ArgumentNullException">When <paramref name="viewModel"/> is <c>null</c>.</exception>
        public void RemoveInterestedViewModel(IViewModel viewModel)
		{
			if (viewModel == null)
			{
			    throw new ArgumentNullException("viewModel");
			}

			lock (_interestedViewModels)
			{
				viewModel.Closed -= InterestedViewModel_Closed;

				_interestedViewModels.Remove(viewModel);

				Log.Debug(TraceMessages.RemovedInterestedViewModel, viewModel.GetType(), ViewModelType, _interestedViewModels.Count);
			}
		}

		/// <summary>
		/// Handles the PropertyChanged event of the ViewModel instances.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
		private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			lock (_interestedViewModels)
			{
				foreach (ViewModelBaseWithoutServices viewModel in _interestedViewModels)
				{
					try
					{
						viewModel.ViewModelPropertyChanged((IViewModel)sender, e.PropertyName);
					}
					catch (Exception ex)
					{
						Log.Error(ex, TraceMessages.FailedToInformInterestedViewModelOfAViewModelChange);
					}	
				}
			}
		}

		/// <summary>
		/// Handles the Closed event of the InterestedViewModel instances.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void InterestedViewModel_Closed(object sender, EventArgs e)
		{
            RemoveInterestedViewModel((IViewModel)sender);
		}
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions