Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Catel - Part 4 of n: Unit testing with Catel

, 28 Jan 2011 CPOL
This article explains how to write unit tests for MVVM using Catel.
Catel-04_01-unittesting.zip
src
Catel.Articles.04 - Unit testing
Models
Properties
Settings.settings
Resources
Images
add.png
delete.png
edit.png
group.png
UI
Data
Converters
ViewModels
Windows
Catel.Articles.04 - Unit testing.Test
Models
Properties
UI
ViewModels
Catel.Articles.Base
Data
Attributes
Properties
Settings.settings
Resources
Images
CatenaLogic.png
Preview.png
Run.png
ShowCode.png
UI
Controls
Helpers
ViewModels
Windows
Catel.Core
Attributes
ClassDiagrams
DataObjectBase.cd
SavableDataObjectBase.cd
Collections
Helpers
ComponentModel
Data
Attributes
Exceptions
Interfaces
Diagnostics
Extensions
Helpers
Exceptions
Helpers
IO
Exceptions
IoC
LLBLGen
Log4net
Appender
Extensions
Helpers
MVVM
Commands
Interfaces
Exceptions
Services
EventArgs
Exceptions
Interfaces
ViewModels
Attributes
Interfaces
Properties
Reflection
Exceptions
Extensions
Helpers
Runtime
Serialization
Attributes
Helpers
Security
Cryptography
Helpers
Catel.Examples.Models
Properties
Catel.Examples.PersonApplication
Properties
Settings.settings
Resources
Images
add.png
delete.png
edit.png
group.png
UI
Data
Converters
ViewModels
Windows
Catel.Examples.Silverlight
Properties
Resources
Images
add.png
delete.png
edit.png
group.png
UI
Data
Converters
Pages
ViewModels
Windows
Catel.Examples.Silverlight.Web
Catel.Examples.Silverlight.Web.csproj.user
ClientBin
Properties
Catel.FxCop
Catel.Silverlight
Diagnostics
log4net
Core
MVVM
Commands
Services
ViewModels
Properties
Catel.Core
Catel.Windows
Reflection
Themes
Generic
Assets
Old
Windows
Controls
Data
Converters
Helpers
Helpers
Catel.Silverlight.Test
Properties
Catel.Silverlight.Test.Web
Catel.Silverlight.Test.Web.csproj.user
ClientBin
Properties
Catel.snk
Catel.Templates.WpfApplication
Properties
Settings.settings
UI
Controls
ViewModels
Windows
Catel.Templates.WpfItemTemplates
Properties
UI
Controls
ViewModels
Windows
Catel.Test
Collections
Convert
Data
Helpers
IO
MVVM
UI
ViewModels
Properties
Reflection
Runtime
Serialization
Security
Cryptography
Test References
Catel.Windows.accessor
Windows
Data
Converters
Catel.vsmdi
Catel.Windows
ClassDiagrams
ViewModelBase.cd
Collections
Extensions
Helpers
MVVM
Commands
Services
Test
UI
ViewModels
Properties
Settings.settings
Resources
Images
Add.png
ClearOutput.png
Edit.png
Error.png
Loading.gif
Preview.png
Remove.png
Save.png
TipOfTheDay.png
Warning.png
Themes
Aero
ExpressionDark
Assets
Generic
Assets
Controls
Jetpack
Assets
background.png
Old
SunnyOrange
Assets
Windows
Controls
Extensions
LinkLabel
StackGrid
Data
Converters
Helpers
Documents
Extensions
Extensions
Helpers
Input
Markup
Media
Effects
EmptyEffect
EmptyEffect.fx
EmptyEffect.ps
EmptyEffect.fx
GrayscaleEffect
GrayscaleEffect.fx
GrayscaleEffect.ps
Extensions
Imaging
Extensions
Windows
DataWindow
TipOfTheDay
Local.testsettings
Settings.StyleCop
TraceAndTestImpact.testsettings
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="StyleHelper.cs" company="Catel development team">
//   Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
//   Sets the available pixel shader modes of Catel.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Resources;
using System.Xml;
using Catel.Windows.Properties;
using log4net;

#if !SILVERLIGHT
using System.Windows.Markup;
using Ricciolo.StylesExplorer.MarkupReflection;
#endif

namespace Catel.Windows
{
    #region Enums
    /// <summary>
    /// Sets the available pixel shader modes of Catel.
    /// </summary>
    public enum PixelShaderMode
    {
        /// <summary>
        /// Disable all pixel shaders.
        /// </summary>
        Off,

        /// <summary>
        /// Automatically determine the best option.
        /// </summary>
        Auto,

        /// <summary>
        /// Use hardware for the pixel shaders.
        /// </summary>
        Hardware,

        /// <summary>
        /// Use software for the pixel shaders.
        /// </summary>
        Software
    }
    #endregion

    /// <summary>
    /// Helper class for WPF styles and themes.
    /// </summary>
    public static class StyleHelper
    {
        #region Constants
        /// <summary>
        /// Prefix of a default style key.
        /// </summary>
        private const string DefaultKeyPrefix = "Default";

        /// <summary>
        /// Postfix of a default style key.
        /// </summary>
        private const string DefaultKeyPostfix = "Style";
        #endregion

        #region Variables
        /// <summary>
        /// The <see cref="ILog">log</see> object.
        /// </summary>
        private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

#if !SILVERLIGHT
        /// <summary>
        /// Cached decompiled XAML resource dictionaries.
        /// </summary>
        private static readonly Dictionary<Uri, XmlDocument> _resourceDictionaryCache = new Dictionary<Uri, XmlDocument>();

        /// <summary>
        /// Cached types of <see cref="FrameworkElement"/> belonging to the string representation of the type.
        /// </summary>
        private static readonly Dictionary<string, Type> _styleToFrameworkElementTypeCache = new Dictionary<string, Type>();
#endif
        #endregion

        #region Properties
        /// <summary>
        /// This property allows you to disable all pixel shaders in Catel.
        /// <para />
        /// By default, all pixel shaders are enabled.
        /// </summary>
        public static PixelShaderMode PixelShaderMode = PixelShaderMode.Auto;
        #endregion

#if !SILVERLIGHT
        /// <summary>
        /// Ensures that an application instance exists and the styles are applied to the application. This method is extremely useful
        /// to apply when WPF is hosted (for example, when loaded as plugin of a non-WPF application).
        /// </summary>
        /// <exception cref="ArgumentNullException">when <paramref name="applicationResourceDictionary"/> is <c>null</c>.</exception>
        public static void EnsureApplicationResourcesAndCreateStyleForwarders(Uri applicationResourceDictionary)
        {
            if (applicationResourceDictionary == null)
            {
                throw new ArgumentNullException("applicationResourceDictionary");
            }

            if (Application.Current == null)
            {
                try
                {
                    new Application();
                    Application.Current.Resources.MergedDictionaries.Add(Application.LoadComponent(applicationResourceDictionary) as ResourceDictionary);

                    CreateStyleForwardersForDefaultStyles(Application.Current.Resources);

                    // Create an invisible dummy window to make sure that this is the main window
                    Window dummyMainWindow = new Window();
                    dummyMainWindow.Visibility = Visibility.Hidden;
                }
                catch (Exception ex)
                {
                    Log.Error(ex, TraceMessages.EnsureApplicationResourcesFailed);
                }
            }
        }
#endif

        /// <summary>
        /// Creates style forwarders for default styles. This means that all styles found in the theme that are
        /// name like Default[CONTROLNAME]Style (i.e. "DefaultButtonStyle") will be used as default style for the
        /// control.
        /// This method will use the current application (<see cref="System.Windows.Application.Current"/> to retrieve
        /// the resources. The forwarders will be written to the same dictionary.
        /// </summary>
        public static void CreateStyleForwardersForDefaultStyles()
        {
            CreateStyleForwardersForDefaultStyles(Application.Current.Resources);
        }

        /// <summary>
        /// Creates style forwarders for default styles. This means that all styles found in the theme that are
        /// name like Default[CONTROLNAME]Style (i.e. "DefaultButtonStyle") will be used as default style for the
        /// control.
        /// This method will use the passed resources, but the forwarders will be written to the same dictionary as
        /// the source dictionary.
        /// </summary>
        /// <param name="sourceResources">Resource dictionary to read the keys from (thus that contains the default styles).</param>
        public static void CreateStyleForwardersForDefaultStyles(ResourceDictionary sourceResources)
        {
            CreateStyleForwardersForDefaultStyles(sourceResources, sourceResources);
        }

        /// <summary>
        /// Creates style forwarders for default styles. This means that all styles found in the theme that are 
        /// name like Default[CONTROLNAME]Style (i.e. "DefaultButtonStyle") will be used as default style for the
        /// control.
        /// <para />
        /// This method will use the passed resources.
        /// </summary>
        /// <param name="sourceResources">Resource dictionary to read the keys from (thus that contains the default styles).</param>
        /// <param name="targetResources">Resource dictionary where the forwarders will be written to.</param>
        public static void CreateStyleForwardersForDefaultStyles(ResourceDictionary sourceResources, ResourceDictionary targetResources)
        {
            CreateStyleForwardersForDefaultStyles(sourceResources, sourceResources, targetResources, false);
        }

        /// <summary>
        /// Creates style forwarders for default styles. This means that all styles found in the theme that are
        /// name like Default[CONTROLNAME]Style (i.e. "DefaultButtonStyle") will be used as default style for the
        /// control.
        /// This method will use the passed resources.
        /// </summary>
        /// <param name="rootResourceDictionary">The root resource dictionary.</param>
        /// <param name="sourceResources">Resource dictionary to read the keys from (thus that contains the default styles).</param>
        /// <param name="targetResources">Resource dictionary where the forwarders will be written to.</param>
        /// <param name="forceForwarders">if set to <c>true</c>, styles will not be completed but only forwarders are created.</param>
        /// <exception cref="ArgumentNullException">when <paramref name="rootResourceDictionary"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="sourceResources"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="targetResources"/> is <c>null</c>.</exception>
        public static void CreateStyleForwardersForDefaultStyles(ResourceDictionary rootResourceDictionary, ResourceDictionary sourceResources,
            ResourceDictionary targetResources, bool forceForwarders)
        {
            if (rootResourceDictionary == null)
            {
                throw new ArgumentNullException("rootResourceDictionary");
            }

            if (sourceResources == null)
            {
                throw new ArgumentNullException("sourceResources");
            }

            if (targetResources == null)
            {
                throw new ArgumentNullException("targetResources");
            }

            #region If forced, use old mechanism
            if (forceForwarders)
            {
                // Get all keys from this resource dictionary
                var keys = (from key in sourceResources.Keys as ICollection<object>
                            where key is string &&
                                  ((string)key).StartsWith(DefaultKeyPrefix, StringComparison.InvariantCulture) &&
                                  ((string)key).EndsWith(DefaultKeyPostfix, StringComparison.InvariantCulture)
                            select key).ToList();

                foreach (string key in keys)
                {
                    Style style = sourceResources[key] as Style;
                    if (style != null)
                    {
                        Type targetType = style.TargetType;
                        if (targetType != null)
                        {
                            try
                            {
#if SILVERLIGHT
                                Style styleForwarder = new Style(targetType);
                                styleForwarder.BasedOn = style;
#else
                                Style styleForwarder = new Style(targetType, style);
#endif
                                targetResources.Add(targetType, styleForwarder);
                            }
                            catch (Exception ex)
                            {
                                Log.Warn(ex, TraceMessages.FailedToCreateStyleForwarder, key);
                            }
                        }
                    }
                }

                foreach (ResourceDictionary resourceDictionary in sourceResources.MergedDictionaries)
                {
                    CreateStyleForwardersForDefaultStyles(rootResourceDictionary, resourceDictionary, targetResources, forceForwarders);
                }
                
                return;
            }
            #endregion

            List<Style> defaultStyles = FindDefaultStyles(sourceResources);

            foreach (Style defaultStyle in defaultStyles)
            {
                try
                {
                    Type targetType = defaultStyle.TargetType;
                    if (targetType != null)
                    {
                        ResourceDictionary resourceDictionaryDefiningStyle = FindResourceDictionaryDeclaringType(targetResources, targetType);
                        if (resourceDictionaryDefiningStyle != null)
                        {
                            Log.Debug(TraceMessages.CompletingStyleInfo, targetType);

                            resourceDictionaryDefiningStyle[targetType] = CompleteStyleWithAdditionalInfo(resourceDictionaryDefiningStyle[targetType] as Style, defaultStyle);
                        }
                        else
                        {
                            Log.Debug(TraceMessages.CannotFindStyleDefinitionCreatingForwarder, targetType);

#if SILVERLIGHT
                            var targetStyle = new Style(targetType);
                            targetStyle.BasedOn = defaultStyle;
                            targetResources.Add(targetType, targetStyle);
#else
                            targetResources.Add(targetType, new Style(targetType, defaultStyle));
#endif
                        }
                    }
                }
                catch (Exception)
                {
                    Log.Warn(TraceMessages.FailedToCompleteStyle, defaultStyle);
                }
            }

#if !SILVERLIGHT
            RecreateDefaultStylesBasedOnTheme(rootResourceDictionary, targetResources);
#endif
        }

        /// <summary>
        /// Finds the <see cref="ResourceDictionary"/> declaring the real style for the target type.
        /// </summary>
        /// <param name="rootResourceDictionary">The root resource dictionary.</param>
        /// <param name="targetType">Type of the target.</param>
        /// <returns><see cref="ResourceDictionary"/> in which the style is defined, or <c>null</c> if not found.</returns>
        /// <exception cref="ArgumentNullException">when <paramref name="rootResourceDictionary"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="targetType"/> is <c>null</c>.</exception>
        private static ResourceDictionary FindResourceDictionaryDeclaringType(ResourceDictionary rootResourceDictionary, Type targetType)
        {
            if (rootResourceDictionary == null)
            {
                throw new ArgumentNullException("rootResourceDictionary");
            }

            if (targetType == null)
            {
                throw new ArgumentNullException("targetType");
            }

            var styleKey = (from key in rootResourceDictionary.Keys as ICollection<object>
                            where key == targetType
                            select key).FirstOrDefault();
            if (styleKey != null)
            {
                return rootResourceDictionary;
            }

            foreach (ResourceDictionary mergedResourceDictionary in rootResourceDictionary.MergedDictionaries)
            {
                var foundResourceDictionary = FindResourceDictionaryDeclaringType(mergedResourceDictionary, targetType);
                if (foundResourceDictionary != null)
                {
                    return foundResourceDictionary;
                }
            }

            return null;
        }

        /// <summary>
        /// Finds all the the default styles definitions 
        /// </summary>
        /// <param name="sourceResources">The source resources.</param>
        /// <returns></returns>
        private static List<Style> FindDefaultStyles(ResourceDictionary sourceResources)
        {
            List<Style> styles = new List<Style>();

            var keys = from key in sourceResources.Keys as ICollection<object>
                       where key is string &&
                             ((string)key).StartsWith(DefaultKeyPrefix, StringComparison.InvariantCulture) &&
                             ((string)key).EndsWith(DefaultKeyPostfix, StringComparison.InvariantCulture)
                       select key;

            foreach (string key in keys)
            {
                try
                {
                    Style style = sourceResources[key] as Style;
                    if (style != null)
                    {
                        styles.Add(style);
                    }
                }
                catch (Exception ex)
                {
                    Log.Warn(ex, TraceMessages.FailedToAddDefaultStyleToDefaultStylesList, key);
                }
            }

            foreach (ResourceDictionary resourceDictionary in sourceResources.MergedDictionaries)
            {
                styles.AddRange(FindDefaultStyles(resourceDictionary));
            }

            return styles;
        }

        /// <summary>
        /// Completes a style with additional info.
        /// </summary>
        /// <param name="style">The style.</param>
        /// <param name="styleWithAdditionalInfo">The style with additional info.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">when <paramref name="style"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="styleWithAdditionalInfo"/> is <c>null</c>.</exception>
        private static Style CompleteStyleWithAdditionalInfo(Style style, Style styleWithAdditionalInfo)
        {
            if (style == null)
            {
                throw new ArgumentNullException("style");
            }

            if (styleWithAdditionalInfo == null)
            {
                throw new ArgumentNullException("styleWithAdditionalInfo");
            }

            Style newStyle = new Style(style.TargetType);

            #region Copy style with additional info
            foreach (Setter setter in styleWithAdditionalInfo.Setters)
            {
                newStyle.Setters.Add(setter);
            }

#if !SILVERLIGHT
            foreach (Trigger trigger in styleWithAdditionalInfo.Triggers)
            {
                newStyle.Triggers.Add(trigger);
            }
#endif
            #endregion

            #region Copy original style
            foreach (Setter setter in style.Setters)
            {
                bool exists = (from styleSetter in newStyle.Setters
                               where ((Setter)styleSetter).Property == setter.Property
                               select styleSetter).Any();
                if (!exists)
                {
                    newStyle.Setters.Add(setter);
                }
            }

#if !SILVERLIGHT
            foreach (Trigger trigger in style.Triggers)
            {
                newStyle.Triggers.Add(trigger);
            }
#endif
            #endregion

            return newStyle;
        }

#if !SILVERLIGHT
        /// <summary>
        /// Recreates the default styles based on theme.
        /// </summary>
        /// <param name="rootResourceDictionary">The root resource dictionary.</param>
        /// <param name="resources">The resources to fix.</param>
        /// <exception cref="ArgumentNullException">when <paramref name="rootResourceDictionary"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="resources"/> is <c>null</c>.</exception>
        /// <remarks>
        /// This method is introduced due to the lack of the ability to use DynamicResource for the BasedOn property when
        /// defining styles inside a derived theme.
        /// </remarks>
        private static void RecreateDefaultStylesBasedOnTheme(ResourceDictionary rootResourceDictionary, ResourceDictionary resources)
        {
            if (rootResourceDictionary == null)
            {
                throw new ArgumentNullException("rootResourceDictionary");
            }

            if (resources == null)
            {
                throw new ArgumentNullException("resources");
            }

            var keys = (from key in resources.Keys as ICollection<object>
                        where key is string &&
                              ((string)key).StartsWith(DefaultKeyPrefix, StringComparison.InvariantCulture) &&
                              ((string)key).EndsWith(DefaultKeyPostfix, StringComparison.InvariantCulture)
                        select key).ToList();

            foreach (string key in keys)
            {
                Style style = resources[key] as Style;
                if (style == null)
                {
                    continue;
                }

                Type basedOnType = FindFrameworkElementStyleIsBasedOn(resources.Source, key);
                if (basedOnType == null)
                {
                    continue;
                }

                resources[key] = CloneStyleIfBasedOnControl(rootResourceDictionary, style, basedOnType);
            }

            foreach (ResourceDictionary resourceDictionary in resources.MergedDictionaries)
            {
                RecreateDefaultStylesBasedOnTheme(rootResourceDictionary, resourceDictionary);
            }
        }
#endif

        /// <summary>
        /// Clones a style when the style is based on a control.
        /// </summary>
        /// <param name="rootResourceDictionary">The root resource dictionary.</param>
        /// <param name="style">The style.</param>
        /// <param name="basedOnType">Type which the style is based on.</param>
        /// <returns><see cref="Style"/>.</returns>
        /// <exception cref="ArgumentNullException">when <paramref name="rootResourceDictionary"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="style"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="basedOnType"/> is <c>null</c>.</exception>
        /// <remarks>
        /// This method is introduced due to the lack of the ability to use DynamicResource for the BasedOn property when
        /// defining styles inside a derived theme.
        /// Should be used in combination with the <see cref="RecreateDefaultStylesBasedOnTheme"/> method.
        /// </remarks>
        private static Style CloneStyleIfBasedOnControl(ResourceDictionary rootResourceDictionary, Style style, Type basedOnType)
        {
            if (rootResourceDictionary == null)
            {
                throw new ArgumentNullException("rootResourceDictionary");
            }

            if (style == null)
            {
                throw new ArgumentNullException("style");
            }

            if (basedOnType == null)
            {
                throw new ArgumentNullException("basedOnType");
            }

#if SILVERLIGHT
            Style newStyle = new Style(style.TargetType);
            newStyle.BasedOn = rootResourceDictionary[basedOnType] as Style;
#else
            Style newStyle = new Style(style.TargetType, rootResourceDictionary[basedOnType] as Style);
#endif

            foreach (SetterBase setter in style.Setters)
            {
                newStyle.Setters.Add(setter);
            }

#if !SILVERLIGHT
            foreach (TriggerBase trigger in style.Triggers)
            {
                newStyle.Triggers.Add(trigger);
            }
#endif

            return newStyle;
        }

#if !SILVERLIGHT
        /// <summary>
        /// Finds the <see cref="FrameworkElement"/> a specific style is based on.
        /// </summary>
        /// <param name="resourceDictionaryUri">The resource dictionary URI.</param>
        /// <param name="styleKey">The style key.</param>
        /// <returns>
        /// 	<see cref="Type"/> or <c>null</c> if the style is not based on a <see cref="FrameworkElement"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">when <paramref name="resourceDictionaryUri"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentNullException">when <paramref name="styleKey"/> is <c>null</c>.</exception>
        /// <remarks>
        /// This method is introduced due to the lack of the ability to use DynamicResource for the BasedOn property when
        /// defining styles inside a derived theme.
        /// Should be used in combination with the <see cref="RecreateDefaultStylesBasedOnTheme"/> method.
        /// </remarks>
        private static Type FindFrameworkElementStyleIsBasedOn(Uri resourceDictionaryUri, string styleKey)
        {
            if (resourceDictionaryUri == null)
            {
                throw new ArgumentNullException("resourceDictionaryUri");
            }

            if (styleKey == null)
            {
                throw new ArgumentNullException("styleKey");
            }

            if (_styleToFrameworkElementTypeCache.ContainsKey(styleKey))
            {
                return _styleToFrameworkElementTypeCache[styleKey];
            }

            try
            {
                XmlDocument doc;

                if (_resourceDictionaryCache.ContainsKey(resourceDictionaryUri))
                {
                    doc = _resourceDictionaryCache[resourceDictionaryUri];
                }
                else
                {
                    StreamResourceInfo streamResourceInfo = Application.GetResourceStream(resourceDictionaryUri);
                    XmlBamlReader reader = new XmlBamlReader(streamResourceInfo.Stream);

                    doc = new XmlDocument();
                    doc.Load(reader);

                    _resourceDictionaryCache.Add(resourceDictionaryUri, doc);
                }

                #region Create xml namespace manager
                // Create namespace manager (all namespaces are required)
                XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(doc.NameTable);
                foreach (XmlAttribute namespaceAttribute in doc.DocumentElement.Attributes)
                {
                    // Clean up namespace (remove xmlns prefix)
                    string xmlNamespace = namespaceAttribute.Name.Replace("xmlns", "").TrimStart(new char[] { ':' });
                    xmlNamespaceManager.AddNamespace(xmlNamespace, namespaceAttribute.Value);
                }

                // Add a dummy node
                xmlNamespaceManager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
                xmlNamespaceManager.AddNamespace("ctl", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
                #endregion

                string xpath = string.Format("/ctl:ResourceDictionary/ctl:Style[@x:Key='{0}']/@BasedOn", styleKey);
                XmlAttribute xmlAttribute = doc.SelectSingleNode(xpath, xmlNamespaceManager) as XmlAttribute;
                if (xmlAttribute == null)
                {
                    Log.Warn(TraceMessages.StyleDoesNotHaveBasedOnAttributeDefined, styleKey);

                    _styleToFrameworkElementTypeCache.Add(styleKey, null);

                    return null;
                }

                string basedOnValue = xmlAttribute.Value;
                basedOnValue = basedOnValue.Replace("StaticResource", "");
                basedOnValue = basedOnValue.Replace("x:Type", "").Trim(new[] { ' ', '{', '}' });

                #region Create xml type mapper
                XamlTypeMapper xamlTypeMapper = new XamlTypeMapper(new[] { "PresentationFramework" });
                foreach (XmlAttribute namespaceAttribute in doc.DocumentElement.Attributes)
                {
                    string xmlNamespace = namespaceAttribute.Name.Replace("xmlns", "").TrimStart(new char[] { ':' });

                    string value = namespaceAttribute.Value;
                    string clrNamespace = value;
                    string assemblyName = string.Empty;

                    if (clrNamespace.StartsWith("clr-namespace:"))
                    {
                        // We have a hit (formatting is normally one of the 2 below):
                        // * clr-namespace:[NAMESPACE]
                        // * clr-namespace:[NAMESPACE];assembly=[ASSEMBLY]
                        if (clrNamespace.Contains(";"))
                        {
                            clrNamespace = clrNamespace.Split(new char[] { ';' })[0];
                        }
                        clrNamespace = clrNamespace.Replace("clr-namespace:", "");

                        if (value.Contains(";"))
                        {
                            assemblyName = value.Split(new char[] { ';' })[1].Replace("assembly:", "");
                        }

                        xamlTypeMapper.AddMappingProcessingInstruction(xmlNamespace, clrNamespace, assemblyName);
                    }
                }
                #endregion

                string[] splittedType = basedOnValue.Split(new[] { ':' });
                string typeNamespace = (splittedType.Length == 2) ? splittedType[0] : "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
                string typeName = (splittedType.Length == 2) ? splittedType[1] : splittedType[0];
                Type type = xamlTypeMapper.GetType(typeNamespace, typeName);
                if (type == null)
                {
                    _styleToFrameworkElementTypeCache.Add(styleKey, null);
                    return null;
                }

                Log.Debug(TraceMessages.StyleIsBasedOnType, styleKey, type);

                if ((type == typeof(FrameworkElement)) || type.IsSubclassOf(typeof(FrameworkElement)))
                {
                    _styleToFrameworkElementTypeCache.Add(styleKey, type);
                    return type;
                }

                Log.Warn(TraceMessages.TypeIsNotAFrameworkElementType, type);

                _styleToFrameworkElementTypeCache.Add(styleKey, null);
                return null;
            }
            catch (Exception ex)
            {
                Log.Error(ex, TraceMessages.FailedToFindFrameworkElementWhereStyleIsBasedOn, styleKey);
                return null;
            }
        }
#endif
    }
}

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)

Share

About the Author

Geert van Horrik
Software Developer CatenaLogic
Netherlands Netherlands
I am Geert van Horrik, and I have studied Computer Science in the Netherlands.
 
I love to write software using .NET (especially the combination of WPF and C#). I am also the lead developer of Catel, an open-source application development framework for WPF, Silverlight, WP7 and WinRT with the focus on MVVM.
 
I have my own company since January 1st 2007, called CatenaLogic. This company develops commercial and non-commercial software.
 
To download (or buy) applications I have written, visit my website: http://www.catenalogic.com
Follow on   Twitter

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 28 Jan 2011
Article Copyright 2011 by Geert van Horrik
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid