2013-07-26 4 views
1

Я пытаюсь изучить MVVM с помощью MVVM Light Toolkit в WPF. Но я застрял в одной простой проблеме.MVVM Light: как отправить параметр ViewModel (при открытии нового окна)?

У меня есть AddEditProfileWindow, который имеет текстовое поле для имени профиля и кнопки подтверждения. Он добавляет новый профиль в таблицу базы данных или обновляет имя существующего профиля.

В MainWindow/MainViewModel У меня есть список профилей и две кнопки: «Добавить профиль» и «Изменить выбранный профиль». Оба они открывают это окно через команды + сообщения. Например вот команда для кнопки «Add Profile»

public RelayCommand OpenAddProfileWindowCommand 
    { 
     get 
     { 
      return _openAddProfileWindowCommand ?? (_openAddProfileWindowCommand = new RelayCommand(
       () => { Messenger.Default.Send(new NotificationMessage("OpenAddProfile")); })); 
     } 
    } 

и это приемник в MainWindow коде позади

private void MessageReceived(NotificationMessage msg) 
{ 
    if (msg.Notification == "OpenAddProfile") 
    { 
     var window = new AddEditProfileWindow(); 
     window.Owner = this; 
     window.ShowDialog(); 
    } 
} 

Таким образом, проблема в том, что мне нужно как-то передать параметр в AddEdit .. . Window/ViewModel (например, установить свойство IsEditing bool в ViewModel), чтобы изменить поведение окна и немного настроить его (сменить заголовок и текст кнопки подтверждения на «Добавить» или «Обновить»). Также для обновления мне нужен объект Profile (или, по крайней мере, Id) выбранной записи.

Для создания ViewModels я использую ViewModelLocator и Unity

public ViewModelLocator() 
    { 
     var container = new UnityContainer(); 

     ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container)); 

     container.RegisterType<MainViewModel>(new ContainerControlledLifetimeManager()); // singleton 
     container.RegisterType<AddEditProfileViewModel>(); 
    } 

    public AddEditProfileViewModel AddEditProfile 
    { 
     get 
     { return ServiceLocator.Current.GetInstance<AddEditProfileViewModel>(); } 
    } 

Я прочитал много подобных нитей и примеров, но до сих пор не понимаю, как я должен передать параметры для просмотра моделей. Некоторые ответы предлагают создать модели просмотра при запуске приложения (и сделать их одиночными) в ViewModelLocator, а затем я могу отправить сообщение перед открытием. Но выглядит не очень чистым, и мне нужно будет сбросить модели просмотра перед открытием (возможно, с помощью Cleanup()).

Есть ли какой-либо подход лучше/проще/чище?

ответ

1

На мой взгляд, Messenger и получение AddEditProfileViewModel из IoC не подходят в этом сценарии. Сначала вы отправляете сообщение из DataContext пользовательского интерфейса в пользовательский интерфейс. Messenger работает между слабо связанными компонентами и, как правило, на одном уровне, например, модель модели и представления. Если вы хотите, чтобы модель просмотра отображала представление, вы можете использовать InteractionRequest от Prism. Во-вторых, AddEditProfileViewModel можно рассматривать как временный, основанный на его представлении, является модальным диалогом, поэтому его создание может зависеть от среды, которая его создает.

Один подход с использованием общего сервиса, возможно, называется IDialogService, который может иметь метод ShowAddEditDialog. Ваша основная модель представления получает эту услугу от IoC и вызывает ее при выполнении команды, добавлении/изменении. При вызове метода основная модель представления также создает AddEditProfileViewModel и состояния передачи, такие как добавление/редактирование, существующий профиль и т. Д.

Другой подход с использованием контроллера приложения, если вы все еще хотите сохранить Messenger и IoC. Вы все еще можете использовать Messenger здесь, но не тот, кто слушает сообщения, а не контроллер приложения. Теперь, контроллер приложения, модель основного вида, окно AddEditProfileViewModel и AddEdit все разрешены из контейнера IoC. Контроллер приложения содержит обе модели просмотра и прослушивает сообщение. Когда он получил сообщение из основной модели представления, он обновляет состояния в AddEditProfileViewModel, разрешает диалог, устанавливает DataContext и показывает диалог. Вы можете поместить экземпляр контроллера приложения в код MainWindow за или где-либо с тех пор, как он будет разрешен с IoC, он является автономным.

+0

О IoC, на самом деле я использую IoC только потому, что ViewModelLocator был по умолчанию в MVVM Light (он добавлен в качестве глобального ресурса в App.xaml, и все представления используют привязку, такую ​​как DataContext = "{Binding Source = {StaticResource Locator} Путь = Main} ">).У меня нет опыта работы с IoC, поэтому я не получаю реальной выгоды от его использования прямо сейчас. – AlexP11223

+0

Обычно (в приложениях, отличных от MVVM, старых WinForms и т. Д.) Я использовал WindowStartupLocation = «CenterOwner» и устанавливал window.Owner = это при создании нового окна в коде главного окна. Как я понимаю, вы первый подход, невозможно сделать что-то похожее здесь? Поскольку ViewModel не должен знать ничего о View. – AlexP11223