tags:

views:

299

answers:

2

Hi, I thought I'd post here in the hope that maybe someone with MVVM expertise would be able to offer opinions on whether the following is a good idea:

I'm using Sacha Barber's Cinch MVVM framework, which includes Marlon Grech's SimpleCommand class.

One thing this class doesn't have which some other alternatives have is a Text property, which can be commonly used to bind UI elements to the 'Title' of the command operation. Consequently I've been writing an extension to this class which exposes a Text property.

Now, what I've run into is a use case where I'm using a command to toggle connectivity to a device. There's a bunch of different ways I could implement this (aren't there always - it's software!). One way would be to expose multiple command objects from my ViewModel - one for 'Disconnect' and one for 'Connect; have the view model expose a property which indicates the connection state (IsConnected) and have the view conditionally bind to either the Connect command or Disconnect command. My reaction to this option though, is ... yuck!

What I initially started looking at instead was not only providing a Text property but also having the command object implement INotifyPropertyChanged so that the text property can be dynamically altered by the viewmodel to 'Connect' or 'Disconnect' according to system state. Doing this, I can avoid having multiple commands and just expose a single 'ToggleConnection' command object.

Starting down this path though, it occurs to me that there may be other variations of this pattern whereby the UI needs to be altered according to command state. For example, in addition to changing the command's text according to connection state, you may have places where an icon needs to change according to connection state. So, I started writing a 'Stateful' class which implements INotifyPropertyChanged, and exposes two properties - 'Text' and 'State'. I've made the class generic so that the type of State can be defined by the user (I usually prefer not to use 'object' where avoidable).

The question I have is... Do you think this is a good or bad idea? It may be diverging from the original intention / design of commands; From what I've seen it may in general be the case that command objects were intended to be stateless as they are the 'verbs' of the system. With routed commands, if I understand things correctly only the target of the command would usually be expected to have state. Particularly since the same command could be routed to different handlers depending on where command bindings are declared.

So, I'm thinking that at least with routed commands, state would not make sense.

However, I'm not dealing with routed commands - I'm specifically dealing with MVVM commands. In this case there basically is no conditional routing of commands - the MVVM views bind directly to a particular viewmodel's command objects and it's execute and canexecute handlers.

In this case, does it make sense?

I've attached a copy of the code in question, in case it's of use/interest.

Thanks, Phil

+1  A: 

It's really up to you what you think would be easier to work with.

I personally do not put the .Text property on my commands simply because I get no reuse out of these commands. It's different with the RoutedUICommands provided in the framework (or similar custom static commands) because they are reused everywhere and if the translation of "Exit" were to change on that command, it would be reflected throughout the application. This is not the case in your example - everything would be one-off.

In your case this text of your button text is really decoupled from your command (even though one affects the other) and so it's probably going to end up being easier and a little less code to decouple them, but the difference isn't going to be that much and it will end up being a matter of taste more than anything.

I'm definitely with you on the 2 commands thing - blech. Most button delegates you write will have to react to state in some way (service you talk to is down, this data needs to be populated this way if the user selected this, etc), so I don't really think it's wrong to have the delegate adapt to stateful information on the ViewModel.

Anyway, this is a bit wordy... the take-away is "do whatever feels comfortable".

Anderson Imes
Thanks Anderson, good comments. I guess my discomfort is from previous use of routed commands but then the whole behavior of MVVM commands is different.I do prefer having the command text in one place with the command since I commonly have multiple UI elements bound to it. I guess having the viewmodel perform localization might seem a bit funky but then it's obviously tightly tied to provision of a UI view.I can also see some advantages when dynamically generating UI - e.g. bind to a list of commands, with a style/datatemplate that creates text of the command object.Cheers!
Phil
In this particular case you still aren't gaining anything. I realize you are binding multiple buttons to the same command for the .Text property, but how is this different than binding to another property on your ViewModel "ConnectionText" or similar property. Just want you to think about it... you are talking symantics here... they are essentially the same thing in your usage scenarios.
Anderson Imes
I get what you're saying Anderson, and have considered having a ConnectionText property as you describe.What I have seen done before though, and have liked is the use of relative bindings in conjunction with commands, e.g.:Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Description}" I like this for a number of reasons - 1. it reduces the number of places where property references must be specified; If we are just talking the text or 'title' displayed for a button, the reduction would be from 2 (the MVVM's command and text properties) to 1.
Phil
Absolutely. This goes back to "whatever feels comfortable". They are nearly identical except for the hoops you might have to jump through getting PropertyChanged events to fire appropriately.
Anderson Imes
(to get round comment limit!)...And 2.) combined with the use of styles you can omit the repeated verbiage of the relative binding (just have it on the style).There would seem to be other advantages too - if you extend the command's properties to also include things like a longer description (useful for binding tooltips to), and possibly icons etc. then again repetition of xaml property references (binding statements) can be reduced.Also, some logic involved in INotifyPropertyChanged notifications for mutable properties (e.g. the commands title/connection text) should be reduced.
Phil
almost real-time conversation! - yes, my intention would be to implement INotifyPropertyChanged on the command object. Then when I want to alter the title, description (tooltips), icons or arbitrary state data, the viewmodel would just do a property assignment on the command object. The command object's implementation of INotifyPropertyChanged then takes care of change notification.
Phil
Sounds like you've already decided. If you were just posting to confirm that this approach was crazy or wrong, you are neither crazy nor wrong. I wouldn't do it like this, but I certainly see why you would and it doesn't violate any MVVM principles. I say go for it.
Anderson Imes
Cool, thanks Anderson. The one thing where I was a bit concerned was just the idea of the command object itself having state... was a bit concerned that it might go against the philosophy behind the command infrastructure.Anyway, all cool. Thanks for the input!
Phil
A: 

Like the last poster said, "Whatever feels comfortable."

In my case, I usually use something like the DelegateCommand. If I need to bind to some data, I bind to the VM. When the command is executed, its executed within my VM (via the delegate provided to the DelegateCommand at init). Then the executed delegate may/maynot run some reusable code to satisfy the command.

It sounds like you want to use the Command as it's own VM. I never thought of doing this before myself, but if it feels good to you, do it! :)

Jeremiah Morrill
I think that's a good way of putting it - the command is kind of becoming a mini VM!Cheers :)
Phil