I’m a longtime supporter of Laurent Bugnion’s MVVM Light Toolkit and I love using it together with my favorite IOC Container NInject, one of the most “boring” area is creating the class that exposes ViewModel instances in a design time way: the famous ViewModelLocator class.
Now that Silverlight5 has custom markup extensions I thought: what about using it to simplify View vs ViewModel lookup?

Here’s my attempt, let’s start with a simple ViewModel (nothing really new here, just to give you a complete scenario)

public class MyViewModel : ViewModelBase
{
private string message;

public MyViewModel()
{
this.SaveCommand = new RelayCommand(this.HandleCommand);
this.Message = "Go!";
}

public string Message
{
get
{
return this.message;
}

set
{
if (value != this.message)
{
this.message = value;
this.RaisePropertyChanged();
}
}
}

public RelayCommand SaveCommand { get; private set; }

private void HandleCommand()
{
MessageBox.Show("Saving...");
}
}
 
Let’s create our generic Provider, as you can see it inherits from NInject module (but you can also use your favorite IOC container)
public class ServiceProvider : NinjectModule
{
public ServiceProvider()
{
this.Kernel = new StandardKernel(this);
}

public override void Load()
{
this.Bind<MyViewModel>().ToSelf();
}
}
 
Now is time for our generic ViewModelLocator:
public class ViewModelLocator
{
private static ViewModelLocator instance;

public static ViewModelLocator Instance
{
get
{
if (instance == null)
{
instance = new ViewModelLocator();
}

return instance;
}
}

public ServiceProvider Resolver { get; set; }

public T Get<T>()
{
return this.Resolver.Kernel.Get<T>();
}
}
 
At startup we associate the provider to the ViewModelLocator:
public App()
{
ViewModelLocator.Instance.Resolver = new ServiceProvider();
InitializeComponent();
}

Finally the custom markup extension:
public class ViewModelProviderExtension : IMarkupExtension<object>
{
public string Type { get; set; }

public object ProvideValue(IServiceProvider serviceProvider)
{
if (this.Type != null)
{
IXamlTypeResolver xamlTypeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
Type type = xamlTypeResolver.Resolve(this.Type);
MethodInfo m = typeof(ViewModelLocator).GetMethod("Get").MakeGenericMethod(type);
return m.Invoke(ViewModelLocator.Instance, null);
}

return null;
}
}
 
Now pairing the View to related ViewModel is just a matter of writing something like:
<Grid x:Name="LayoutRoot"
DataContext="{my:ViewModelProvider Type=my:MyViewModel}"
Background="White">
<Button Content="{Binding Message}"
Height="40"
Command="{Binding SaveCommand}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="100" />
</Grid>
Since most of the part are generic, you can pack them in a library and reuse them, looks fine isn’t it? Winking smile
Unfortunately solution isn’t applicable yet Sad smile while everything is ok at runtime if you try to use Blend to bind UI elements to ViewModel properties here’s what you get:
image  
As you can see Blend (and Visual Studio too) doesn’t recognize the type applied at design time and instead inspects associated type (ViewModelProviderExtension in this case) so until this won’t be fixed my solution is nothing more than an example of Silverlight 5 custom markup extension since, for me, Blendability is a must, period.
 
While nothing more than a tentative I hope you enjoyed it anyway… Smile
 

venerdì 6 maggio 2011 11:56