This project has moved. For the latest updates, please go here.

Decoupled Views

Jan 7, 2010 at 4:26 PM

Apologies for the title - I am not sure the correct terminology for what I am asking.

Firstly I would like to thank you for WAF, it's an excellent framework and has helped me greatly in getting inboard with WPF and MVVM. I find the sample applications invaluable and would love to see more functionality and example documentation (for example the scope of the Controller's role).

Question 1 is regarding the Writer sample. The status bar at the bottom currently reads "Ready." What would be the best approach to take if I wanted to change the status bar text when, for example, my mouse is hovering over a toolbar button or I am currently typing into a document? What is the best way of emitting and subscribing for events that do not couple the views/viewmodels.

Finally, what's the best practice when it comes to nestint view models? Should I build a controller to manage them, ensuring that the view models are not coupled or is it ok for a ViewModel to contain direct references to multiple child ViewModels?

Thanks,

Daniel

Coordinator
Jan 10, 2010 at 7:49 PM

Hi Daniel,
 
Thanks a lot for your feedback. I will try to answer your questions:
 
1. How to update the status bar?
 
I would use a service to update the status bar from various Controllers or ViewModels:
 
public interface IShellService : INotifyPropertyChanged
{
    string StatusMessage { get; set; }
}
 
The implementation of this service is similar to the ZoomService of the Writer sample application. This way you can update the message in the status bar from everywhere without coupling the views together.

2. Is a ViewModel allowed to have a reference to another (nested) ViewModel?
 
Yes, but I would keep them rare.
 
Example that shows how to keep the ViewModels decoupled:
The ViewModel sample (EmailClient) has a Shell which contains two nested views. These views are composed together by the Controller and so the ViewModels don’t need to refer each other. This way they are decoupled of each other and the Controller is the mediator between them.

 
Best regards,
  jbe

Jan 11, 2010 at 4:34 PM
Edited Jan 11, 2010 at 4:35 PM

Thanks jbe - these insights are really helpful when getting to grips with WPF, MVVM and WAF. If I may, I have a follow-up question:

public class ScenarioViewModel : ViewModel<IScenarioView>
{
    public string Name
    {
        get { return scenario.Name; }
        set
        {
            if (Name != value)
            {
                scenario.Name = value;
                RaisePropertyChanged("Name");
            }
        }
    }
}

I realised that binding directly to the ViewModel doesn't keep sync if I happen to change Scenario.Name in another part of the application (e.g. another ViewModel). What I have resorted to now, which I doubt is a good idea, is binding directly to the Scenario.Name property by exposing Scenario:

public Scenario Scenario
{
    get
    {
        return scenario;
    }
}

This only works since I have had the luxury of writing a domain model that extends from the base Model class.

So, what should I be doing?

1. Is binding directly to the domain model incorrect in MVVM?
2. Is it wrong to have multiple ViewModels representing the same domain object?

Kind Regards,

Daniel

Coordinator
Jan 11, 2010 at 6:35 PM

Hi Daniel

It's a common misunderstanding in the MVVM community that this pattern forbids to bind directly to the model. That’s not true.

  1. Binding directly to the domain model is allowed. I often prefer this approach because it keeps the software more simple. (See also ViewModel Sample)
  2. When the domain object doesn’t provide the functionality I need for the UI then I wrap it in a Model.
  3. It’s not wrong to have more Models representing the same domain object. However, you might have to synchronize them.

 

What’s the difference between ViewModel and a Model?

ViewModel
- abstracts the View
- 1:1 relationship with the View

Model

- encapsulates a domain object to provide functionality which is needed for the UI
- 1:1 relationship with the domain object
- is optional. Often the UI can bind directly to the domain object

Note: Some MVVM frameworks refer the Model as ViewModel.

 

Best Regards,
  jbe

Jan 12, 2010 at 10:39 AM

Thanks for your insight jbe. Now that I see the Domain and Model can be seperate (and the Model optional) it makes perfect sense to bind directly to the Model. Of course there are cases where I bind directly to the ViewModel when the VM must provide functionality to the View that the Model/Domain has no concept of. It's all clicking together now!

Do you have any thoughts on using CollectionViews and where they should belong? I am currently taking care of it in the VM (since in this case any view using the VM should have the same filtering functionality):

public StartDetailViewModel(IStartDetailView view, StartPoint start, Scenario scenario)
        : base(view)
    {
        this.scenario = scenario;
        this.start = start;

        this.eligibleModulesSource = new CollectionViewSource();
        this.eligibleModulesSource.Filter += new FilterEventHandler(Eligible_Filter);
        this.eligibleModulesSource.Source = scenario.Starts; 
    }
    public ICollectionView EligibleModules
    {
        get
        {
            return eligibleModulesSource.View;
        }
    }
    void Eligible_Filter(object sender, FilterEventArgs e)
    {
        if (e.Item != null && this.StartDate != null)
        {
            e.Accepted = (((StartPoint)e.Item).Date == start);
        }
    }
}

I realise it's not clear cut. For example, if I felt that the filtering was specific to a single View only then I might have placed the logic into the View itself. Although I'm not sure whether that would be very testable.

How can I donate you some beer tokens to show my appreciation?

Coordinator
Jan 18, 2010 at 6:56 PM

I have no experience with the CollectionView. At the first glance your implementation looks good and I don’t see any problems by using the ICollectionView interface in a ViewModel.

Best Regards
   jbe