Click here to Skip to main content
13,259,539 members (53,743 online)
Click here to Skip to main content
Add your own
alternative version

Stats

3.5K views
71 downloads
3 bookmarked
Posted 23 May 2017

MVVM Auto ViewModelLocator

Rate this:
Please Sign up or sign in to vote.
Faster and easy way for generated ViewModel class

Introduction

I will present a little trick inside of the ViewModels instantiation in MVVM pattern.

Sometimes, we work in a WPF small solutions in which isn’t usually needed the ViewModelLocator class as ViewModels class generator, because we don’t need save the ViewModels reference. We will not worry about feeding the ViewModelLocator class and we will go to deploy our ViewModels classes immediately. This fits perfectly with the unit tests and binding engine.

Background

We will have two cases:

  • The View name and the ViewModel name have a equivalents names:

SameNameClass[View].xaml

SameNameClass[ViewModel].cs

  • The View name and the ViewModel name don’t have a equivalents names:

DiferentNameView.xaml

DiferentNameViewModel.cs

Equivalents Names (View and ViewModel)

In this case, only config one property in the view:

<Window x:Class="AutoMVVMLocator.Example1View"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:AutoMVVMLocator"

        local:MLMVVM.IsAutomaticLocator="True"

        mc:Ignorable="d"

        Title="Example1View" Height="300" Width="300">

The important part is:

local:MLMVVM.IsAutomaticLocator = "True"

In this example, the view Example1View instances an Example1ViewModel object as DataContext automatically.

Not Equivalents Names (View and ViewModel)

In this case, we need specify another property with the name of ViewModel class.

<Window x:Class="AutoMVVMLocator.Example2Window"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:AutoMVVMLocator"

        local:MLMVVM.ViewModelClassName="Example2ViewModel"

        local:MLMVVM.IsAutomaticLocator="True"

        mc:Ignorable="d"

        Title="Example2Window" Height="300" Width="396.546">

The important part:

local:MLMVVM.ViewModelClassName = "Example2ViewModel"
local:MLMVVM.IsAutomaticLocator = "True"

Note: The property ViewModelClassName has to be in first place.

In this example, the view Example2Window instances an Example2ViewModel object as DataContext automatically.

MLMVVM Class

It is a very simple class. It has two AtachProperties and two private methods.

The attachproperties are the previous configured properties:

  • IsAutomaticLocator - Activated the automatic instance ViewModels classes.
  • ViewModelClassName - Show the ViewModel class name to instance. If your ViewModelClass name is equivalent with the View name, its property isn’t necessary.
public static bool GetIsAutomaticLocator(DependencyObject obj)
{
    return (bool)obj.GetValue(IsAutomaticLocatorProperty);
}

public static void SetIsAutomaticLocator(DependencyObject obj, bool value)
{
    obj.SetValue(IsAutomaticLocatorProperty, value);
}

public static readonly DependencyProperty IsAutomaticLocatorProperty =
    DependencyProperty.RegisterAttached("IsAutomaticLocator", 
    typeof(bool), typeof(MLMVVM), new PropertyMetadata(false, IsAutomaticLocatorChanged));

private static void IsAutomaticLocatorChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var callOwner = d as FrameworkElement;

    var className = GetViewModelClassName(d);

    var userControl = GetInstanceOf(callOwner.GetType(), className);

    callOwner.DataContext = userControl;
}


public static string GetViewModelClassName(DependencyObject obj)
{
    return (string)obj.GetValue(ViewModelClassNameProperty);
}

public static void SetViewModelClassName(DependencyObject obj, string value)
{
    obj.SetValue(ViewModelClassNameProperty, value);
}


public static readonly DependencyProperty ViewModelClassNameProperty =

    DependencyProperty.RegisterAttached("ViewModelClassName", 
    typeof(string), typeof(MLMVVM), new PropertyMetadata(null));

The two private’s methods contains a dynamic instance engine:

private static object GetInstanceOf(Type dependencyPropertyType, string className)
{
    var assembly = dependencyPropertyType.Assembly;

    var assemblyTypes = assembly.GetTypes();

    var classNameDef = GetClassName(dependencyPropertyType, className);

    var userControlType = assemblyTypes.FirstOrDefault(a => a.Name.Contains(classNameDef));

    if (userControlType == null) 
    throw new ArgumentException($"Not exist a type 
    {classNameDef} in the assembly {assembly.FullName}");

    var resultado = Activator.CreateInstance(userControlType);

    return resultado;
}

private static string GetClassName(Type dependencyPropertyType, string className)

{
    if (string.IsNullOrWhiteSpace(className)) 
    return $"{dependencyPropertyType.Name}Model";

    return className;
}

Limitations

If you work on a great project, or you need to recover the references of instances ViewModels, you must use a classical ViewModelLocator class.

Test Project

In the test project, we have the code and example for all cases.

License

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

Share

About the Author

Juan Francisco Morales Larios
Software Developer (Senior) Cecabank
Spain Spain
MAP Microsoft Active Professional 2014

MCPD - Designing and Developing Windows Applications .NET Framework 4
MCTS - Windows Applications Development .NET Framework 4
MCTS - Accessing Data Development .NET Framework 4
MCTS - WCF Development .NET Framework 4

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.171114.1 | Last Updated 24 May 2017
Article Copyright 2017 by Juan Francisco Morales Larios
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid