views:

1034

answers:

4

I've decoupled events in this WPF application in the following way.

What is the best way to continue decoupling?

Shell.xaml:

<Button x:Name="btnProcess"
        Content="Process"
        Margin="10"/>

Bootstrapper.cs:

public void Run()
{
    Shell shell = new Shell(new Customer());
    shell.Show();
}

Shell.xaml.cs:

public Shell(IPerson person)
{
    InitializeComponent();
    btnProcess.Click +=new RoutedEventHandler(person.Process);
}

Customer.cs:

public class Customer : IPerson
{
    public void Process(object sender, RoutedEventArgs e)
    {
        Button theButton = (Button)sender;
        theButton.Content = "Customer processed.";
    }
}

The above code successfully decouples the view Shell from the model Customer:IPerson so that I can swap in e.g. a model Employee:IPerson etc. which handles "Processed" in its own way. That was the first goal.

But now:

  • how do I decouple the Processed method from talking specifically to a Button, so that it could also talk to a MenuItem or a ListView which fires the event in the view and so that it doesn't even have to be an element at all that calls it, e.g. a unit test class?
  • how do I alter other elements of the view other than the sender (Button), e.g. how would I alter the status bar in Shell? I see two ways:
    • I could either build a container which holds all views and inject the container in the Customer upon creation, then the customer can look in the container and manipulate the calling view anyway it wants (although I would have to somehow match the view that sent the event and the view in the container as the same one)
    • I could somehow send the whole view (Window object) to the Model with the eventargs when firing the event, although the Model would need some way of knowing (via interface) what kinds of regions were available to manipulate at runtime
  • How would you continue this application in the direction of a more decoupled design?
  • What pattern is this actually, e.g. MVC, MVP, MVVM? I only see a view (Shell) and a Model (Customer).
    • How would a Presenter fit in?
    • How would a ViewModel fit in?
    • How would a Controller fit in?
+3  A: 

i suggest you to implement your event handling using commands instead of classic events, its very easy in wpf because the command pattern is already implemented for you and you can tell all of your UI inputs (button, menu item...) that their command is [name of your command] and handle all of them in one place.

Chen Kinnrot
thanks, I suspected this and am currently reading an MSDN article on commands: http://msdn.microsoft.com/en-us/magazine/cc785480.aspx
Edward Tanguay
+1  A: 

As Chen suggests, i'd look into the Command pattern: Routed commands

A working example from which i learned a lot can be found on Jaime Rodriquez his blog: Southridge

Tom Deleu
+1  A: 

how do I decouple the Processed method from talking specifically to a Button
Commands. Put a command in the IPerson interface and call that command from the Shell's xaml.

how do I alter other elements of the view
Properties and Binding. If you have a property showing the state (processed/not processed) then you can use binding to display that property directly in the xaml.

How would you continue
I'd head more down the MVVM path by creating a ViewModel between the Shell and the IPerson. The ViewModel is designed to have 1) The properties needed for bindings, and 2) any Commands that need executing. The ViewModel is designed to provide the UI with what it needs from the Model.

What pattern is this
Currently? Nothing. I see only two objects, the View and the Model. You don't have a Presenter, Controller or ViewModel.

For WPF I prefer ViewModel. See this question for more info on MVVM.

Cameron MacFarland
+2  A: 

Cameron MacFarland did a good job here, but I can add a little.

When following M-V-VM, the tools in your box for decoupling are data binding, commands, attached behaviors and interfaces. Data binding should be self evident. You've already gotten a good description of commands, but I'd suggest you avoid RoutedCommand and stick with an ICommand implementation. Attached behaviors are attached DependencyProperty's that subscribe to events on the element they are attached to, and in this scenario would be used to relay event handling to the ViewModel. Interfaces give you the greatest flexibility, but you have to work out how to pass the interface to the ViewModel. The best way to learn all of this right now is to Google and to look at existing M-V-VM frameworks. Here's a list of frameworks:

  • Prism/Composite WPF (http://www.codeplex.com/CompositeWPF). This one comes from the Microsoft Patterns & Practices group. Lots of good stuff here, but one of the examples of the three things above that you can learn from here is how to use ICommand. Prism includes a DelegateCommand that implements ICommand and simplifies using commands from a ViewModel in M-V-VM.

  • Caliburn (http://www.codeplex.com/caliburn). Recently released, one of the key things you can learn from this one is how to use attached behaviors, which this library uses for it's "Actions".

  • Onyx (http://www.codeplex.com/wpfonyx). Disclaimer: I'm the author of this one. This one hasn't been released yet, though the current alpha source is available. This one provides a novel solution to the problem of how to provide interfaces to your ViewModel.

wekempf