How to open a new window using WPF respecting good

2019-05-05 09:23发布

问题:

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?

回答1:

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.



回答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).



标签: c# wpf mvvm