Device-specific interaction logic in an MVVM application

Rudi Grobler recently posted an article called ‘Classic Jukebox‘ that shows how to build a jukebox application using custom hardware.  It’s a very cool idea, and his article is well worth reading.

This article reminds me of a problem that I was discussing with someone at work the other day, and have been thinking about since.  What are the best practices for designing an app, let’s say the Jukebox app, such that it can accomodate multiple form factors?  Suppose you wanted this app to be controlled by a custom input device, or a regular mouse + keyboard, or on a multi-touch device like Microsoft Surface, or an HP TouchSmart running Windows 7. 

Each form factor would bring along new, and potentially unique, interaction possibilities: Surface allows for multi-finger gestures, while a traditional keyboard allows for things like shortcut keys, etc.  How should the MVVM design be used/augmented to make the input processing device-specific, without convulting the core application logic (play next song, pause, lower volume, etc)?  Should there be an intermediary layer  between View and ViewModel, which is perhaps an InteractionModel, to which the device-specific View is bound?   This topic is something that I’m very interested in, so expect to see some more posts on it in the near future.

Food for thought…

22 Responses to Device-specific interaction logic in an MVVM application

  1. As I see it, the ViewModel *is* the intermediary layer between the view and the core application logic!

    One ViewModel supports one interaction model, which may be implemented (in whole or in part) by one or more views.

    So, if you have a totally different interaction model with which you don’t want to bloat your original ViewModel, it becomes a new ViewModel.

    Your core application logic (in this case, it looks like some API you might wrap up in a class called something like MediaSource) is clearly independent of that ViewModel.

    Isn’t that the whole point of MVVM?

    The unnecessary-extra-layer-of-indirection is a classic design antipattern and this smells strongly of that to me.

  2. Josh Smith says:

    I agree with you, Matthew. I think we’re talking about the same thing, with different words. The main idea is to separate the core application functionality, whether it resides in VM objects or not, from how the user can access it via the hardware.

    I introduced the idea of InteractionModel, which would be a ViewModel custom built for a specific interaction scenario. I think this idea has merit, but am still thinking about how to best implement it and make it easy to unit test.

    Thanks for your feedback.

  3. David Roh says:

    This may not be the best place for this but I know that if anyone knows the anwser to this, you will.🙂

    I believe that I understand and appreciate most of the MVVM feature with the exception of commanding (using ICommand – RelayCommand, DelegateCommand, etc.).
    I understand that the VM should not be aware of the View – makes good sense for testability; however, I don’t understand the need for using the RelayCommand or DelegateCommand.
    I understand that many purist insist on no code in the View’s code behind; however, I am a minimalist and a pragmatist so it’s okay🙂

    For the sake of this discussion, let’s ignore CanExecute.

    So why do we need ICommand? Since the View can have its DataContext set to the respective VM object why can we not simply implement an event handler in the View code behind and use the DataContext to call a command handler directly in the VM with a single line of code? What do I gain by adding the complexity of a RelayCommand or DelegateCommand (ignoring CanExecute)?

    The VM command handler can do just about anything needed on the View by just changing VM properties that the View has bound – the VM does not need and should not have a reference to the View.

    By using an event handler in the code behind I gain compile time checking of the control’s event name string attribute – I don’t believe that the RelayCommand or DelegateCommand provide compile time errors for mistakes in a controls command string attribute.

    In short, a single line direct call from an event handler in the View’s code behind:
    takes significantly less code to implement
    gives compile time checking
    I suppose that some may say that the View is now aware of the VM; however, it already is if it is using data binding to the VM.
    I am sure that there is something that I don’t understand so a short tutorial or reference on what I am missing would be appreciated.

    David Roh

  4. Josh Smith says:

    David. There are no rules. If you’d rather write code in your code-behind (which I’m not against either…it’s called the “code-behind” for a reason) then go for it.

    However, by following your line of reasoning, why not just write handlers for a ViewModel object’s PropertyChanged event and update the UI elements in code, instead of relying on binding? That way, you’d have more compile-time protection. 😛

    Josh

  5. David Nelson says:

    I agree with Matthew: this feels redundant. The whole point of the ViewModel is to serve as an indirection layer between the core application logic and the user’s interaction with that logic.

    You asked in the post, “Should there be an intermediary layer between View and ViewModel, which is perhaps an InteractionModel…?” But you said to Matthew, “I introduced the idea of InteractionModel, which would be a ViewModel custom built for a specific interaction scenario.” So now I’m not really sure what you are proposing here. The ViewModel IS custom-built for a specific interaction scenario. That is its reason for being.

  6. Josh Smith says:

    I don’t agree that the VM is supposed to be a layer of indirection between the View and core application logic. The VM can contain application logic, in fact, I usually find that it often contains most of my application logic. It does not, however, contain business/domain logic. So, it knows how to react to the user requesting the app to do something, and coordinate various things that need to occur to satisfy that request. But it shouldn’t know, say, how to calculate the location of a satellite in orbit. That’s for the domain objects to figure out.

    If I have an app where I need to have some basic UI features available on all form factors, I would want to reuse the VM classes that represent those features, as much as possible. If I need to support different interaction models to consume those UI features, I wouldn’t want to rewrite all of those VM classes just for a different form factor. I’d want to isolate what’s unique to that device/input technique and make it plug into my shared code.

  7. David Roh says:

    @Josh

    So where do you put the “business/domain” logic?

  8. Josh Smith says:

    David — I put “business/domain” logic in my “business/domain” objects.🙂

  9. David Roh says:

    Let me rephrase – why not put “how to calculate the location of a satellite in orbit” in a ViewModel. That is, depending upon the needs of the application, it might make sense to put domain logic in a ViewModel and it might not. I am looking for a reason that makes it bad design to have domain logic in a ViewModel.

    If there are many small VM’s, then I would think that the VM’s would not be a good place for domain logic; however, if the app has a main VM that most UI processing goes through, then why not have some domain logic in the VM?

  10. I’m new to the MVVM mindset, so please forgive, but:

    Isn’t the View the place for display/interaction variation? Given your situation, I would probably create a set of views that all bound to the same ViewModel to satisfy the different interaction requirements. A little code behind would handle things like ink gestures, but would be quickly wind up calling down to the ICommand objects on the ViewModel. Avoiding putting this stuff in the code behind results in another layer between the View and the ViewModel, but it would have to be bounded so tightly to the View that I wouldn’t see much opportunity for reuse/testability/etc.

    To me, this sounds a lot like the case for ASP.NET MVC. You can have different view on the same VM… what I haven’t seen in WPF MVVM is any sort of factory pattern implementation for getting different views.

  11. Josh Smith says:

    @David Roh:

    Well, you can do that, but, by the same reasoning, why not just put all of the application logic and domain logic into the code-behind of Window1? I’m kidding, but my point is that separation of concerns can be expressed along a spectrum. Finding the right balance between a giant bowl of spaghetti and an extremely loosely-coupled system where no piece knows about any other piece, is the tricky part. Suppose you need to integrate with an existing domain library. Suppose you need to have various ViewModels to present the domain data to the UI. Suppose you need to unit test the VM objects, but the domain objects take hours to perform their calculations and you don’t want your tests to take hours to complete. Etc. etc. etc.

    Do what works, and get to work. That’s my motto!😀

  12. Josh Smith says:

    @Ben:

    Yup, that’s an option. But, then you can’t easily unit test your application logic because it resides in UserControls (i.e. Views). If you aren’t a fan of unit testing, then this isn’t an issue.

  13. But only the interaction logic falls into the “untestable” category… the commands themselves still reside on the VM and of course we all wrote the tests before we even wrote that, right? (No, not really🙂 ) At the end of the day, this is the stuff that’s still basically impossible to test in an automated fashion. Someone still needs to click in the box and type something to make sure we bound it to the right field on the VM, right?

    I’m honestly not sure how I would go about testing Surface or Touch interactions in the first place. So much of that is wrapped up into the framework that, e.g. faking out a gesture to test it seems unreasonably difficult. I’m eager to be enlightened if this isn’t true, though.

    Looking forward to your exploration of this issue. My WPF exploration application is primarily tablet/touch targeted, but I am looking at a Keyboard/Mouse version and I would run into some very different requirements (e.g. moving buttons around so your hand isn’t in the way, that kind of thing).

  14. Ben Reierson says:

    I’ve been thinking about this lately too. In fact the MVVM app I’ve created for personal reference has separate view implementations for mouse/keyboard, win7 touch, and Surface. I have a single shared project containing the VMs and any resources used by multiple interface implementations.

    For the most part, this works fine. Most of the commands are generic enough to be reused across all implmementations, it’s just that they are activated in different ways (double-click vs. tap for example). So for these, I agree with Ben, in that it’s easiest just to keep the differences in how the UI interprets the input in the view. Side note: I really like the ExecuteCommandAction for gesture-based interfaces.

    But I think I can see what you’re getting at Josh, sometimes there are some complex interaction patterns that are unique to certain input types, but there might be aspects of that logic that apply to multiple devices. I think that these can and should be refactored out of the view when possible, but I don’t know that I see it as another layer of MVVM. I think it makes more sense to think think of this as part of the input framework.

    The Surface SDK has a couple gestures built-in, like Tap. This is part of their input framework that’s bolted onto WPF. That seems like a resonable model to follow for generic gestures as well. I like that their logic just tells me when a Tap has taken place. My view and viewmodel don’t have to know what exactly a Tap is, they just know know that when it happens they are wired up to call a given command.

  15. Josh Smith says:

    Great feedback, Ben.

    Thanks,
    Josh

  16. @David Roh
    One of the reasons why Commands were developed is to accomodate one issue in WPF: Templating. When you have a template with a button, and this button will be clicked by a user, you need execution logic. However, when the template is placed in a resource dictionary, there is no place to put the event handling code. It simply doesn’t work (in fact it will fail if you try to compile it, because resource dictionaries don’t have code behind typically). The problem is the very tight link between the event and the handler. Commands introduce a looser link and help solve that problem. XAML 4 will help solve that issue with the introduction of delegates, but this is not available yet. Commands do help solve other problems, but their main advantage is just that, less coupling between XAML and code.

    About encapsulation, behaviors are also following this kind of philosophy: encapsulate complex code, hide it from the designers who will use it. Designers and Blend are the primary “targeted users” for commands and now behaviors. We developers may scoff at that because we love to look at code🙂 but most designers don’t. By providing ways to encapsulate actions (with commands) or behaviors (with, well, behaviors), you help the workflow. Again, that might not be needed by every firm, but WPF targets a wide audience, including firms like IdentityMine (where Josh and I work) which have many designers touching the XAML.

    I too struggled for a long time trying to understand why commands are needed. And like you, I came to the conclusion that you can indeed program without using them, but if you start using them consequently, you will feel that they help keep neater code with less tight links between the layers. But like Josh said, there is no rule. WPF is a very powerful toolbox, but not every tools are needed by everyone.

    Note also that I find having to implement ICommand too much trouble. Honestly this is one thing I hate to do. Discovering RelayCommand (and the fact that I can use it in Silverlight too with only minor changes to the XAML) totally changed my vision of commands. I can say now that it’s thanks to Josh that I dig commands😉

  17. David Roh says:

    Thank you Laurent – awesome answer!

  18. Josh @10:49am

    Ah; I see what you’re getting at. I *think* I would prefer to think of them as just ViewModels (and therefore nothing special).

    If we then build more complex ViewModels by aggregating (yay!) or inheriting (yuk) these pieces of ViewModel, then all power to us.

    The idea of building complex ViewModels from simpler (or smaller, more specializsed) ViewModels is one that I use a lot. It helps with testability, and also helps other developers understand how the thing comes together.

  19. Josh Smith says:

    I see where you’re coming from, Matthew. The distinction I was making between InteractionModel and ViewModel was minor and poorly explained. I was using the term InteractionModel to help emphasize the device-specific role played by such classes. At the end of the day, code is code is code. 😀

    Thanks!
    Josh

  20. Josh – I’d certainly go along with that.

    My only concern is that folks already struggle conceptually with MVVM, and MV(VM->IM->XYZM) might be a concept too far!😀

  21. Josh Smith says:

    Ha! That might be true…but, I only feel that I’ve gone too far if new concepts add no significant clarification to the solution.

  22. Deepak says:

    Well this question relates to MVVM pattern and i could see expert’s talk so i thought to ask and clear the confusions i had about the pattern.

    I am quite new to MVVM approach. I appreciate the pattern and understand the principals behind it.Maybe i have not worked that much with the pattern that’s why there is a confusion.

    If there is a scenario in which i want to load few parts of my WPF page dynamically with XAML and still want to be compliant with MVVM approach.

    The confusion is
    1. Where the logic of loading a view dynamically with XAML reside.
    2. Whether i should have a single ViewModel for my WPF page or each seperate part have its own viewmodel with interactions with other viewmodel classes.
    3. What if i had to build control tree displayed on the GUI using C# code in the codebehind itself.
    For the controls created using code should i do the commandbindings in the codebehind of the view itself.

%d bloggers like this: