Как вы успешно реализовали функциональность MessageBox.Show() в MVVM?

StackOverflow https://stackoverflow.com/questions/1098023

  •  11-09-2019
  •  | 
  •  

Вопрос

У меня есть приложение WPF который вызывает MessageBox.Show() еще во ViewModel (чтобы проверить, действительно ли пользователь хочет удалить). Это действительно работает, но идет вразрез с принципом MVVM поскольку ViewModel не должна явно определять, что происходит в представлении.

Итак, теперь я думаю как мне лучше всего реализовать функциональность MessageBox.Show() в моем приложении MVVM параметры:

  1. Я мог бы получить сообщение с текстом "Вы уверены ...?" Наряду с двумя кнопками «да» и «нет» на границе в моем XAML, и создать триггер на шаблоне, чтобы он был рухну AreYourSureDialogueBoxIsVisible, а затем, когда мне понадобится это диалоговое окно, присвойте AreYourSureDialogueBoxIsVisible значение «true», а также обработайте две кнопки через DelegateCommand обратно в мою ViewModel.

  2. Я также мог бы каким-то образом попытаться обработать это с помощью триггеров в XAML, чтобы кнопка «Удалить» фактически просто вызывала появление некоторого элемента Border с сообщением и кнопками в нем, а кнопка «Да» фактически выполняла удаление.

Оба решения кажутся слишком сложными для того, что раньше было парой строк кода с MessageBox.Show().

Каким образом вы успешно реализовали диалоговые окна в своих приложениях MVVM?

Это было полезно?

Решение

Из двух упомянутых вами вариантов я предпочитаю вариант №2.Кнопка «Удалить» на странице просто вызывает появление «Диалог подтверждения удаления».«Диалог подтверждения удаления» фактически запускает удаление.

Вы проверяли Карла Шиффлетта? Слайды и демонстрации направления бизнеса WPF?Я знаю, что он делает что-то подобное.Попробую вспомнить где.

РЕДАКТИРОВАТЬ:Ознакомьтесь с демонстрацией № 11 «Проверка данных в MVVM» (EditContactItemsControlSelectionViewModel.DeleteCommand).Карл вызывает всплывающее окно из ViewModal (Что!?:-).Мне вообще-то твоя идея больше нравится.Кажется, проще провести модульное тестирование.

Другие советы

Службы спасения.С использованием Оникс (отказ от ответственности, я автор) это так же просто, как:

public void Foo()
{
    IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
    dm.Show("Hello, world!");
}

В запущенном приложении это косвенно вызовет MessageBox.Show("Hello, world!").При тестировании сервис IDisplayMessage можно имитировать и предоставлять ViewModel, чтобы он мог делать все, что вы хотите выполнить во время теста.

Чтобы расширить ответ Дина Чока теперь, когда его ссылка окончена:

В файле App.xaml.cs мы подключаем диалоговое окно подтверждения к модели представления.

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    var confirm = (Func<string, string, bool>)((msg, capt) => MessageBox.Show(msg, capt, MessageBoxButton.YesNo) == MessageBoxResult.Yes);
    var window = new MainWindowView();
    var viewModel = new MainWindowViewModel(confirm);
    window.DataContext = viewModel;
    ...
}

В представлении (MainWindowView.xaml) у нас есть кнопка, вызывающая команду во ViewModel.

<Button Command="{Binding Path=DeleteCommand}" />

ViewModel (mainwindowviewmodel.cs) использует команду делегата, чтобы показать "вы уверены?" диалог и выполните действие.В данном примере это SimpleCommand похожий на этот, но подойдет любая реализация ICommand.

private readonly Func<string, string, bool> _confirm;

//constructor
public MainWindowViewModel(Func<string, string, bool> confirm)
{
    _confirm = confirm;
    ...
}

#region Delete Command
private SimpleCommand _deleteCommand;
public ICommand DeleteCommand
{
    get { return _deleteCommand ?? (_deleteCommand = new SimpleCommand(ExecuteDeleteCommand, CanExecuteDeleteCommand)); }
}

public bool CanExecuteDeleteCommand()
{
    //put your logic here whether to allow deletes
    return true;
}

public void ExecuteDeleteCommand()
{
    bool doDelete =_confirm("Are you sure?", "Confirm Delete");
    if (doDelete)
    {
        //delete from database
        ...
    }
}
#endregion

Я просто создаю интерфейс (IMessageDisplay или аналогичный), который внедряется в виртуальную машину, и у него есть такие методы, как MessageBox (ShowMessage() и т. д.).Вы можете реализовать это, используя стандартное окно сообщений или что-то более специфичное для WPF (я использую это на CodePlex какой-то парень по имени Праджиш).

Таким образом, все разделено и тестируемо.

А как насчет создания такого события, как "MessageBoxRequested" обрабатывается в выделенном коде представления (в любом случае это код только для просмотра, поэтому я не вижу никаких проблем с наличием этого кода в выделенном коде).

Я создал простой элемент управления-оболочки MessageBox, который мы можем использовать в чистом решении MVVM, при этом сохраняя возможность модульного тестирования.Подробности в моем блоге http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

мукапу

Я реализовал поведение, которое прослушивает сообщение из ViewModel.Он основан на решении Лорана Бюньона, но, поскольку он не использует код и его можно использовать повторно, я думаю, что он более элегантен.

Проверьте это здесь

Окна сообщений WPF и Silverlight

MVVM поддерживается

http://slwpfmessagebox.codeplex.com/

На всякий случай, если кто-то еще читает и недоволен:

Я просто хотел обработать MessageBoxes типа «уведомление» (т.меня не волнует DialogResult), но проблема с большинством решений, о которых я читал, заключается в том, что они, похоже, косвенно заставляют вас выбирать реализацию View (то есть в настоящее время у меня есть MessageBox.Show, но если позже я решу просто поиграть с видимостью скрытой панели непосредственно в моем представлении, это не будет очень хорошо сочетаться с INotification интерфейс, переданный в ViewModel).

Поэтому я пошел быстро и грязно:

ViewModel имеет string NotificationMessage имущество, об изменениях уведомлено PropertyChanged.

Представление подписывается на PropertyChanged, и если он увидит NotificationMessage собственность проходит, делает все, что хочет.

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

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

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

Недавно я столкнулся с этой проблемой, когда мне пришлось заменить MessageBox.Show в ViewModels каким-то полностью механизмом окна сообщений о жалобах MVVM.

Чтобы добиться этого, я использовал InteractionRequest<Notification> и InteractionRequest<Confirmation> вместе с триггерами взаимодействия и написал свои собственные представления для окна сообщений.

То, что я реализовал, опубликовано здесь

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

Но если вы просто хотите использовать обычное окно сообщения от Microsoft для своего приложения WPF, вот реализация, удобная для MVVM/юнит-теста:

Первоначально я думал, что просто унаследую окно сообщения и оберну его интерфейсом, но не смог из-за того, что в окне сообщения нет общедоступного конструктора, поэтому вот «простое» решение:

Декомпилируя окно сообщения в Visual Studio, вы можете увидеть все перегрузки методов, я проверил, какие из них мне нужны, затем создал новый класс и добавил методы, обернул его интерфейсом и та-да!Теперь вы можете использовать ninject для привязки интерфейса и класса, внедрить его и использовать Moq для модульного тестирования и т. д.

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

public interface IMessageBox
    {
        /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>          
        MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button);

        /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>           
        MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);

        /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
        MessageBoxResult Show(string messageBoxText, string caption);
    }

Затем у нас есть класс, который будет от него наследовать:

public class MessageBoxHelper : IMessageBox
    {
        /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button,
            MessageBoxImage icon)
        {
            return MessageBox.Show(messageBoxText, caption, button, icon, MessageBoxResult.None,
                MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
        {
            return MessageBox.Show(messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None,
                MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption)
        {
            return MessageBox.Show(messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None,
                MessageBoxResult.None, MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message and that returns a result.</summary>           
        public MessageBoxResult Show(string messageBoxText)
        {
            return MessageBox.Show(messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None,
                MessageBoxResult.None, MessageBoxOptions.None);
        }
    }

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top