WPF (MVVM): Закрытие представления из Viewmodel?

Кто-нибудь сталкивается с умным способом закрытия представления в режиме просмотра с использованием MVVM?

Может быть, есть способ использовать привязку, чтобы сигнализировать о закрытии окна (окна)?

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

В основном у меня есть loginView, привязанный к loginViewModel, в viewmodel (используя привязку к команде). Я тестирую, чтобы проверить, успешно ли вход в систему, и если я в основном загружаю новый View (mainview) и прикрепляю его datacontext...

но у меня все еще есть показанный loginView, поэтому мне нужно сигнализировать об этом для разгрузки.

Я также надеялся на общее решение, потому что я уверен, что мне нужно будет делать подобные вещи в других ситуациях.

Любые идеи?

Ответ 1

Изменить: см. мой пост в блоге для более подробного объяснения.

Когда мне нужно это сделать, я использую интерфейс IRequestCloseViewModel, который я создал.

Этот интерфейс содержит только одно событие: RequestClose. Это событие создается ViewModel (который наследует от класса ViewModelBase И реализует IRequestCloseViewModel), когда он хочет закрыть связанный с ним просмотр.

В моем приложении все окна наследуются от абстрактного класса ApplicationWindow. Этот абстрактный класс уведомляется каждый раз, когда DataContext изменен, и в обработчике проверяется, поддерживает ли DataContext IRequestCloseViewModel. Если это так, обработчик события настроен для закрытия окна при запуске события.

В качестве альтернативы, как сказал Кент, вы можете использовать экранный контроллер, который обрабатывает этот mecanism во внешнем классе.

Ответ 2

Не знаете, какую структуру MVVM вы используете, но большинство из них содержат какое-то решение для обмена сообщениями/уведомления, которое легко регистрировать для сообщений, которые отправляются. Нет никаких оснований полагать, что ваше мнение не могло регистрироваться для сообщения, такого как "CloseWindowsBoundTo" и viewModel в качестве отправителя. Тогда, на ваш взгляд, вы можете просто зарегистрироваться для этого сообщения и сравнить свой текущий файл данных с отправителем. Если они совпадают, закройте окно.

Простой и сохраняет ваше отражение от вашей модели.

Вот мой подход с использованием инструментария MVVM-light:

В ViewModel:

public void notifyWindowToClose()
{
    Messenger.Default.Send<NotificationMessage>(
        new NotificationMessage(this, "CloseWindowsBoundToMe")
    );
}

И в представлении:

Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
    if (nm.Notification == "CloseWindowsBoundToMe")
    {
        if (nm.Sender == this.DataContext)
            this.Close();
    }
});

Ответ 3

Раньше я использовал поведение приложения к диалоговому окну, но мне было проще найти решение, представленное ниже. В приведенном ниже примере для простоты приведен пример кнопки закрытия в окне.

передать окно в качестве параметра команды.

в кнопке xaml для просмотра:

CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"

в команде execute метод в модели представления:

if (parameter is System.Windows.Window)
{
    (parameter as System.Windows.Window).Close();
}

Ответ 4

Как правило, вы должны использовать какой-то контроллер/презентатор/службу для управления активацией/деактивацией экрана. MVVM не предназначен для того, чтобы стать одним из них, чтобы исправить их. Вам нужно будет объединить его с другими шаблонами в любом нетривиальном приложении.

Тем не менее, в некоторых ситуациях имеет смысл иметь модель представления, которая управляет жизненным циклом моделей детского зрения. Например, у вас может быть EditorViewModel, который управляет коллекцией моделей детского просмотра - по одному для каждого редактируемого документа. В этом случае простое добавление/удаление в/из этой коллекции может привести к активации/деактивации. Но это не похоже на то, как он подходит для вашего случая использования.

Ответ 6

Вы можете сделать команду, которая присоединяется к окну, и когда выполняется, закрывает окно. Затем вы можете привязать эту команду к свойству в своей модели просмотра и выполнить команду, когда вы хотите закрыть окно.

Ответ 7

Я бы использовал ApplicationController, который создает экземпляр LoginViewModel и показывает LoginView. Когда пользователь переходит к экрану входа в систему, ApplicationController закрывает LoginView и отображает MainView с помощью MainViewModel.

Как это можно сделать, показано в примерах приложений Проект WPF Application Framework (WAF).

Ответ 8

Этот ответ показывает другой способ сделать это:

Как закрыть ViewModel форму?

Он использует прикрепленное свойство, чтобы привязать свойство окна DialogResult к свойству ViewModel. При установке значения DialogResult в true или false, представление закрывается.

Ответ 9

Просто закройте в EventHandler код и обработайте все остальное в модели представления, где вы можете использовать привязку команд.

Ответ 10

Вы также можете сделать это, используя событие. Хотя вам нужен как 3 строки кода в вашем коде зрения (некоторые MVVM-пуристы не любят это);

В вашей модели просмотра вы создаете событие, на которое может подписаться вид:

    public event CloseEventHandler Closing;
    public delegate void CloseEventHandler();
    private void RaiseClose()
    {
        if (Closing != null)
            Closing();
    }

В вашем представлении вы подписываетесь на событие после вашего метода initializecomponent, как показано ниже:

        public View
        {
           *//The event can be put in an interface to avoid direct dependence of the view on the viewmodel. So below becomes
            //ICloseView model = (ICloseView)this.DataContext;*
            ProgressWindowViewModel model = (ProgressWindowViewModel)this.DataContext;
            model.Closing += Model_Closing;
        }
        private void Model_Closing()
        {
             this.Close();
        }

Вы просто вызываете RaiseClose(), когда будете готовы закрыть представление из ViewModel.

Вы даже можете использовать этот метод для отправки сообщения в представление из режима просмотра.

Событие может быть помещено в интерфейс, чтобы избежать прямой зависимости вида на viewmodel.

Ответ 11

Чтобы закрыть представление из viewmodel, я использовал инструмент Galasoft MVVM Light Toolkit, который вы можете скачать здесь: http://www.mvvmlight.net/

  • создайте класс следующим образом: открытый класс ClosingRequested: MessageBase {}

  • добавьте это в конструктор вида: Messenger.Default.Register(это, vm, msg = > Close());

  • вызовите это, чтобы закрыть окно: Messenger.Default.Send(новый ClosingRequested(), this);