views:

427

answers:

6

I'd like to implement the ViewModel part of WPF's MVVM pattern without referencing WPF assemblies. The problematic part is command routing, which requires that ViewModels implement properties of type ICommand so that command bindings can work.

Now, I can avoid the ICommand and simply declare the properties as object. Everything still works, so that's that. But what bothers me is, I still have to declare them, and I really don't want to, because they feel like boiler plate code.

My ViewModels currently look like this:

public class HelloWorldViewModel : ViewModel
{
    [BoundProperty]
    public string Name { get; set; }

    [CommandHandler("SayHello")]
    public bool CanSayHello()
    {
        return Name != "" && Name != null;
    }

    [CommandHandler("SayHello")]
    public void SayHello()
    {
        View.ShowMessage("Hello, {0}!", Name);
    }

    public object SayHello { get; private set; }
}

The CommandHandlerAttribute enables runtime discovery of command handlers (an Action and an optional Func<bool>), while the BoundPropertyAttribute is really an aspect that injects itself into the property setter and calls INotifyPropertyChanged. I accompish this by using a compile time IL weaver.

Ideally, I'd like to make the last line (the SayHello property) implicit, too. There would be no point in having it there in the source if it wasn't for WPF's requirement.

So, naturally, I'm thinking of using the CommandHandlerAttribute aspect to inject the necessary IL into class and essentially creating the property post-compile. This is quite hard, although a good IL weaver (such as PostSharp) can go a long way to make it easier.

Before I embark on this journey, I'd like to hear what you all think of my approach. Is it sound? Is there a better way? How would/do you do it?

A: 

My personal opinion is that this is interesting, but I would avoid it in general.

Avoiding boiler-plate code (or code that feels like boiler plate code) has consequences. It may seem like a good idea, since you're not retyping things constantly, but in the long run, you're making it less readable and understandable.

Personally, I try to just setup good code templates to insert the boiler plate code for me, and wrap it in regions so I can hide it in the source code. The 30 seconds it takes to fill in a file with boiler plate in that case is less painful (for me) than the 2 hours I spend, two years later when I'm trying to understand the code, or worse, the two weeks somebody else spends two years later when they're trying to understand my code....

Reed Copsey
+1  A: 

Read this To Inject Or Not To Inject

You know this libraries :

Ninject 2 and Extensions
Ninject

lsalamon
+1  A: 

Some time after playing with Prism, but before I'd seem the MVVM stuff, I came up with a strategy that I still think has some validity:

I created an implementation of the ICommand interface based on reflection. The constructor accepted a target object and an operation name. Using reflection, the code looked for a method with name "[operation]", property or method with name "Can[operation]" or "[operation]Enabled" and an event with name "Can[operation]Changed" or "[operation]Enabled Changed". Only the first was required, but the reflected method/property/event were wired up to a pretty basic implementation of the ICommand interface.

I then created an implementation of IValueConverter that would create an instance of the previous class, passing the value to be converted as the target object, and the parameter of the converter being the operation name.

Given the above components, I was then able to, for example, bind a button's Command property directly to the source of the operation (along with specifying the converter), and set the Button's CommandParameter property to the name of the operation. In this way, I got declarative command binding without the command source having carnal knowledge of anything WPF.

Daniel Pratt
I don’t like using reflection with “magic” method and property names. I have found to often in the past, I rename a method and then unexpected bit of UI has stopped working without the compiler giving me an error. However I like your basic design, what about lambda expressions to do the wireup?
Ian Ringrose
I like the idea of a lambda a lot. I might still prefer to discover the "enabled" property/event via reflection (at least by default) as it would simplify the interface.
Daniel Pratt
+1  A: 

To me this sounds too clever by far. There's too much "magic" happening. In particular, I dislike the magic strings and other aspects of your CommandHandlerAttribute. That said, if I were to go down this route, I'd use something akin to the EventAggregator but for commands. IOW, SayHello wouldn't exist on your ViewModel at all. What ever magic creates the command bindings to SayHell() and CanSayHello() would instead locate the command in the global CommandAggregator. As long as we're using magic strings for this, the commands in the CommandAggregator could be lazily created, thus requiring no "boiler plate" coding on your part. All that's left is to create some XAML magic (markup extension) to specify the command on the ICommandSource.

<Button Command="{my:AggregateCommand SayHello}"/>
wekempf
A: 

The best way in your case is Proxy or Decorator pattern I think. You can low level entities that are wrapped/decorated with UI/WPF stuff members during runtime. This is the simplest but yet efficient way to save your time and don't bother with frameworks, injections, etc.

The only thing is you will have to design some small infrastructure to wrap your entities with appropriate decorators.

Denis Vuyka
A: 

Take a look at PostSharp http://www.postsharp.org/

Nir
I'm already using PostSharp, as I've hinted in my question. My concern was precisely that it might not be appropriate here, though.
aoven