Откройте новое окно в MVVM

Допустим, у меня естьMainWindow иMainViewModelЯя не используюMVVM Light или жепризма в этом примере.

В этомMainWindow Я хочу нажать наMenuItem или жеButton открытьNewWindow.xaml не а.UserControl

Я знаю, как использовать это сUserControl открыть новыйUserControl в моем существующем окне вContrntControl илиFrame


Код

public ViewModelBase DisplayUserControl
{
    get
    {
        if (displayUserControl == null)
        {
            displayUserControl = new ViewModels.UC1iewModel();
        }
        return displayUserControl;
    }
    set
    {
        if (displayUserControl == value)
        {
            return;
        }
        else
        {
            displayUserControl = value;
            OnPropertyChanged("DisplayUserControl");
        }
    }
}

вResourceDitionary заMainWindow Я имею :


    


    

Дело в том, что я хочу открыть новыйWindowнеUserControl, Поэтому я использую некоторый код, подобный этому:

private ICommand openNewWindow;

public ICommand OpenNewWindow
{
    get { return openNewWindow; }
}

public void DoOpenNewWindow()
{
    View.NewWindowWindow validationWindow = new View.NewWindow();
    NewWindowViewModel newWindowViewModel = new NewWindowViewModel();
    newWindow.DataContext = ewWindowViewModel;
    newWindow.Show();
}

а затем связатьOpenNewWindow кMenuItem или же .Button

Я знаю, что это не правильный путь, но как правильно это сделать?

Спасибо!

 Zoro Roronoa20 мая 2013 г., 17:48
было бы проблемой протестировать этот ViewModel, потому что он зависел бы от класса NewWindowViewModel, потому что я создал экземпляр в методе DoOpeNewWindow (), который находится в MainViewMOdel
 sircodesalot20 мая 2013 г., 17:23
Почему вы думаете, что это нет правильный путь. У вас есть привязка ICommand, которая выполняет действие. (Это кажется правильным?)

Ответы на вопрос(1)

Решение Вопроса

Есть две проблемы, которые вы должны решить с этим типом приложения.

Во-первых, вы не хотите, чтобы View-Model создавала и отображала компоненты пользовательского интерфейса напрямую. Одним из мотивов использования MVVM является введение возможности тестирования в вашу View-Model, и наличие у этого класса всплывающих новых окон делает этот класс более сложным для тестирования.

Вторая проблема, которую вам нужно решить, - это как разрешить зависимости в вашем приложении или в этом случае - как тебе "монтировать" View-Model для соответствующего View? Устойчивое решение этой последней проблемы дается использованием контейнера DI. Очень хорошая ссылка на эту тему даетсяВнедрение зависимостей в .NET, На самом деле он также обсуждает, как решить первую проблему тоже!

Чтобы решить первую проблему, вам нужно ввести слой косвенности в ваш код, чтобы модель представления не зависела от конкретной реализации создания нового окна. Очень простой пример приведен в коде ниже:

public class ViewModel
{
    private readonly IWindowFactory m_windowFactory;
    private ICommand m_openNewWindow;

    public ViewModel(IWindowFactory windowFactory)
    {
        m_windowFactory = windowFactory;

        /**
         * Would need to assign value to m_openNewWindow here, and associate the DoOpenWindow method
         * to the execution of the command.
         * */
        m_openNewWindow = null;  
    }

    public void DoOpenNewWindow()
    {
        m_windowFactory.CreateNewWindow();
    }

    public ICommand OpenNewWindow { get { return m_openNewWindow; } }
}

public interface IWindowFactory
{
    void CreateNewWindow();
}

public class ProductionWindowFactory: IWindowFactory
{

    #region Implementation of INewWindowFactory

    public void CreateNewWindow()
    {
       NewWindow window = new NewWindow
           {
               DataContext = new NewWindowViewModel()
           };
       window.Show();
    }

    #endregion
}

Обратите внимание, что вы берете реализациюIWindowFactory в конструкторе вашей View-Model, и именно этому объекту делегировано создание нового окна. Это позволяет заменять производственную реализацию другой во время тестирования.

 Lawrence20 мая 2013 г., 17:56
Цель IWindowFactory - просто делегировать фактическое создание окна абстракции (которая может быть впоследствии заменена во время тестирования). В том смысле, что он скрывает реализацию для реального создания - да, это подход Factory Pattern.
 Lennart11 февр. 2015 г., 13:45
@Lawrence Означает ли это, что вам нужно для каждого окна, в котором вы хотите создать отдельную Фабрику (т.е.XWindowFactory а такжеYWindowFactory)? Или вы создаете одну фабрику, которая предоставляет такие методы, какCreateNewXWindow а также ?CreateNewYWindow
 Lawrence11 февр. 2015 г., 14:42
@ Леннарт: Этозависит от вас и от того, как вы разрабатываете свое приложение. Шаблон просто позволяет отделить реализацию "открытое окно" от того, как это называется. Если вы обычно хотите открытьXWindow а такжеYWindow с той же модели представления вполне может быть уместным представить методы, которые делают это на одном и том же заводском интерфейсе.
 Zoro Roronoa20 мая 2013 г., 18:10
ок это сработало для моего примера спасибо :)
 Lennart11 февр. 2015 г., 14:45
@ Лавренс Хорошо, спасибо!
 rolls17 нояб. 2016 г., 06:05
Не могли бы вы вместо этого поместить CreateNewWindow в класс IMainView?
 Zoro Roronoa20 мая 2013 г., 17:51
очень хорошее решение, я знаю, что мне приходится иметь дело здесь с DI. Я хотел бы спросить вас, является ли IWindowFactory подходом Factory Pattern. Так что это в основном делегировано фабрике для создания этой модели представления?

Ваш ответ на вопрос