<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Derik Whittaker : XAML, Ninject</title><link>http://devlicio.us/blogs/derik_whittaker/archive/tags/XAML/Ninject/default.aspx</link><description>Tags: XAML, Ninject</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Convention Based View Model Location using Ninject in a MVVM/Silverlight Application</title><link>http://devlicio.us/blogs/derik_whittaker/archive/2011/07/02/view-model-location-using-ninject-in-a-mvvm-silverlight-application.aspx</link><pubDate>Sat, 02 Jul 2011 11:23:53 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:67852</guid><dc:creator>Derik Whittaker</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/derik_whittaker/rsscomments.aspx?PostID=67852</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/derik_whittaker/commentapi.aspx?PostID=67852</wfw:comment><comments>http://devlicio.us/blogs/derik_whittaker/archive/2011/07/02/view-model-location-using-ninject-in-a-mvvm-silverlight-application.aspx#comments</comments><description>***** UPDATE *****   &lt;br /&gt;If you would like to see a video on this topic check out &lt;a href="http://dimecasts.net/Casts/CastDetails/194"&gt;Episode 194 @ Dimecasts.Net&lt;/a&gt;   &lt;br /&gt;*******************  &lt;p&gt;When building out a Silverlight application (or WPF application for that matter) the &lt;a href="http://en.wikipedia.org/wiki/Model_View_ViewModel"&gt;MVVM&lt;/a&gt; pattern is the pattern of choice for most projects I am aware of.&amp;#160; When using MVVM there is a sub pattern which is commonly used which is known as ViewModelLocator.&amp;#160; The ViewModelLocator concept basically tries to handle the repetitive task of coupling the View with its ViewModel but doing so in a way which removes any manual coding and it just ‘happens’.&lt;/p&gt;  &lt;p&gt;Now if you have done any research on the ViewModel Location I am sure you have run across countless other blog posts out there which explain how to implement in this code, and many of them are great.&amp;#160; In fact here are a few which helped me down the path of creating the code I am going to talk about in this post&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://johnpapa.net/simple-viewmodel-locator-for-mvvm-the-patients-have-left-the-asylum"&gt;Simple ViewModel Locator&lt;/a&gt; for MVVM by John Papa (this is the post which really kick started this pattern) &lt;/li&gt;    &lt;li&gt;Wiring up &lt;a href="http://blog.roboblob.com/tag/viewmodellocator/"&gt;ViewModel Locator&lt;/a&gt; w/ Silverlight &lt;/li&gt;    &lt;li&gt;MVVM and &lt;a href="http://geekswithblogs.net/bdiaz/archive/2010/03/31/kiss-and-tell---mvvm-and-the-viewmodellocator.aspx"&gt;ViewModel Location&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Another MVVM and &lt;a href="http://geekswithblogs.net/bdiaz/archive/2010/03/31/kiss-and-tell---mvvm-and-the-viewmodellocator.aspx"&gt;ViewModel Location&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt; has an implementation &lt;/li&gt;    &lt;li&gt;&lt;a href="http://mvvmlight.codeplex.com/"&gt;MVVMLight&lt;/a&gt; has an implementation &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;All of the above posts basically show how to implement this pattern in your application and from what I can tell all of them work and will do the job. However, none of those (minus the Caliburn.Micro) implementations fulfills the one requirement I want which is to totally remove the need to ‘wire’ the ViewModel up to your View if even via XAML.&amp;#160; I want to remove this wiring from the XAML because in my mind this still leaves me hard wiring the relationship rather than using convention based wiring.&amp;#160; One scenario in which the hard wiring could turn around and bite you is in the times where you rename the view and the view model.&amp;#160; If you fail to update your wiring code in XAML you will receive runtime errors.&lt;/p&gt;  &lt;p&gt;Here are a few examples:    &lt;br /&gt;John Papa’s Implementation&lt;/p&gt;  &lt;pre class="c-sharp" name="code"&gt;DataContext=&amp;quot;{Binding Source={StaticResource VMLocator}, Converter={StaticResource VMIndexerConverter}, ConverterParameter=MainPageViewModel}&amp;quot;&lt;/pre&gt;

&lt;p&gt;ViewModelLocator’s Implementation&lt;/p&gt;

&lt;pre class="c-sharp" name="code"&gt;    &amp;lt;UserControl.Resources&amp;gt;
        &amp;lt;ViewModels:EditUsersViewModelLocator x:Key=&amp;quot;viewModelLocator&amp;quot;  /&amp;gt;
    &amp;lt;/UserControl.Resources&amp;gt;
    &amp;lt;UserControl.DataContext&amp;gt;
        &amp;lt;Binding Source=&amp;quot;{StaticResource viewModelLocator}&amp;quot; Path=&amp;quot;ViewModel&amp;quot; /&amp;gt;
    &amp;lt;/UserControl.DataContext&amp;gt;&lt;/pre&gt;

&lt;p&gt;I wanted my implementation of toe ViewModelLocator pattern to NOT need to know anything about the actual View or the ViewModel either in the XAML or in the code behind.&amp;#160; What I wanted as the following:&lt;/p&gt;

&lt;pre class="c-sharp" name="code"&gt;DataContext=&amp;quot;{Binding Source={StaticResource VMLocator}, Converter={StaticResource VMIndexerConverter}}&amp;quot;&lt;/pre&gt;

&lt;p&gt;Now you may be looking at my XAML above and comparing it to the XAML from John Papa’s post and be thinking what is really different?&amp;#160; The difference is in this segment of code &lt;em&gt;ConverterParameter=MainPageViewModel &lt;/em&gt;In his example he ‘hard wires’ the ViewModel which is being used up to the page and I did not want to do that.&amp;#160; I wanted to use a standard naming convention (right, &lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;convention over configuration&lt;/a&gt;) and allow my locator to determine the ViewModel based on the current View.&lt;/p&gt;

&lt;p&gt;So how did I implement my ViewModelLocator pattern, well lets take a look.&lt;/p&gt;

&lt;p&gt;Code for ViewModelLocator&lt;/p&gt;

&lt;pre class="c-sharp" name="code"&gt;public class ViewModelLocator
{   
    private static readonly IDictionary&amp;lt;type, type&amp;gt; s_viewModelCache = new Dictionary&amp;lt;type, type&amp;gt;();
        
    public Type GetViewModelTypeForView( Type viewType )
    {
        var viewModelName = ResolveViewModelName(viewType.Name).ToLower();

        // We are try to cache the types in order to remove the assembly scan hit, this is optional of course and 
	// you may not want or need this
	// One thing to point out here is that this code ASSUMES that your view and viewmodel classes are in the 
	//  same assembly.  if this is not true for your project this code will not work as expected.  We made this
	//  assumption because it is true in our project
        var foundViewModelType = GetExistingTypeFromCache(viewType) ?? (from type in viewType.Assembly.GetExportedTypes()
                                                                        where viewModelName.Equals(type.Name.ToLower())
                                                                        select type).FirstOrDefault();
    
        // this will throw a custom exception type, you can use your own if you want
        if (foundViewModelType == null) { throw new ViewModelTypeNotResolvedException(viewModelName, viewType); }

        // Add the found view and viewModel to the cache
        AddToCache(viewType, foundViewModelType);

        return foundViewModelType;
    }

    private void AddToCache(Type viewType, Type foundViewModelType)
    {
        if (!s_viewModelCache.ContainsKey(viewType))
        {
            s_viewModelCache.Add(viewType, foundViewModelType);
        }
    }

    private Type GetExistingTypeFromCache( Type viewType )
    {
        if (s_viewModelCache.ContainsKey(viewType))
        {
            return s_viewModelCache[viewType];
        }

        return null;
    }

    private string ResolveViewModelName(string viewTypeName)
    {
        var asLowerViewTypeName = viewTypeName.ToLower();

	// ***** Below is OUR product&amp;#39;s current naming conventions, replace with your own if you want *****
        // check to see if the view ends w/ &amp;quot;View&amp;quot;
        if (asLowerViewTypeName.EndsWith(&amp;quot;view&amp;quot;))
        {
            return asLowerViewTypeName.Replace(&amp;quot;view&amp;quot;, &amp;quot;ViewModel&amp;quot;);
        }

        if (asLowerViewTypeName.EndsWith(&amp;quot;usercontrol&amp;quot;))
        {
            return asLowerViewTypeName.Replace(&amp;quot;usercontrol&amp;quot;, &amp;quot;ViewModel&amp;quot;);
        }

        if (asLowerViewTypeName.EndsWith(&amp;quot;childwindow&amp;quot;))
        {
            return asLowerViewTypeName.Replace(&amp;quot;childwindow&amp;quot;, &amp;quot;ViewModel&amp;quot;);
        }

        return string.Concat(viewTypeName, &amp;quot;ViewModel&amp;quot;);
    }

    public static IDictionary&amp;lt;type, type&amp;gt; ViewModelCache { get { return s_viewModelCache; } }
}&lt;/pre&gt;

&lt;p&gt;Code for IndexConverter&lt;/p&gt;

&lt;pre class="c-sharp" name="code"&gt;public class IndexerConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    {
        Contract.Requires&amp;lt;ArgumentNullException&amp;gt;(value != null);

        var locator = value as ViewModelLocator;

        Contract.Assume(locator != null,
                        string.Format(
                            &amp;quot;The provided converter value was expected to be of type {0} but was provided as type {1} which is not acceptable for this converter&amp;quot;,
                            typeof(ViewModelLocator).Name,
                            value.GetType().Name));

        var viewType = GetViewType();

        var viewModelType = locator.GetViewModelTypeForView(viewType);

	// We are using the ServiceLocator pattern which is wrapping Ninject
        var viewModelInstance = ServiceLocator.Current.GetInstance(viewModelType);

        return viewModelInstance;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
        
    // This does incur a perf hit by looking at the stack trace, but in 
    //  my opinion this hit is worth it compared to having to manually wire items up
    private Type GetViewType()
    {
        var stack = new StackTrace();

        return stack.GetFrames()
            .Select(f =&amp;gt; f.GetMethod())
            .Where(m =&amp;gt; m.Name == &amp;quot;InitializeComponent&amp;quot;)
            .Select(m =&amp;gt; m.DeclaringType)
            .FirstOrDefault();
    }

}&lt;/pre&gt;

&lt;p&gt;Code needed in your App.Xaml&lt;/p&gt;

&lt;pre class="c-sharp" name="code"&gt;&amp;lt;MVVMLib:ViewModelLocator x:Key=&amp;quot;VMLocator&amp;quot; /&amp;gt;
&amp;lt;MVVMLib:IndexerConverter x:Key=&amp;quot;VMIndexerConverter&amp;quot; /&amp;gt;&lt;/pre&gt;

&lt;p&gt;Code for the custom Exception ViewModelTypeNotResolvedException&lt;/p&gt;

&lt;pre class="c-sharp" name="code"&gt;public class ViewModelTypeNotResolvedException : Exception
{
    public string ViewModelName { get; set; }
    public Type ViewName { get; set; }

    // Commented this out because i do not want to be able to create this without the VMName or the VName
    //public ViewModelTypeNotResolvedException() {}

    /// 
    /// Will build an instance of the exception and push in a default message based on the viewModelname and view properties.
    /// *** This is the lazy way to create the message ***
    /// 
    /// &lt;param name="viewModelName" /&gt;The name of the viewModel which was not able to be created or found&lt;/param&gt;
    /// &lt;param name="view" /&gt;The type for the view we were trying to bind the VM to&lt;/param&gt;
    public ViewModelTypeNotResolvedException(string viewModelName, Type view)
        : base(string.Format(&amp;quot;When trying to resolve the view model {0} it was not found in the same assembly as the view {1}&amp;quot;, viewModelName, view.Name))
    {
        ViewModelName = viewModelName;
        ViewName = view;            
    }

    /// 
    /// Will build an instance of the exception
    /// 
    /// &lt;param name="viewModelName" /&gt;The name of the viewModel which was not able to be created or found&lt;/param&gt;
    /// &lt;param name="view" /&gt;The type for the view we were trying to bind the VM to&lt;/param&gt;
    /// &lt;param name="message" /&gt;&lt;/param&gt;
    public ViewModelTypeNotResolvedException(string viewModelName, Type view, string message) : base(message)
    {
        ViewModelName = viewModelName;
        ViewName = view;
    }

    /// 
    /// Will build an instance of the exception
    /// 
    /// &lt;param name="viewModelName" /&gt;The name of the viewModel which was not able to be created or found&lt;/param&gt;
    /// &lt;param name="view" /&gt;The type for the view we were trying to bind the VM to&lt;/param&gt;
    /// &lt;param name="message" /&gt;&lt;/param&gt;
    /// &lt;param name="innerException" /&gt;&lt;/param&gt;
    public ViewModelTypeNotResolvedException(string viewModelName, Type view, string message, Exception innerException)
        : base(message, innerException)
    {
        ViewModelName = viewModelName;
        ViewName = view;
    }
}&lt;/pre&gt;

&lt;p&gt;As you can see the code needed for this is not that complicated or difficult to implement.&amp;#160; &lt;/p&gt;

&lt;p&gt;One thing to understand with this post, I am NOT saying that the other implementations are bad or they do not work. In fact I am saying the exact opposite, they all are great and they all work and I used all their implementations as baseline for my implementation.&amp;#160; What I am saying as the other examples did not meet my EXACT needs. &lt;/p&gt;

&lt;p&gt;Please take a look at the code and let me know where I went wrong or what your thoughts are.&amp;#160; &lt;/p&gt;

&lt;p&gt;Till next time,&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=67852" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/derik_whittaker/archive/tags/Development/default.aspx">Development</category><category domain="http://devlicio.us/blogs/derik_whittaker/archive/tags/Best+Practice/default.aspx">Best Practice</category><category domain="http://devlicio.us/blogs/derik_whittaker/archive/tags/HowTo/default.aspx">HowTo</category><category domain="http://devlicio.us/blogs/derik_whittaker/archive/tags/XAML/default.aspx">XAML</category><category domain="http://devlicio.us/blogs/derik_whittaker/archive/tags/Silverlight/default.aspx">Silverlight</category><category domain="http://devlicio.us/blogs/derik_whittaker/archive/tags/Ninject/default.aspx">Ninject</category></item></channel></rss>