Обработка диалогов в WPF с помощью MVVM

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

кто-нибудь знает хороший способ обработки результатов из диалогов? Я говорю о диалоговых окнах windows, таких как MessageBox.

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

public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;

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

23 ответов


Я предлагаю отказаться от модальных диалогов 1990-х годов и вместо этого реализовать элемент управления как наложение (canvas+абсолютное позиционирование) с видимостью, привязанной к булеву назад в VM. Ближе к элементу управления типа AJAX.

Это очень полезно:

<BooleanToVisibilityConverter x:Key="booltoVis" />

в:

<my:ErrorControl Visibility="{Binding Path=ThereWasAnError, Mode=TwoWay, Converter={StaticResource booltoVis}, UpdateSourceTrigger=PropertyChanged}"/>

вот как я реализовал его в качестве пользовательского элемента управления. Нажатие на " x " закрывает элемент управления в строке кода в коде usercontrol позади. (Поскольку у меня есть свои взгляды в an .exe и ViewModels в dll, я не чувствую себя плохо о коде, который манипулирует UI.)

Wpf dialog


вы должны использовать посредника для этого. Медиатор-это общий шаблон дизайна, также известный как Посланник в некоторых его реализациях. Это парадигма типа Register / Notify и позволяет вашей ViewModel и Views общаться через низко-связанный обмен сообщениями mecanism.

вы должны проверить группу учеников google WPF и просто искать посредника. Вы будете очень довольны ответами...

вы можете, однако, начать с это:

http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/

наслаждайтесь !

Edit: вы можете увидеть ответ на эту проблему с помощью MVVM Light Toolkit здесь:

http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338


хороший диалог MVVM должен:

  1. объявляется только с помощью XAML.
  2. получить все это поведение из привязки данных.

к сожалению, WPF не предоставляет эти функции. Для отображения диалогового окна требуется вызов кода showdialog (). Класс Window, который поддерживает диалоговые окна,не может быть объявлен в XAML, поэтому он не может быть легко привязан к DataContext.

чтобы решить эту проблему, я написал элемент управления заглушки XAML, который находится в логическом дереве и ретранслирует привязку данных к окну и обрабатывает отображение и скрытие диалога. Вы можете найти его здесь:http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

это действительно просто использовать и не требует каких-либо странных изменений в вашей ViewModel и не требует событий или сообщений. Основной вызов выглядит так:

<dialog:Dialog Content="{Binding Path=DialogViewModel}" Showing="True" />

вы, вероятно,хотите добавить стиль, который устанавливает показ. Я объясняю это в своей статье. Надеюсь, это вам поможет.


Я использую этой подход для диалогов с MVVM.

все, что мне нужно сделать сейчас, это позвонить по моей модели представления.

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);

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

см. полное решение Silverlight 4 здесь модальные диалоговые окна с MVVM и Silverlight 4


Я действительно боролся с этой концепцией некоторое время, когда изучал (все еще изучал) MVVM. То, что я решил, и то, что я думаю, другие уже решили, но что мне не было ясно, это:

моя первоначальная мысль заключалась в том, что ViewModel не следует разрешать вызывать диалоговое окно напрямую, поскольку ему не нужно решать, как должен отображаться диалог. Из-за этого я начал думать о том, как я мог бы передавать сообщения так же, как и в MVP (т. е. View.ShowSaveFileDialog ()). Однако я считаю, что это неправильный подход.

Это нормально для ViewModel, чтобы вызвать диалог напрямую. Однако, когда вы тестируете ViewModel, это означает, что диалоговое окно либо появится во время теста, либо потерпит неудачу (никогда не пробовал это).

Итак, что должно произойти во время тестирования, это использовать "тестовую" версию вашего диалога. Это означает, что для ever dialog у вас есть, вам нужно создать интерфейс и либо макет диалогового ответа, либо создайте тестовый макет, который будет иметь поведение по умолчанию.

вы уже должны использовать какой-то локатор служб или IoC, который вы можете настроить, чтобы предоставить вам правильную версию в зависимости от контекста.

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

надеюсь, что это помогает.


есть два хороших способа сделать это: 1) диалоговая служба (простая, чистая) и 2) просмотр с помощью. View assisted предоставляет некоторые аккуратные функции, но обычно этого не стоит.

ДИАЛОГОВАЯ СЛУЖБА

a) интерфейс диалоговой службы, например, через конструктор или контейнер зависимостей:

interface IDialogService { Task ShowDialogAsync(DialogViewModel dlgVm); }

b) ваша реализация IDialogService должна открыть окно (или ввести некоторый элемент управления в активное окно), создать представление, соответствующее имя заданного типа dlgVm (используйте регистрацию контейнера или соглашение или ContentPresenter с типом, связанным с DataTemplates). ShowDialogAsync должен создать TaskCompletionSource и вернуть его .Отеля задач. Самому классу DialogViewModel нужно событие, которое вы можете вызвать в производном классе, когда хотите закрыть, и посмотреть в диалоговом окне, чтобы фактически закрыть / скрыть диалог и завершить TaskCompletionSource.

b) для использования, просто вызовите await этот.DialogService.ShowDialog (myDlgVm) на вашем экземпляре некоторого DialogViewModel-производного класса. После await returns просмотрите свойства, добавленные в диалоговую виртуальную машину, чтобы определить, что произошло; вам даже не нужен обратный вызов.

ПРОСМОТР ASSISTED

это имеет ваше представление прослушивания события на viewmodel. Все это может быть обернуто в поведение смеси, чтобы избежать кода и использования ресурсов, если вы так склонны (FMI, подкласс класса "поведение", чтобы увидеть сортировку из тушуется арестованного имущества на стероидах). На данный момент мы сделаем это вручную в каждом представлении:

a) создайте OpenXXXXXDialogEvent с пользовательской полезной нагрузкой (производный класс DialogViewModel).

b) имеют представление подписаться на событие в его ondatacontextchanged события. Обязательно спрячьте и отпишитесь, если старое значение != null и в выгруженном событии окна.

c) когда событие срабатывает, откройте представление, которое может быть в ресурсе на вашем страница, или вы можете найти его по соглашению в другом месте (например, в подходе диалоговой службы).

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

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


используйте команду freezable

<Grid>
        <Grid.DataContext>
            <WpfApplication1:ViewModel />
        </Grid.DataContext>


        <Button Content="Text">
            <Button.Command>
                <WpfApplication1:MessageBoxCommand YesCommand="{Binding MyViewModelCommand}" />
            </Button.Command>
        </Button>

</Grid>
public class MessageBoxCommand : Freezable, ICommand
{
    public static readonly DependencyProperty YesCommandProperty = DependencyProperty.Register(
        "YesCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty OKCommandProperty = DependencyProperty.Register(
        "OKCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty CancelCommandProperty = DependencyProperty.Register(
        "CancelCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty NoCommandProperty = DependencyProperty.Register(
        "NoCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
        "Message",
        typeof (string),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata("")
        );

    public static readonly DependencyProperty MessageBoxButtonsProperty = DependencyProperty.Register(
        "MessageBoxButtons",
        typeof(MessageBoxButton),
        typeof(MessageBoxCommand),
        new FrameworkPropertyMetadata(MessageBoxButton.OKCancel)
        );

    public ICommand YesCommand
    {
        get { return (ICommand) GetValue(YesCommandProperty); }
        set { SetValue(YesCommandProperty, value); }
    }

    public ICommand OKCommand
    {
        get { return (ICommand) GetValue(OKCommandProperty); }
        set { SetValue(OKCommandProperty, value); }
    }

    public ICommand CancelCommand
    {
        get { return (ICommand) GetValue(CancelCommandProperty); }
        set { SetValue(CancelCommandProperty, value); }
    }

    public ICommand NoCommand
    {
        get { return (ICommand) GetValue(NoCommandProperty); }
        set { SetValue(NoCommandProperty, value); }
    }

    public MessageBoxButton MessageBoxButtons
    {
        get { return (MessageBoxButton)GetValue(MessageBoxButtonsProperty); }
        set { SetValue(MessageBoxButtonsProperty, value); }
    }

    public string Message
    {
        get { return (string) GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    public void Execute(object parameter)
    {
        var messageBoxResult = MessageBox.Show(Message);
        switch (messageBoxResult)
        {
            case MessageBoxResult.OK:
                OKCommand.Execute(null);
                break;
            case MessageBoxResult.Yes:
                YesCommand.Execute(null);
                break;
            case MessageBoxResult.No:
                NoCommand.Execute(null);
                break;
            case MessageBoxResult.Cancel:
                if (CancelCommand != null) CancelCommand.Execute(null); //Cancel usually means do nothing ,so can be null
                break;

        }
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;


    protected override Freezable CreateInstanceCore()
    {
        throw new NotImplementedException();
    }
}

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

Если вы измените взаимодействие ViewModel-View для обработки диалогов, то ViewModel зависит от этой реализации. Самый простой способ справиться с этой проблемой-сделать представление ответственным за выполнение задачи. Если это означает отображение диалога, то отлично,но также может быть сообщением о состоянии в строке состояния и т. д.

мой дело в том, что весь смысл шаблона MVVM заключается в том, чтобы отделить бизнес-логику от GUI, поэтому вы не должны смешивать логику GUI (для отображения диалога) на бизнес-уровне (ViewModel).


интересной альтернативой является использование контроллеров, которые отвечают за отображение представлений (диалогов).

Как это работает показывает WPF Application Framework (WAF).


Почему бы просто не поднять событие в виртуальной машине и подписаться на событие в представлении? Это позволит сохранить логику приложения и представление отдельно и по-прежнему позволяет использовать дочернее окно для диалоговых окон.


я реализовал поведение, которое слушает сообщение от ViewModel. Он основан на решении Laurent Bugnion, но поскольку он не использует код и более многоразовый, я думаю, что он более элегантен.

как заставить WPF вести себя так, как будто MVVM поддерживается из коробки


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

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


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

http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

то же самое можно распространить на любые модальные диалоговые окна, просмотра файлов и т. д.


Я свернул свой собственный загрузчик окон, описанный в ответе на этот вопрос:

управление несколькими представлениями WPF в приложении


Карл Шиффлетт создал пример приложения для отображения диалоговых окон с использованием сервисного подхода и Prism InteractionRequest подхода.

Мне нравится подход к сервису - он менее гибкий, поэтому пользователи с меньшей вероятностью что-то сломают :) Это также согласуется с частью WinForms моего приложения (MessageBox.Показывать) Но если вы планируете показать много разных диалогов, то InteractionRequest-лучший способ идти.

http://karlshifflett.wordpress.com/2010/11/07/in-the-box-ndash-mvvm-training/


Я знаю, что это старый вопрос, но когда я сделал этот поиск, я нашел много связанных вопросов, но я не нашел действительно четкого ответа. Поэтому я делаю свою собственную реализацию диалогового окна / messagebox / popin, и я разделяю ее!
Я думаю, что это" доказательство MVVM", и я пытаюсь сделать его простым и правильным, но я новичок в WPF, поэтому не стесняйтесь комментировать или даже делать запрос pull.

https://github.com/Plasma-Paris/Plasma.WpfUtils

Вы можете использовать его как это:

public RelayCommand YesNoMessageBoxCommand { get; private set; }
async void YesNoMessageBox()
{
    var result = await _Service.ShowMessage("This is the content of the message box", "This is the title", System.Windows.MessageBoxButton.YesNo);
    if (result == System.Windows.MessageBoxResult.Yes)
        // [...]
}

или как это, если вы хотите более сложный popin:

var result = await _Service.ShowCustomMessageBox(new MyMessageBoxViewModel { /* What you want */ });

и он показывает такие вещи :

2


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

  1. реализует собственный свет MVVM IDialogService.
  2. View не нужно добавлять ссылку MVVM Light.
  3. VM не нужно делать никаких действий на уровне презентации. Даже не нужно PresentationFramework ссылка.
  4. использует собственный канал мессенджера MVVM Light, поэтому слои презентации и VM развязаны.
  5. поддерживает диалоги с возвращаемым значением, такие как Да/нет вопросов или ОК/отмена ситуаций.
  6. поддерживает пользовательские диалоговые окна.

вот реализация IDialogService (входит в ViewModel):

using System;
using System.Linq;
using System.Threading.Tasks;

namespace VM
{
  public enum MessageBoxButtonVM
  {
    OK,
    OKCancel,
    YesNo
  }

  public enum MessageBoxImageVM
  {
    None,
    Information,
    Question,
    Error
  }

  public class MessageBoxArgs
  {
    public MessageBoxButtonVM Buttons { get; set; }
    public MessageBoxImageVM Icon { get; set; }
    public string Title { get; set; }
    public string Message { get; set; }
  }

  //For custom dialogs that return a value
  public class MessageBoxNotificationWithAction<T>
  {
    private readonly Action<T> _callback;

    public MessageBoxArgs Notification { get; set; }

    public MessageBoxNotificationWithAction(MessageBoxArgs notification, Action<T> callback)
    {
      Notification = notification;

      CheckCallback(callback);
      _callback = callback;
    }

    public virtual void Execute(T argument)
    {
      _callback.Invoke(argument);
    }

    private static void CheckCallback(Delegate callback)
    {
      if (callback == null)
      {
        throw new ArgumentNullException(nameof(callback), "Callback must not be null");
      }
    }
  }

  /// <summary>
  /// Provides an implementation-agnostic way of communicating with the user through dialog boxes. Clients must register for communication messages using
  /// MVVM Light messaging system.
  /// </summary>
  public class DialogService : GalaSoft.MvvmLight.Views.IDialogService
  {
    private static GalaSoft.MvvmLight.Messaging.IMessenger Messenger = GalaSoft.MvvmLight.Messaging.Messenger.Default;

    private string _ProductName = "";

    public string ProductName
    {
      get
      {
        if (_ProductName == "")
        {
          //The following statement returns the Title attribute of the current assembly, as defined in project properties (Assembly Information dialog).
          var TitleAttrib = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributesData().First(x => x.AttributeType.Name == "AssemblyTitleAttribute");

          if (TitleAttrib != null)
          {
            _ProductName = TitleAttrib.ConstructorArguments[0].Value.ToString();
          }
          else
          {
            _ProductName = "Default Application Name";
          }
        }

        return _ProductName;
      }
    }

    public Task ShowError(Exception error, string title, string buttonText, Action afterHideCallback)
    {
      return ShowError(error.Message, title, buttonText, afterHideCallback);
    }

    public Task ShowMessage(string message, string title)
    {
      return Task.Run(() => MessengerSend(message, title, MessageBoxButtonVM.OK, MessageBoxImageVM.Error));
    }

    public Task ShowError(string message, string title, string buttonText, Action afterHideCallback)
    {
      return Task.Run(() =>
      {
        MessengerSend(message, title, MessageBoxButtonVM.OK, MessageBoxImageVM.Error);
        afterHideCallback?.Invoke();
      });
    }

    public Task ShowMessage(string message, string title, string buttonText, Action afterHideCallback)
    {
      return Task.Run(() =>
      {
        MessengerSend(message, title);
        afterHideCallback?.Invoke();
      });
    }

    public Task<bool> ShowMessage(string message, string title, string buttonConfirmText, string buttonCancelText, Action<bool> afterHideCallback)
    {
      if ((buttonConfirmText == "OK" && buttonCancelText == "Cancel") ||
        (buttonConfirmText == "Yes" && buttonCancelText == "No"))
      {
        return Task.Run<bool>(() =>
        {
          MessageBoxButtonVM btn;
          if (buttonConfirmText == "OK")
            btn = MessageBoxButtonVM.OKCancel;
          else
            btn = MessageBoxButtonVM.YesNo;


          bool Response = false;
          Messenger.Send(new MessageBoxNotificationWithAction<bool>(
                                                      new MessageBoxArgs()
                                                      {
                                                        Buttons = btn,
                                                        Icon = MessageBoxImageVM.Question,
                                                        Title = (string.IsNullOrEmpty(title) ? _ProductName : title),
                                                        Message = message
                                                      },
                                                      (result) => Response = result
                                                        ));

          afterHideCallback?.Invoke(Response);

          return Response;
        });
      }
      else
        throw new ArgumentException($"{nameof(buttonConfirmText)} and {nameof(buttonCancelText)} must either be OK/Cancel or Yes/No.");
    }

    /// <summary>
    /// For debugging purpose only
    /// </summary>
    /// <param name="message"></param>
    /// <param name="title"></param>
    /// <returns></returns>
    public Task ShowMessageBox(string message, string title) => ShowMessage(message, title);

    private void MessengerSend(string msg, string title = "", MessageBoxButtonVM btn = MessageBoxButtonVM.OK, MessageBoxImageVM icon = MessageBoxImageVM.Information)
    {
      Messenger.Send(new MessageBoxArgs()
      {
        Buttons = MessageBoxButtonVM.OK,
        Icon = MessageBoxImageVM.Information,
        Title = (string.IsNullOrEmpty(title) ? _ProductName : title),
        Message = msg
      });
    }
  }
}

вот слой презентации (переходит в посмотреть)

using System.Windows;
using VM;

namespace View
{
  class DialogPresenter
  {
    private Window _Parent;

    public DialogPresenter()
    {
      //For simple information boxes
      GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<MessageBoxArgs>(this, (arg) => ShowDialog(arg));

      //For Yes/No or OK/Cancel dialog boxes.
      GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<MessageBoxNotificationWithAction<bool>>(this, (arg) => arg.Execute(ShowDialog(arg.Notification)));

      //For notifications that require a string response (such as Manual Timeslot Description)
      GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<MessageBoxNotificationWithAction<string>>(this,
        (arg) => arg.Execute(ShowStringInputDialog(arg.Notification.Title, arg.Notification.Message)));
    }

    private bool ShowDialog(MessageBoxArgs arg)
    {
      MessageBoxButton btn = MessageBoxButton.OK;
      MessageBoxImage ico = MessageBoxImage.None;

      switch (arg.Buttons)
      {
        case MessageBoxButtonVM.OK: btn = MessageBoxButton.OK; break;
        case MessageBoxButtonVM.OKCancel: btn = MessageBoxButton.OKCancel; break;
        case MessageBoxButtonVM.YesNo: btn = MessageBoxButton.YesNo; break;
      }

      switch (arg.Icon)
      {
        case MessageBoxImageVM.Error: ico = MessageBoxImage.Error; break;
        case MessageBoxImageVM.Information: ico = MessageBoxImage.Information; break;
        case MessageBoxImageVM.None: ico = MessageBoxImage.None; break;
        case MessageBoxImageVM.Question: ico = MessageBoxImage.Question; break;
      }

      bool Result = false;
      _Parent.Dispatcher.Invoke(() =>
      {
        var Res = MessageBox.Show(arg.Message, arg.Title, btn, ico);
        Result = (Res == MessageBoxResult.OK || Res == MessageBoxResult.Yes);
      });

      return Result;
    }

    private string ShowStringInputDialog(string title, string description, string value = "", int maxLength = 100)
    {
      string Result = null;

      _Parent.Dispatcher.Invoke(() =>
      {
        //InputBox is a WPF Window I created for taking simple
        //string values from the user. This also shows that you can
        //any custom dialog using this approach.

        InputBox input = new InputBox();
        input.Title = title;
        input.Owner = _Parent;
        if (input.ShowDialog(description, value, maxLength).Value)
          Result=input.Value;
        else
          Result=null;
      });

      return Result;
    }

    //Call this somewhere at application startup so that the dialog boxes
    //appear as child windows.
    public void SetParentWindow(Window parent)
    {
      _Parent = parent;
    }
  }
}

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

мое текущее решение выглядит так:

public class SelectionTaskModel<TChoosable> : ViewModel
    where TChoosable : ViewModel
{
    public SelectionTaskModel(ICollection<TChoosable> choices);
    public ReadOnlyCollection<TChoosable> Choices { get; }
    public void Choose(TChoosable choosen);
    public void Abort();
}

когда модель представления решает, что требуется ввод пользователя, она вытаскивает экземпляр SelectionTaskModel с возможными вариантами для пользователя. Инфраструктура заботится о том, чтобы вызвать соответствующий вид, который в свое время вызовет Choose() функция с потребителем выбор.


Я боролся с той же проблемой. Я придумал способ взаимодействия между View и ViewModel. Вы можете инициировать отправку сообщения из ViewModel в представление, чтобы показать messagebox, и он сообщит об этом с результатом. Затем ViewModel может ответить на результат, возвращенный из представления.

я демонстрирую это в мой блог:


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

https://www.codeproject.com/Articles/820324/Implementing-Dialog-Boxes-in-MVVM


Извините, но я должен присоединиться. Я прошел через несколько предложенных решений, прежде чем нашел призму.В WPF.Пространство имен интерактивности в проекте Prism. Вы можете использовать запросы на взаимодействие и действие всплывающего окна, чтобы либо свернуть пользовательское окно, либо для более простых нужд. Они создают true windows и управляются как таковые. в диалоговом окне можно передать объект контекста с любыми зависимостями. Мы используем это решение на моем работа с тех пор, как я ее нашел. У нас здесь много старших разработчиков, и никто не придумал ничего лучше. Нашим предыдущим решением был диалоговый сервис в оверлей и использование класса presenter, чтобы это произошло, но вы должны были иметь фабрики для всех диалоговых моделей и т. д.

Это не тривиально, но и не очень сложно. И он встроен в призму и поэтому лучше (или лучше) практиковать ИМХО.

мои 2 цента!


EDIT: да, я согласен, что это не правильный подход MVVM, и теперь я использую что-то похожее на то, что предлагается blindmeis.

один из способов вы могли бы это

В вашей модели основного вида (где вы открываете модальный):

void OpenModal()
{
    ModalWindowViewModel mwvm = new ModalWindowViewModel();
    Window mw = new Window();
    mw.content = mwvm;
    mw.ShowDialog()
    if(mw.DialogResult == true)
    { 
        // Your Code, you can access property in mwvm if you need.
    }
}

и в вашем модальном окне View / ViewModel:

XAML:

<Button Name="okButton" Command="{Binding OkCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">OK</Button>
<Button Margin="2" VerticalAlignment="Center" Name="cancelButton" IsCancel="True">Cancel</Button>

ViewModel:

public ICommand OkCommand
{
    get
    {
        if (_okCommand == null)
        {
            _okCommand = new ActionCommand<Window>(DoOk, CanDoOk);
        }
        return _okCommand ;
    }
}

void DoOk(Window win)
{
    <!--Your Code-->
    win.DialogResult = true;
    win.Close();
}

bool CanDoOk(Window win) { return true; }

или аналогично тому, что опубликовано здесь WPF MVVM: как закрыть окно