views:

218

answers:

1

I'm writing an app that lets users browse through data, and I want to use the FireFox UI style: allow the user to open as many windows as they want, each with as many tabs as they want. I also want to try to do this using the Model-View-ViewModel pattern as much as possible.

Opening a new tab should be easy enough to handle in MVVM. Make an ObservableCollection of TabViewModel, bind that collection to the ItemsSource of a TabControl, and then opening a new tab is theoretically as easy as adding a new TabViewModel to the collection.

Here's the question that interests me: Is there a way to do the same thing for opening a new window? I.e., databind an ObservableCollection of WindowViewModel to the ItemsSource of... the Application's Windows collection?... so that when I add a new WindowViewModel to the observable collection, a new window automatically opens? And then tie that into app startup, so that instead of setting StartupUri, I just add the first WindowViewModel to the collection?

Since I can't actually databind Application.Windows, what would be the best way for the ViewModel layer to:

  1. Add a new WindowViewModel and have a new Window appear automatically;
  2. Remove the WindowViewModel and have its Window automatically close.
  3. Remove the WindowViewModel from the collection if the user closes the window.

I could write my own object that watches an INotifyCollectionChanged and opens/closes windows in response to collection events, but I'm not sure whether that's the best way -- and if it is, I'm not sure of the best way to hook it into the application. Anyone have thoughts on the best way to go about this?

A: 

The point of MVVM is, that the ViewModel doesn't have to concern itself (in detail) with how the View will react to changes in the ViewModel.

One possibility would be a simple tracking algorithm in the View listening to the CollectionChanged event in the ViewModel, creating and destroying Windows on the go:

Dictionary<WindowModel, WindowView> _cache = new;
void WindowModelListChangedHandler(sender, args) {
    switch(args.Action) {
        case Add:
            _cache[args.NewItem] = new WindowView(args.NewItem);
            _cache[args.NewItem].Show();
            break;
        case Remove:
            // ...
    }    
}
David Schmitt