2009-09-27 6 views
46

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

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

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

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

, но я до сих пор есть LoginView показали - так что мне нужно, чтобы просигнализировать разгружать ..

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

Любые идеи?

ответ

35

Редактировать: См. my blog post для более подробного объяснения.

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

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

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

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

+0

Привет, Jalfp, это звучит очень здорово. У вас есть пример абстрактного класса, который мне нужно, чтобы все окна унаследовали? .. Если у вас есть пример, в том числе Irquestcloseviewmodel, также - было бы замечательно –

+0

Я собираюсь разместить статью в своем блоге в ближайшие несколько часов. Я дам вам знать, как только он будет онлайн :-) – japf

+0

Вот он: http://www.japf.fr/2009/09/how-to-close-a-view-from-a-viewmodel/ Надеюсь, что эта помощь :) – japf

8

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

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

2

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

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

4

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

+0

Ницца и просто. – Darren

22

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

Простой, и сохраняет ваше мнение абстрактным с вашей модели.

Вот бы мой подход с использованием MVVM-легкий инструментарий:

В 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(); 
    } 
}); 
+0

Просто интересно, может ли это вызвать утечку памяти, потому что вы передаете ссылку на объект, который должен быть удален? .. –

2

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

How should the ViewModel close the form?

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

2

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

+0

Я буду поражен болтом формы молнии ViewModel для этого, а не писать собственные Интерфейс IRequestCloseViewModel? – Ted

7

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

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

в кнопку XAML для вида:

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

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

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

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

  1. создать такой класс: общественного класса ClosingRequested: MessageBase {}

  2. добавить это в ваш вид конструктора: Messenger.Default.Register (это, VM, сообщ => Close());

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

0

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

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

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(), когда вы будете готовы закрыть View из ViewModel.

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

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

Смежные вопросы