Showing posts with label MVVM. Show all posts
Showing posts with label MVVM. Show all posts

Wednesday, January 26, 2011

Auto-ViewModel binding with Ninject

I have done a lot of post about binding ViewModels to Views in Silverlight, so can you see that it is really a subject I am quite interested in.  It also allows me to learn more about several technologies all in the context of this domain.

Having said this, lets have a look at using Ninject for Injecting our ViewModels into our Views.  We are going to use the concept of a ViewModelLocator that will be hosting our Ninject kernel in the application scope.

This means we are going to host our Locator as a resource in our App.xaml resource dictionary and bind to it in our views, using the StaticResource as a source.

You would go about doing this as following, and reference it in your code
<Application.Resources> 
<Foo:ViewModelLocator x:Key="viewModelLocator"/>
</Application.Resources>

<UserControl DataContext="{Binding [Bar], Source={StaticResource viewModelLocator}}"/>

You can see that we have defined our ViewModel with the name ‘Bar’ and within square brackets, this means we are binding to an indexer of the ViewModelLocator.  This allows us to do some pretty cool stuff, on the expense of loosing Intelli-Sense.
So lets get started on writing our locator, we first start my setting up our class and initializing some Ninject stuff, creating the Kernel, adding modules,…
public class ViewModelLocator
{       
private readonly IKernel kernel;       
public ViewModelLocator()
{           
kernel = new StandardKernel(GetModules());           
kernel.Load();       
}
}

So the really cool thing we can do now, is create an indexer that will allow us the query our ViewModels setup in our Kernel dynamically without having to type it, and add a new Property for every ViewModel.

The indexer is pretty straightforward, it looks like this :
public object this[string viewModel]
{
get { return GetViewModel(viewModel); }
}

So as you could imagine, the real stuff goes on in the GetViewModel method, so lets have a quick look at that now, I'll explain what we are doing here afterwards.
private object GetViewModel(string viewModel)
{
String viewModelName = viewModel;
if (!viewModel.ToUpper().EndsWith("VIEWMODEL"))
{
viewModelName = viewModelName + "ViewModel";
}
return kernel.Get(GetViewModelType(viewModelName));
}

private Type GetViewModelType(string viewModelname)
{
foreach (string location in GetLocations())
{
Type type = Type.GetType(string.Format("{0}.{1}", location, viewModelname), false, true);
if (type != null)
return type;
}
return null;
}

When we are calling our “Bar” viewmodel, the GetViewModel method will get a string with the value '”Bar”, from this it will need to locate the ViewModel from our kernel which could have a whole bunch of dependency’s injected ( or should I say nInjected ) into it.

Our locator will will take into account a few conventions, it will check the ViewModel string ends with “ViewModel” and if not will append it.  It will then attempt to find the ViewModel Type and return the corresponding instance of that type from the Ninject kernel.

This is where our last convention comes into play, our ViewModels in our application will most likely be located on some very well defined locations (hence the GetLocations method). We can easily define these conventions and possibly even add new ones later, a simple convention for locations might look something like this :
 private IEnumerable GetLocations()
{
string applicationNamespace = GetType().Namespace;
yield return applicationNamespace;
yield return applicationNamespace + ".Shared";
yield return applicationNamespace + ".Shared.ViewModel";
yield return applicationNamespace + ".Views";
yield return applicationNamespace + ".Views.ViewModel";
}

So this way you can add ViewModels with Ninject without having to define any properties to bind to, you just have to type your ViewModel’s name and the locator will do the rest for you.

Tuesday, October 19, 2010

Automatic MVVM Command Binding

When working with MVVM it can be quite a lot of work to wire up all commands with the view, bind them and make sure the right method was called.

Furthermore, you would need a property in your ViewModel that would bind to the view, wouldn’t it be nice to just have some methods in your ViewModel that would just like that respond to the buttons you click.

I came across this technique while looking at a MIX talk by Rob Eisenberg. The following example is an easy to use simple framework. It allows you to implement this quickly.  And use it without needing to change a lot of your already in place MVVM screens.  It is based on a great MVVM framework that Rob has been working on : Caliburn , which definitely is worth a look.

The concept that we are working with here, is to have some convention in our application in regards to using ViewModels and Commands.  The convention in this example is that all methods used for handling commands start with “Execute” and end with “Command”.  This is a very intuitive way to write commands, and is actually the way I was declaring then before I started to use this setup.

Lets say for a moment, we want to create new MVVM screen using a ViewModel, in this example we want to declare our ViewModel inside our View by calling an extension method “Bind<TViewModel>()” and binding the ViewModel to it.  You could eventually extract this into a Bootstrapper or so… But for now we will just keep it this way.

Our first class to do this, is our Extension class called “MvvmBindingExtension”.  It accepts a TViewModel generic type and reflects all Command methods in it.  Then it binds them to the View so they can be invoked.

Lets have a look at the implementation of this extension.

public static class MvvmBindingExtension
{
private const string COMMAND_METHOD_PREFIX = "Execute";
private const string COMMAND_METHOD_SUFFIX = "Command";

/// <summary>
/// Bind a ViewModel to a View, and auto bind commands
/// </summary>
/// <typeparam name="TViewModel">The ViewModel that should be </typeparam>
/// <param name="element">The view we want to bind our viewmodel to</param>
public static void Bind<TViewModel>(this FrameworkElement view) where TViewModel : new()
{
//Create an instance of our viewModel
object viewModel = new TViewModel();

//Get the type of the viewmodel for reflection purposes.
Type viewModelType = viewModel.GetType();

//Get all command methods obbeying the convention we set up for command handler methods
IEnumerable<MethodInfo> commandMethods = viewModelType.GetMethods()
.Where(method => method.Name.StartsWith(COMMAND_METHOD_PREFIX))
.Where(method => method.Name.EndsWith(COMMAND_METHOD_SUFFIX));

foreach (MethodInfo commandMethod in commandMethods)
{
//Make sure we get the right name of the method
int lengtOfSubString = commandMethod.Name.Length - COMMAND_METHOD_PREFIX.Length - COMMAND_METHOD_SUFFIX.Length;
string commandName = commandMethod.Name.Substring(COMMAND_METHOD_PREFIX.Length, lengtOfSubString);

//Get button by name
ButtonBase button = view.FindName(commandName) as ButtonBase;
if (button != null)
{
//Set binding to reflection command
button.SetBinding(ButtonBase.CommandProperty, new Binding { Source = new ReflectionCommand(commandMethod, viewModel) });
}
}
view.DataContext = viewModel;
}
}


You can see that we are using a “ReflectiveCommand” here,  this command takes the MethodInfo we have extracted from the ViewModel, and invokes it when executing the command on the ViewModel. 
We are binding this directly to the Source, so we don’t have to create any properties in our ViewModel to bind to.



public class ReflectionCommand : ICommand
{
private object target;
private MethodInfo method;

public ReflectionCommand(MethodInfo method, object target)
{
this.method = method;
this.target = target;
}

public bool CanExecute(object parameter)
{
return true;
}

public event EventHandler CanExecuteChanged;

public void Execute(object parameter)
{
method.Invoke(target, new[] { parameter });
}
}


This is command is then bound to a FrameworkElement that has the same name as the Command method without it’s PRE- and SUFFIX. So basically for a “Save” method this would be “ExecuteSaveCommand” where Save would then be set as the name of the element.



<Grid x:Name="LayoutRoot" Background="White">
<Button x:Name="Save" Content="Save"/>
</Grid>


Finally we would have a ViewModel that would look something like this, no more Command properties, no more RelayCommands being initialized. Just simply one public command method we can use.



  public class ViewModel
{
public void ExecuteSaveCommand(object parameter)
{
MessageBox.Show("Hello world!");
}
}

Tuesday, December 1, 2009

Creating a basic MVVM Application

In one of my previous post I mentioned MVVM ( or Model-View-ViewModel ) , so what exactly is the idea behind it, and more importantly, what are the advantages?

Separating UI from Business logic

The main problem with a Silverlight application is that you have a whole bunch of UI code intermingled with a bunch of Business logic.  This makes the whole application hard to understand, hard to debug and hard to test. We would like to have a way to avoid this. 

A solution to this problem is the concept of databinding in Silverlight, this allows us to loosely couple business Logic ( ViewModel )to our UI ( View ) and display the data we want ( Model ).

To allow interaction with our ViewModel, we would also require some functionalities to be bound to some UI components such as buttons.  For this we can use Commands,  Silverlight 3 provides by default the ICommand interface, and the PRISM framework has made an implementation of this so we can define commands on our FrameworkElement using attached properties. 

In Silverlight 4 there will be support for Commands out of the box for the ButtonBase and Hyperlink classes, so we will simply be able to bind to the Command property directly.

Setting it up

To make a MVVM application we will have to define a View and a ViewModel, a practice I like to use is to create two folders in our application to group our View’s and ViewModel’s so we have a clear view were our UI and our business logic is located.

As an example we will create a simple UI with a listbox and a button that will add quotes to it and display the data when the last quote was added.

The XAML for this view is straightforward :

<StackPanel Orientation="Vertical">
 <ListBox Height="150"/>
 <TextBlock />
 <Button Content="Add Quote"/>
</StackPanel>

Notice that I have not yet defined any databinding here, we will first create our ViewModel and map our binding to this afterwards.

A ViewModel that wants changes in it to be propagated to the UI should implement INotifyPropertyChanged this will provide a NotifyPropertyChanged event that will have to be invoked whenever a property in our ViewModel changes.  We will use an ObservableCollection to bind our quotes, to automatically trigger changes when we add new quotes.

This is the code for our ViewModel

public class ViewModel : INotifyPropertyChanged

    public ViewModel() 
   
        //Initialize our properties 
        Quotes = new ObservableCollection<string>(); 
        AddQuoteCommand = new DelegateCommand<object>(onAddQuoteCommandExecute); 
    }

    /// <summary> 
    /// Command that will be triggered when a button was clicked and will add a quote to the Quotes collection 
    /// </summary> 
    public DelegateCommand<object> AddQuoteCommand { get; set; }  

    /// <summary> 
    /// The list of Quotes we will bind to our listbox 
    /// </summary> 
    public ObservableCollection<String> Quotes { get; set; }  

    private DateTime lastModified; 
    /// <summary> 
    /// When was the list last modified 
    /// </summary> 
    public DateTime LastModified 
   
        get { return lastModified; }
        set 
       
            lastModified = value
            InvokePropertyChanged("LastModified"); 
       
    }  

    /// <summary> 
    /// When the AddQuoteCommand is triggered, it execute run this method 
    /// </summary> 
    private void onAddQuoteCommandExecute(object parameter) 
   
        //Add a generated quote 
        Quotes.Add(QuoteFactory.Generate());
        //Set the last modified date 
        LastModified = DateTime.Now; 
    }  

    public event PropertyChangedEventHandler PropertyChanged; 
    /// <summary> 
    /// Invoke that a property was changed 
    /// </summary> 
    /// <param name="propertyName">The propertyname</param> 
    private void InvokePropertyChanged(string propertyName) 
   
        if (PropertyChanged != null)
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    }

}

Now we can start binding our ViewModel to our View, there are a few ways you could to this, you could set the DataContext of the View in Code, or use dependency injection to initialize the ViewModel.  But for this example I will just define an instance of the ViewModel in the XAML of the View in its DataContext. Now we can simple add the databinding to our ListBox ,our TextBlock and bind the Command to the Button.  Silverlight will take care of the rest. 

<ListBox Height="150" ItemsSource="{Binding Quotes}"/>
<TextBlock Text="{Binding LastModified}" />
<Button Content="Add Quote" Commands:Click.Command="{Binding AddQuoteCommand}"/>

Conclusion

This example illustrates that setting up MVVM is not very difficult and allows for a nice separation of UI code and business logic.  You can, using MVVM, very easily define logic on several controls without having to write spaghetti code with events.  You would simply bind to the changing property in the UI ( e.g. a checkbox that is checked ) and have your View adapt to it accordingly because the setter in the ViewModel can very easily trigger business logic to occur.

There are however cases where you cannot, or very difficultly, achieve this.  You can not, for example, bind to a DependencyObject ( which is possible in WPF ). This will throw a XAML error in Silverlight 3.  However, in Silverlight 4 it will be possible to bind to a DependencyObject, making life a bit easier for people implementing MVVM.