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.
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AnimatedGif.cs" company="Catel development team">
//   Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
//   User control supporting animated gif.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
using System.Windows.Threading;

namespace Catel.Windows.Controls
{
	/// <summary>
	/// User control supporting animated gif.
	/// </summary>
	public class AnimatedGif : System.Windows.Controls.Image
	{
		#region Win32 imports
		[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
		private static extern IntPtr DeleteObject(IntPtr hDc);
		#endregion

		#region Variables
		private Bitmap _bitmap;
		#endregion

		#region Constructor & destructor
		#endregion

		#region Delegates
		/// <summary>
		/// OnFrameChanged delegate.
		/// </summary>
		private delegate void OnFrameChangedDelegate();
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets a value indicating whether this instance is animating.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is animating; otherwise, <c>false</c>.
		/// </value>
		private bool IsAnimating { get; set; }

		/// <summary>
		/// Gets or sets the current frame.
		/// </summary>
		/// <value>The current frame.</value>
		private int CurrentFrame { get; set; }

		/// <summary>
		/// Gets or sets GifSource.
		/// </summary>
		/// <remarks>
		/// Wrapper for the GifSource dependency property.
		/// </remarks>
		public string GifSource
		{
			get { return (string)GetValue(GifSourceProperty); }
			set { SetValue(GifSourceProperty, value); }
		}

		/// <summary>
		/// DependencyProperty definition as the backing store for GifSource.
		/// </summary>
		public static readonly DependencyProperty GifSourceProperty = DependencyProperty.Register("GifSource", typeof(string),
			typeof(AnimatedGif), new UIPropertyMetadata(string.Empty, GifSource_Changed));
		#endregion

		#region Methods
		/// <summary>
		/// Invoked when the GifSource dependency property has changed.
		/// </summary>
		/// <param name="sender">The object that contains the dependency property.</param>
		/// <param name="e">The event data.</param>
		[DebuggerStepperBoundary()]
		private static void GifSource_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
		{
			AnimatedGif typedSender = sender as AnimatedGif;
			if (typedSender != null)
			{
				typedSender.SetImageGifSource();
			}
		}

		/// <summary>
		/// Sets the image gif source.
		/// </summary>
		private void SetImageGifSource()
		{
			if (_bitmap != null)
			{
				ImageAnimator.StopAnimate(_bitmap, OnFrameChanged);

				_bitmap = null;
			}

			if (string.IsNullOrEmpty(GifSource))
			{
				Source = null;

				InvalidateVisual();

				return;
			}

			// Check if this is a file
			if (File.Exists(GifSource))
			{
				_bitmap = (Bitmap)Image.FromFile(GifSource);
			}
			else
			{
				// Support looking for embedded resources
				Assembly assemblyToSearch = Assembly.GetAssembly(GetType());
				_bitmap = GetBitmapResourceFromAssembly(assemblyToSearch);
				if (_bitmap == null)
				{
					// Search calling assembly
					assemblyToSearch = Assembly.GetCallingAssembly();
					_bitmap = GetBitmapResourceFromAssembly(assemblyToSearch);
					if (_bitmap == null)
					{
						// Get entry assembly
						assemblyToSearch = Assembly.GetEntryAssembly();
						_bitmap = GetBitmapResourceFromAssembly(assemblyToSearch);
						if (_bitmap == null)
						{
							throw new FileNotFoundException(Properties.Exceptions.AnimatedGifNotFound, GifSource);
						}
					}
				}
			}

			// Start animating
			ImageAnimator.Animate(_bitmap, OnFrameChanged);
		}

		/// <summary>
		/// Gets the bitmap resource from a specific assembly.
		/// </summary>
		/// <param name="assemblyToSearch">The assembly to search.</param>
		/// <returns><see cref="Bitmap"/> or null if resource is not found.</returns>
		[DebuggerStepperBoundary()]
		private Bitmap GetBitmapResourceFromAssembly(Assembly assemblyToSearch)
		{
			// Loop through all resources
			if (null != assemblyToSearch.FullName)
			{
				// Get stream resource info
				StreamResourceInfo streamResourceInfo = Application.GetResourceStream(new Uri(GifSource, UriKind.RelativeOrAbsolute));
				if (streamResourceInfo != null)
				{
					return (Bitmap)Image.FromStream(streamResourceInfo.Stream);
				}
			}

			return null;
		}

		/// <summary>
		/// Called when a frame has changed.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		[DebuggerStepperBoundary()]
		private void OnFrameChanged(object sender, EventArgs e)
		{
			// Dispatch the frame changed
			Dispatcher.BeginInvoke(DispatcherPriority.Normal, new OnFrameChangedDelegate(OnFrameChangedInMainThread));
		}

		/// <summary>
		/// Called when a frame changed in the main thread.
		/// </summary>
		[DebuggerStepperBoundary()]
		private void OnFrameChangedInMainThread()
		{
			// Update the frames
			ImageAnimator.UpdateFrames(_bitmap);

			// Get bitmap source
			Source = GetBitmapSource(_bitmap);

			// Invalidate visual
			InvalidateVisual();
		}

		/// <summary>
		/// Gets the bitmap source.
		/// </summary>
		/// <param name="gdiBitmap">The GDI bitmap.</param>
		/// <returns></returns>
		[DebuggerStepperBoundary()]
		private static BitmapSource GetBitmapSource(Bitmap gdiBitmap)
		{
			// Get the bitmap
			IntPtr hBitmap = gdiBitmap.GetHbitmap();

			// Create the bitmap
			BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

			// Delete bitmap pointer
			DeleteObject(hBitmap);

			// Return bitmap source
			return bitmapSource;
		}
		#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