Showing posts with label Silverlight. Show all posts
Showing posts with label Silverlight. 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!");
}
}

Thursday, April 1, 2010

Tracking events with Rx in Silverlight

When you want to execute some code after multiple events have been completed, you don’t always know which event will be triggered first, you might have to synchronize them using some boiler plate logic.  This could, for example,  happen when you have to execute two service calls at the same time.

The solution for this problem comes with the Rx framework, the System.Reactive assembly found in the Silverlight Toolkit.

Image you have two events coming from “serviceProxy”, you could make them observable like this.

IObservable<Event<EventArgs>> observable1
    = Observable.FromEvent<RoutedEventArgs>(serviceProxy, "EventOne");

IObservable<Event<EventArgs>> observable2
    = Observable.FromEvent<EventArgs>(serviceProxy, "EventTwo");

You can execute the following Rx method to make sure only a composite event is triggered once both events have been triggered. 

IObservable<Event<EventArgs>> joinedObservable = observable1.ForkJoin(observable2);

To be able to now execute our event we can simply call the Subscribe method and execute a action of our choice :

joinedObservable.Subscribe( /* Some Method */ );

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.

Saturday, November 7, 2009

Silverlight Rx : System.Reactive

Yesterday I came across the System.Reactive assembly that is included with the Silverlight Toolkit.  On the blog of Jafar Husain

He has made a lot of posts about the Rx framework, and it is definitely interesting to read!

http://themechanicalbride.blogspot.com/2009/07/introducing-rx-linq-to-events.html

We can program in reaction to events and apply our logic on them. We could for example do some action only when an event is raised with a certain event argument. This embeds the Async handling of events and allows this code to be unit tested.

The big problem with asynchronous programming is that the code very quickly gets unreadable and hard to maintain, as it is not always clear how several events are linked to one another.

The Reactive framework works with the IObserver and the IObservable classes, which can be thought of as Reactive versions of IEnumerable in the context of Linq ( actually the extension methods have been added to the System.Linq namespace ).  You basically look at the events being thrown as a collection you can browse trough.

So how does it work.

To quickly show how we can use Rx to simplify our code, We will write an extension method that will call a web client's DownloadString method and return a String.

public static class WebClientExtender
{

public static IObservable<string> GetSite(this WebClient client, string url)
{
var downloaded = Observable.FromEvent<DownloadStringCompletedEventArgs>
                 (client, "DownloadStringCompleted");
client.DownloadStringAsync(new Uri(url));
return downloaded.Select(x=>((DownloadStringCompletedEventArgs)x.EventArgs).Result);
}

}

To call this we can now simple add the following line of code to our Silverlight application.

new WebClient().GetSite("http://localhost/").Subscribe(x => MessageBox.Show(x));

This way we can very easily clean up the code and structure how the Asynchronous events are handled.

Sunday, November 1, 2009

CollectionViewSource in Silverlight

What is CollectionViewSource

The CollectionViewSource is a class that is used in WPF to apply sorting and filtering on Data. We can also use this class in Silverlight 3.
I came across it while studying for my WPF exam and noticed it was also available in Silverlight. So naturally I had a look. It is very easy to use as I will demonstrate below.

So lets have a look.

In this case, we have List of Person we want be able to Filter and Sort correctly.

A person could be defined like this :

public class Person
{
public String FirstName { get; set; }
public String LastName { get; set; }
}

To be able to use a CollectionViewSource we can define it as a resource in our XAML, we could also define it in code, but for this example we will write most in XAML.

<UserControl.Resources>
<local:PersonDataSource key="data">
<CollectionViewSource Source="{Binding Source={StaticResource data}}" x:Key="CollVS">
<CollectionViewSource.SortDescriptions>
<ComponentModel:SortDescription Direction="Descending">
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</UserControl.Resources>

You see here that we defined a "data" datasource, we should create a class that will be able to store the information we need, lets call it PersonDataSource. We could also add some logic here to return some dummy data for now. For this example I chose to simply inherit from ObservableCollection and not add any additional logic, obviously you could use any collection here you would normally use to bind to a datagrid.

To finish our XAML UI, we add a DataGrid to display our data and a TextBox we can use for filtering. In our case we will apply filtering on the LastName.

<StackPanel Orientation="Vertical">
<data:DataGrid ItemsSource="{Binding Source={StaticResource CollVS}}"/>
<TextBox x:Name="filter"/>
</StackPanel>

Now we can define how we are going to do our filtering and make sure the filtering is visible in the User interface.

public MainPage()
{
InitializeComponent();
//Get the CollectionViewSource from the Resource of the UserControl
CollectionViewSource CollVS = (CollectionViewSource)Resources["CollVS"];
//Make sure we update the datagrid when we change our filter
filter.TextChanged += delegate { CollVS.View.Refresh(); };
//Subscribe to the filter event
CollVS.Filter += cvs_Filter;
}

void cvs_Filter(object sender, FilterEventArgs e)
{
e.Accepted = ((Person)e.Item).LastName.ToLower().StartsWith(filter.Text.ToLower());
}

So what did we do here ? First we needed to get our CollectionViewSource from our Resources. The most important thing here is that we do the following :

filter.TextChanged += delegate { CollVS.View.Refresh(); };

If we don't do this, our view will not update and we will not be able to see our filter.

To filter, we can change if an Item should be filtered by setting the Accepted property , the Filter will be called for every element in your collection.

The last step is to implement IComparable on our Person object , this is required by the CollectionViewSource to apply sorting on the Collection. The data will now be automatically sorted as it is filtered.