Click here to Skip to main content
15,881,588 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 48.8K   572   11  
This article explains how to write unit tests for MVVM using Catel.
using System;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using Catel.Articles.Base.Data;
using Catel.Articles.Base.Data.Attributes;
using Catel.Articles.Base.Properties;
using Catel.Data;
using Catel.MVVM;
using Catel.MVVM.Services;
using log4net;

namespace Catel.Articles.Base.UI.ViewModels
{
    /// <summary>
    /// Examples view model.
    /// </summary>
    public class ExamplesViewModel : ViewModelBase
	{
		#region Variables
    	private readonly string _title;
		#endregion

		#region Constructor & destructor
		/// <summary>
		/// Initializes a new instance of the <see cref="ExamplesViewModel"/> class.
		/// </summary>
		/// <param name="title">The title.</param>
		public ExamplesViewModel(string title)
		{
			// Store values
			_title = title;
		}
		#endregion

		#region Properties
    	/// <summary>
    	/// Gets the title of the view model.
    	/// </summary>
    	/// <value>The title.</value>
    	public override string Title { get { return _title; } }

        #region View model
        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        public string Description
        {
            get { return GetValue<string>(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }

        /// <summary>
        /// Register the Description property so it is known in the class.
        /// </summary>
        public static readonly PropertyData DescriptionProperty = RegisterProperty("Description", typeof(string), Resources.ExamplesDescription);

        /// <summary>
        /// Gets or sets a collection of themes.
        /// </summary>
        public Collection<ThemeInfo> ThemeCollection
        {
            get { return GetValue<Collection<ThemeInfo>>(ThemeCollectionProperty); }
            set { SetValue(ThemeCollectionProperty, value); }
        }

        /// <summary>
        /// Register the ThemeCollection property so it is known in the class.
        /// </summary>
        public static readonly PropertyData ThemeCollectionProperty = RegisterProperty("ThemeCollection", typeof(Collection<ThemeInfo>));

        /// <summary>
        /// Gets or sets the selected theme.
        /// </summary>
        public ThemeInfo SelectedTheme
        {
            get { return GetValue<ThemeInfo>(SelectedThemeProperty); }
            set { SetValue(SelectedThemeProperty, value); }
        }

        /// <summary>
        /// Register the SelectedTheme property so it is known in the class.
        /// </summary>
        public static readonly PropertyData SelectedThemeProperty = RegisterProperty("SelectedTheme", typeof(ThemeInfo),
            (sender, e) => ((ExamplesViewModel)sender).OnSelectedThemeChanged());

        /// <summary>
        /// Gets or sets the examples collection.
        /// </summary>
        public ObservableCollection<ExampleInfo> Examples
        {
            get { return GetValue<ObservableCollection<ExampleInfo>>(ExamplesProperty); }
            set { SetValue(ExamplesProperty, value); }
        }

        /// <summary>
        /// Register the Examples property so it is known in the class.
        /// </summary>
        public static readonly PropertyData ExamplesProperty = RegisterProperty("Examples", typeof(ObservableCollection<ExampleInfo>), new ObservableCollection<ExampleInfo>());

        /// <summary>
        /// Gets or sets the selected example.
        /// </summary>
        public ExampleInfo SelectedExample
        {
            get { return GetValue<ExampleInfo>(SelectedExampleProperty); }
            set { SetValue(SelectedExampleProperty, value); }
        }

        /// <summary>
        /// Register the SelectedExample property so it is known in the class.
        /// </summary>
        public static readonly PropertyData SelectedExampleProperty = RegisterProperty("SelectedExample", typeof(ExampleInfo));
        #endregion
        #endregion

        #region Methods
        /// <summary>
        /// Initializes the object by setting default values.
        /// </summary>	
        protected override void Initialize()
        {
            // Log
            Log.Info("Welcome to the examples app");
            Log.StartStopwatchTrace("Searching for all examples in the current AppDomain");

            // Get all the types of the app domain
            foreach (Assembly assembly in AssemblyHelper.GetLoadedAssemblies())
            {
                try
                {
                    foreach (Type type in assembly.GetTypes())
                    {
                        // Is the type decorated with the example attribute?
                        if (type.IsClass)
                        {
                            ExampleAttribute[] exampleAttributes = (ExampleAttribute[])type.GetCustomAttributes(typeof(ExampleAttribute), false);
                            if (exampleAttributes.Length > 0)
                            {
                                // Create example info
                                ExampleInfo exampleInfo = new ExampleInfo(exampleAttributes[0]);

                                // Does the attribute have a click handler?
                                if (!string.IsNullOrEmpty(exampleAttributes[0].ClickHandlerName))
                                {
                                    // Try to find the handler
                                    MethodInfo methodInfo = type.GetMethod(exampleAttributes[0].ClickHandlerName,
                                        BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                                    if (methodInfo != null)
                                    {
                                        // Store it
                                        exampleInfo.ClickHandler = Delegate.CreateDelegate(typeof(VoidDelegate), methodInfo) as VoidDelegate;
                                    }
                                }

                                // Add
                                if (!Examples.Contains(exampleInfo)) Examples.Add(exampleInfo);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Log and continue
                    Log.Error(ex, "Failed to get types of an assembly");
                }
            }

            // Log
            Log.StopStopwatchTrace("Searching for all examples in the current AppDomain");
            Log.Info("Found '{0}' example(s)", Examples.Count);

            // Set initial example
            if (Examples.Count > 0) SelectedExample = Examples[0];

            // Initialize themes
            ThemeCollection = new Collection<ThemeInfo>();
            ThemeCollection.Add(new ThemeInfo("Aero - normal", "/Catel.Windows;component/themes/aero/catel.aero.normal.xaml"));
            ThemeCollection.Add(new ThemeInfo("Aero - large", "/Catel.Windows;component/themes/aero/catel.aero.large.xaml"));
            ThemeCollection.Add(new ThemeInfo("Expression Dark - normal", "/Catel.Windows;component/themes/expressiondark/catel.expressiondark.normal.xaml"));
            ThemeCollection.Add(new ThemeInfo("Expression Dark - large", "/Catel.Windows;component/themes/expressiondark/catel.expressiondark.large.xaml"));
            ThemeCollection.Add(new ThemeInfo("Jetpack", "/Catel.Windows;component/themes/jetpack/generic.xaml"));
            ThemeCollection.Add(new ThemeInfo("Sunny Orange", "/Catel.Windows;component/themes/sunnyorange/generic.xaml"));

            // Set selected (default) theme
            SelectedTheme = ThemeCollection[0];
        }

        /// <summary>
        /// Called when the <see cref="SelectedTheme"/> property has changed.
        /// </summary>
        private void OnSelectedThemeChanged()
        {
            // Clear app resources
            var currentApp = Application.Current;
            if (currentApp == null)
            {
                // Show error
                var messageService = GetService<IMessageService>();
                messageService.ShowError("There is no current application object, cannot switch theme");

                // Exit
                return;
            }

            // Need to call this twice because the first update fixes the dictionaries, and the second one actually updates the UI
            UpdateApplicationResources(currentApp);
            UpdateApplicationResources(currentApp);
        }

        /// <summary>
        /// Updates the application resources.
        /// </summary>
        /// <param name="currentApp">The current application.</param>
        private void UpdateApplicationResources(Application currentApp)
        {
            // Clear resources
            currentApp.Resources.Clear();
            currentApp.Resources.MergedDictionaries.Clear();

            // Merge resources
            ResourceDictionary resourceDictionary = new ResourceDictionary(); 
            resourceDictionary.Source = new Uri(SelectedTheme.Source, UriKind.RelativeOrAbsolute);

            // Now merge the dictionaries
            currentApp.Resources.MergedDictionaries.Add(resourceDictionary);

            // Create style forwarders
            Catel.Windows.StyleHelper.CreateStyleForwardersForDefaultStyles();
        }
        #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