MVVM and “restricted” functionality

So, I am back with a new post after WAY too long. It got really busy around TechEd Aus and NZ, and I really thought and hoped that I could get back and become active again as soon as that was over. Unfortunately, pushing work in front of you doesn’t really clear it…so when I finally got back from Auckland, I had a whole pile of things to do…

Anyhow…enough with the excuses…get to the topic already! So the topic is how to handle commanding with “restricted” functionality. There is two things in that sentence that I want to clarify. With commanding, I mean move functionality from the view into the viewmodel and removing as much code as possible from the code behind of the view. And with “restricted” functionality, I mean the type of functionality that cannot be handled anywhere but in the code behind of the view…

So what kind of functionality is “restricted”. Well, it can be a lot of things. The most obvious example in Silverlight is the OpenFileDialog and SaveFileDialog. As well as requesting access to webcam and so on. Basically functionality that has to be user initiated. In Silverlight, user initiated means that it has to be handled in code behind…

It can also be functionality that is hard to handle in any other way. I have for example a WPF application on my other screen that has this kind of functionality. I needs to pass a HandleRef from the view to the ViewModel. I know…this sounds really off…but due to some video features, I need to do this…just trust me… And since there is no really good way of passing a HandleRef from the view to the ViewModel, I have to handle it by the use of code behind…

So how can this be solved. Well, there are several ways. Some more ugly than others…

The most obvious and least (at least by me) preferred way is shown in the following code

MyViewModel vm = DataContext as MyViewModel;
if (vm != null)
{
   vm.Handle = myHandleRef;
}

So why is this not good? Well…if you have to ask, you should probably go through the chapter about decoupling again. This couple the view 100% to the ViewModel. There is no way at all to change the VM without having to recode the view. This is bad…m’kay…

Another way, which is slightly better, is by the use of an interface

IHandleRefConsumer handleRefConsumer = DataContext as IHandleRefConsumer;
if (handleRefConsumer != null)
{
   handleRefConsumer.Handle = myHandleRef;
}

This decouples the view from the VM in quite a nice way. The only downside is the fact that I will not have to create an interface just for this simple little task. And in a bigger application, there might end up being loads of little interfaces like this. Having that said, it is still a good idea. Just remember to place the interface in a common assembly, instead of placing it in the VM assembly as you once again couple things…

My personal favourite is a bit cumbersome. It does mean a bit more code, but it does mean that we get the same separation that the rest of out bindings get. It means that the coupling is only by name of property.

private static DependencyProperty WindowHandleProperty = DependencyProperty.Register("WindowHandle", typeof(HandleRef), typeof(MyClass));

public MyControl()
{
    InitializeComponent();
    SetBinding(WindowHandleProperty , new Binding("WindowHandle") { Mode=TwoWay });
    this.Loaded += OnLoaded;
}

void OnLoaded(object sender, RoutedEventArgs e)
{
    WindowHandle= new HandleRef(MyPanel, MyPanel.Handle);
}

public HandleRef WindowHandle
{
    get { return (HandleRef)GetValue(WindowHandleProperty ); }
    set { SetValue(WindowHandleProperty , value); }
}

This last example does as I mentioned give us “complete” decoupling. It doesn’t care about what object we got as DataContext. The only thing it cares about there being a property named “WindowHandle” on the object. Just as any other binding we do. The only difference is that instead of setting the binding in XAML, we do it from the code behind.

All the previous examples used set a property, but it could just as well have called an ICommand. So for a SaveFileDialog in Silverlight, it would look something like this

private static DependencyProperty SaveFileProperty = DependencyProperty.Register("SaveFile", typeof(ICommand), typeof(MyClass));

public MyControl()
{
    InitializeComponent();
    SetBinding(WindowHandleProperty , new Binding("SaveFileCommand"));
}

void Save()
{
    SaveFileDialog dlg = new SaveFileDialog();
    if (dlg.Show() == true)
    {
        if (SaveFile != null)
            SaveFile.Execute(dlg.OpenFile());
    }
}

public ICommand SaveFile
{
    get { return (ICommand)GetValue(SaveFileProperty); }
    set { SetValue(SaveFileProperty, value); }
}

I want to mention that I wrote the above code in Live Writer without any documentation, so there might be some issues with it…sorry about that…

Anyhow…after a long break, I come back with something that might be obvious to a lot of people. But it is still something I get questions about quite frequently. Especially since there are quite a few scenarios that are “restricted”.

If you have any questions, I am usual available via the blog by adding a comment, or by sending me an e-mail by clicking “Contact” above…

Cheers!

Comments (4) -

How do you apply this to silverlight where MyControl is a UserControl ... HandleRef doesn't seem to exist in Silverlight

hello ... How do you do this in Silverlight?

Hi Peter!
The HandleRef example was not the best possible. it was from WPF. The post is about MVVM, and not only about Silverlight. The second example will work for Silverlight....

Comments are closed