4

I've read a good practice with WPF (and GUI in general) saying to open as few windows as possible. But sometimes, you simply don't have the choice.

So I thought about a fast an elegant solution to open a new window and I thought to this:

public static class WinManager
{
    private static Dictionary<Type, Func<Window>> collection 
        = new Dictionary<Type, Func<Window>>();

    /* Bind the type of the ViewModel with a lambda that build an 
     * instance of a window*/
    public static void Bind(Func<Window> ctor, Type type) { ... }

    /* Search in the dictionary the specified type and show the window 
     * returned by the lambda*/
    public static void Show(Type type){ ... }

    /* Search in the dictionary the specified type and show the dialogue
     * returned by the lambda*/
    public static void ShowDialog(Type type) { ... }
}

typeis the type of the ViewModel binded to the View (that's the window) and the lambda ctor is used to return a fresh instance of a window.

Is it a good idea to manage windows like this or am I totally wrong?

JiBéDoublevé
  • 4,124
  • 4
  • 36
  • 57
  • Is the good practice talks about User experience or about handling Windows in WPF (and GUI in general)? As an end user, I would prefer to work with less windows. If its about UX then I think you should address it requirements and not in code. – Ramesh Apr 19 '12 at 09:28
  • The question is about opening Windows in MVVM from a ViewModel which should be View agnostic. – Daniel Hilgarth Apr 19 '12 at 09:31
  • 2
    Just dont use static helpers, inject this stuff as a service in the view model constructor. It will save you a lot of time for writing unit tests. – v00d00 Apr 19 '12 at 10:11

2 Answers2

2

I think it is a decent idea.

It has the advantage that the ViewModel that wants to show another window doesn't have to use any WPF specific code or even know the view. It only needs to know the ViewModel it wants to show the window for. This is very similar to Caliburn.Micros IWindowManager.

The thing I don't like about this solution is the static nature of the class. This makes unit testing hard(er). If you are using dependency injection, you could create an interface and an implementation of that interface that is similar to your static class. You could then create an instance of that class in your composition root, bind the ViewModel types to the lambda View factories and register that instance with your DI container. Every ViewModel that wants to show another window now has a dependency on that interface which makes it easily mockable in unit tests.

Something like this:

interface IWindowManager
{
    void Show(Type type);
    void Show<T>();
    void ShowDialog(Type type);
    void ShowDialog<T>();
}

class WindowManager : IWindowManager
{
    // Implementation of the four methods from the interface plus:

    private Dictionary<Type, Func<Window>> collection 
        = new Dictionary<Type, Func<Window>>();

    public void Bind(Func<Window> ctor, Type type) { ... }
}

Having the Bind method only on the concrete implementation WindowManager has the benefit that consumers of IWindowManager can't change the registration.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
2

This is not bad idea, actually the same I used inside my personal project and it works pretty well:)

In WindowManager, you can track all open forms visible on screen, manage their appearance and visual relationship (hide one if another is hidden too and stuff like this).

Tigran
  • 61,654
  • 8
  • 86
  • 123