Пример диалога WPF MVVM

Есть ли у кого-нибудь примеры отображения диалогового окна с использованием MVVM (Prism)? - например, окно настроек конфигурации при выполнении команды.

Все примеры, которые я видел, используют шаблон посредника, который хорош, но они также имеют ссылку на представление в модели представления, которое не является идеальным (мы используем DataTemplates)

Спасибо

Ответ 1

Я бы использовал сервис для отображения диалога. Затем служба может также связывать представления с режимами просмотра.

public interface IDialogService {
    void RegisterView<TView, TViewModel>() where TViewModel:IDialogViewModel;
    bool? ShowDialog(IDialogViewModel viewModel);
}

public interface IDialogViewModel {
    bool CanClose();
    void Close();
}


RegisterView просто связывает тип вида с типом ViewModel. Вы можете настроить эти ссылки в инициализации модуля. Это проще, чем пытаться получить модули для регистрации datatemplates в верхнем слое вашего приложения.

ShowDialog Показывает ViewModel, который вы хотите отобразить. Он возвращает true, false и null для закрытия точно так же, как метод Window.ShowDialog. Реализация просто создает новый вид типа TView из вашего контейнера, перехватывает его до предоставленного ViewModel и показывает его.

IDialogViewModel предоставляет механизм ViewModel для проверки и отмены закрытия диалога.

У меня есть стандартное диалоговое окно с элементом управления содержимым. Когда вызывается ShowDialog, он создает новый стандартный диалог, добавляет представление в элемент управления содержимым, подключает ViewModel и отображает его. Стандартный диалог уже имеет кнопки [OK] и [Cancel] с соответствующей логикой для вызова правильных методов из IDialogViewModel.

Ответ 2

То, как я это делаю, также использует шаблон медиатора. Когда ViewModel хочет показать диалог, он отправляет сообщение, которое отображает главное окно приложения. Сообщение содержит экземпляр ViewModel, используемый в диалоговом окне.

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

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

В вашей модели просмотра:

DialogViewModel viewModel = new DialogViewModel(...);
ShowDialogMessage message = new ShowDialogMessage(viewModel);

_messenger.Broadcast(message);

if (message.Result == true)
{
    ...
}

В главном окне codebehind:

void RecieveShowDialogMessage(ShowDialogMessage message)
{
    DialogWindow w = new DialogWindow();
    w.DataContext = message.ViewModel;
    message.Result = w.ShowDialog();
}

Надеюсь, этого достаточно, чтобы дать вам идею...

Ответ 3

Как я понял ваш комментарий выше, вопрос заключается не столько в том, чтобы показывать диалоги, как об их скрытии. Существует два способа решить эту проблему:

  • Используйте стандартное диалоговое окно для реализации представления. Это потребует наличия слабосвязанного способа связи между View и ViewModel, чтобы ViewModel мог уведомить View, который он закрыл, без ссылки на представление.

    Существует несколько фреймворков, которые позволили бы это сделать - агрегаторы событий Prism были бы одним из них. В этом случае View будет подписаться на событие (скажем, MyDialogResultValidated), и после получения события он установит диалоговое окно DialogResult. ViewModel (в SaveCommand) запустит событие, если проверка прошла успешно.

  • Не используйте стандартное диалоговое окно для реализации представления. Это потребует наличия наложения, которое эффективно эмулирует модальность.

    В этом случае видимость представления и наложения будет привязана к свойству ViewModel IsVisible, которое будет установлено соответственно реализацией SaveCommand или когда ViewModel должен показать представление.

Первый подход потребует наличия кода с кодом в коде, требуется добавить глобальные события (события) и (возможно) меньше MVVM-ish. Второй подход потребует внедрения (или использования какой-либо другой реализации) оверлея, но не потребует наличия какого-либо кода в кодировке, не потребует наличия глобальных событий (событий) и (возможно) более MVVM-ish,

Ответ 4

Я согласен, что использование сервиса для отображения диалога в соответствии с шаблоном MVVM является самым простым решением. Но я также спросил себя, есть ли 3 сборки в моей модели Model, ViewModel, View и в соответствии с сборкой шаблонов MVVM. В ViewModel есть ссылка на Model и View на Model и ViewModel, где я должен разместить класс DialogService? Если я поместил его в сборку ViewModel, у меня нет шансов создать экземпляр DialogView; с другой стороны, если я поместил DialogService в сборку "Просмотр", как я должен ввести ее в мой класс ViewModel?

Итак, я бы рекомендовал посмотреть Расширенные сценарии MVVM с Призма Часть: Использование объектов запроса на взаимодействие

В качестве примера такого подхода:

DialogViewModelBase

public abstract class DialogViewModelBase : ViewModelBase
{
    private ICommand _ok;

    public ICommand Ok
    {
        get { return _ok ?? (_ok = new DelegateCommand(OkExecute, CanOkExecute)); }
    }

    protected virtual bool CanOkExecute()
    {
        return true;
    }

    protected virtual void OkExecute()
    {
        _isSaved = true;
        Close = true;
    }

    private ICommand _cancel;

    public ICommand Cancel
    {
        get 
        {
           return _cancel ?? (_cancel = new DelegateCommand(CancelExecute, CanCancelExecute));
        }
    }

    protected virtual bool CanCancelExecute()
    {
        return true;
    }

    protected virtual void CancelExecute()
    {
        Close = true;
    }

    private bool _isSaved = false;
    public bool IsSaved
    {
        get { return _isSaved; }
    }

    private bool _close = false;

    public bool Close
    {
        get { return _close; }
        set
        {
            _close = value;
            RaisePropertyChanged(() => Close);
        }
    }
}

CreateUserStoryViewModel:

public class CreateUserStoryViewModel : DialogViewModelBase
{
    private string _name = String.Empty;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            RaisePropertyChanged(() => Name);
        }
    }
}

CreateUserStoryRequest

private InteractionRequest<Notification> _createUserStoryRequest;
public InteractionRequest<Notification> CreateUserStoryRequest
{
    get
    {
        return _createUserStoryRequest ?? (_createUserStoryRequest = new InteractionRequest<Notification>());
    }
}

Команда CreateUserStory

private void CreateUserStoryExecute()
{
    CreateUserStoryRequest.Raise(new Notification()
    {
        Content = new CreateUserStoryViewModel(),
        Title = "Create User Story"
    }, 
    notification =>
                 {
                      CreateUserStoryViewModel createUserStoryViewModel =
                               (CreateUserStoryViewModel)notification.Content;
                      if (createUserStoryViewModel.IsSaved)
                      {
                         _domainContext.CreateUserStory(
new UserStory(){ Name = createUserStoryViewModel.Name, });
                      }
                 });
}

XAML:

<!--where xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
          xmlns:ir="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"-->

<i:Interaction.Triggers>
  <ir:InteractionRequestTrigger SourceObject="{Binding CreateUserStoryRequest}">
    <ir:PopupChildWindowAction>
      <ir:PopupChildWindowAction.ChildWindow>
        <view:CreateUserStory />
      </ir:PopupChildWindowAction.ChildWindow>
    </ir:PopupChildWindowAction>
  </ir:InteractionRequestTrigger>
</i:Interaction.Triggers>

Ответ 5

Вам может быть интересно следующее приложение-образец:

http://compositeextensions.codeplex.com

Он использует Prism2 с шаблоном PresentationModel (aka MVVM). Пример приложения содержит модальный диалог.

Ответ 6

Это не Prism, но эта демоверсия MVVM имеет Диалог опций, который полностью MVVM.