views:

223

answers:

2

Hi,

I need some advice on implementing UIs in WPF.

So far, I've been using Code-Behinds, which is extremely easy to get-started, but hell when maintaining/changing/testing.

I've looked at MVP (and its WPF variant - MVVM), but having some trouble getting started.

Assuming I have a UI to build, here's what I think I should do:

1. Create a "Main UI" Mediator class which specifies ALL high-level operations (LoadSettings(), SetVisibility() ) and events (not triggered by the user, e.g, model data changed) that my UI supports.

2. Create the "Model" classes to represent the data

3. Create "ViewModel" classes for my model classes.

4. For complex behaviours (e.g, a sequence of operations need to be done before the UI can/should update, such as modifying items in a collection), do not rely on ViewModels to update the UI. Instead, do it manually through the Main UI Mediator class.

5. For simple behaviours (e.g, toggling the visibility/enabled states/etc), use WPF binding to bind the ViewModels' properties directly to the UI.

In this case, the Main UI Mediator class would maintain both the ViewModel and Model objects, and delegate user interactions (to the Model) and UI update requests (to the ViewModel/View) appropriately. The Mediator class also provides a centralised interface which specifies the functionalities of the UI, while acting as a Change Manager (described in GOF's Observer Pattern) to handle complex UI behaviour/reduce redundant UI updates.

Am I on the right track? Should I tweak my approach? Change it completely? At the moment, I lack the experience/knowledge to implement huge/complex UIs, so I don't really know whether I'm on the right track.

Thanks

+4  A: 

This is a bit long, sorry about that!

So far, I've been using Code-Behinds, which is extremely easy to get-started, but hell when maintaining/changing/testing.

Yep :) Anytime you have to name a control and write "someControl dot blah" in your code-behind, that's a code smell. It's sometimes unavoidable, but try to limit it as much as possible. Your UI is a projection of the model - ViewModels and ValueConverters are a way to deal with the impedance mismatch between the two domains.

A few problems with your approach:

Create a "Main UI" Mediator class which specifies ALL high-level operations

Instead of doing this, your Window class acts as the "Controller"; the important thing is, use Commanding to define your top-level actions. This way, you can have UserControls decoupled from the Window class, because the UserControl will just call Commands.Open.Execute(null, this), and the Window can handle it, and the UserControl will never explicitly have a dependency on the Window.

Create "ViewModel" classes for my model classes.

In MVVM, the VM part is to help you out - if you can get away with binding directly to the model (i.e. the data doesn't change or you don't mind implementing INotifyPropertyChanged in your models), then doing this (even if you have to use a few IValueConverter classes) is okay. ViewModels are mostly used when the view is so different from the model representation that it'd be ugly to hack up your model, or to "tack on" extra properties that only make sense in this particular view.

while acting as a Change Manager...

Remember that WPF does this for you, via Dependency Properties and INotifyPropertyChanged; don't reinvent the wheel; if you write an OnDataUpdate() function, this is a sign you're not using data binding properly.

e.g, a sequence of operations need to be done before the UI can/should update, such as modifying items in a collection

This is where Commanding is great - your CanExecute function can apply arbitrarily complex logic to decide whether a certain operation can be done, and if you bind it to UI elements like Menus or Buttons, they will automatically disable/enable as needed.

Paul Betts
Hi Paul, thanks for the reply.Just wanted to comment on the Change Manager bit.I've used a fair bit of INotifyPropertyChanged in my code, and it's been great for immediately (and easily) updating the UI to reflect the changes (visibility, isenabled, content, etc). However, I've also noticed that when working with complex behaviours (e.g, complex notification, delayed notification (update everything before requesting the UI to update), etc), the INotifyPropertyChanged sometimes gets invoked a little too often for comfort.
Got another question: currently MVVM relies heavily on binding and Commands. If I were to implement this in something other than WPF (like WinForms), what would the recommended approach be? The reason I mentioned the Mediator/Change Manager class in my question was because it felt like it would be something that I can easily port between WPF and WinForms (or any other GUI libraries).
A: 

It hasn't been mentioned, but do all of your UI design in XAML.

There is nothing worse than seeing WPF UI's being created via code-behind.

Alastair Pitts