Как вы успешно реализовали функцию MessageBox.Show() в MVVM?
У меня есть приложение WPF , которое вызывает MessageBox.Show() обратно в ViewModel (чтобы проверить, действительно ли пользователь хочет удалить). Это действительно работает, но идет против зерна MVVM, поскольку ViewModel не должен явно определять, что происходит в представлении.
Итак, теперь я думаю, что как лучше всего реализовать функцию MessageBox.Show() в моем приложении MVVM, параметры:
-
У меня могло бы быть сообщение с текстом "Вы уверены...?" наряду с двумя кнопками "Да" и "Нет" на границе в моем XAML и создайте триггер на шаблоне, чтобы он был свернут/виден на основе ViewModelProperty, называемого AreYourSureDialogueBoxIsVisible, а затем, когда мне нужен этот диалог box, присвойте AreYourSureDialogueBoxIsVisible значение "true", а также обработайте две кнопки через DelegateCommand обратно в моей ViewModel.
-
Я мог бы как-то попытаться обработать это с помощью триггеров в XAML, чтобы кнопка Delete фактически просто создавала элемент Border с сообщением и кнопками в нем, а кнопка Yes действительно удаляла.
Оба решения кажутся слишком сложными для того, что раньше было рядом строк кода с MessageBox.Show().
Каким образом вы успешно реализовали диалоговые окна в ваших MVVM-приложениях?
Ответы
Ответ 1
Из двух вы упомянули, я предпочитаю вариант № 2. Кнопка "Удалить" на странице просто заставляет "Подтвердить диалог удаления". Диалоговое окно "Подтвердить удаление" фактически отменяет удаление.
Вы проверили Karl Shifflett WPF Line Business Slides and Demos? Я знаю, что он делает что-то подобное. Я постараюсь запомнить, где.
EDIT: ознакомьтесь с демонстрацией № 11 "Проверка данных в MVVM" (EditContactItemsControlSelectionViewModel.DeleteCommand). Карл называет всплывающее окно из ViewModal (What!?:-). Мне больше нравится ваша идея. Кажется, проще Unit Test.
Ответ 2
Службы на помощь. Используя Onyx (отказ от ответственности, я автор) это так же просто, как:
public void Foo()
{
IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
dm.Show("Hello, world!");
}
В запущенном приложении это косвенно вызовет MessageBox.Show( "Hello, world!" ). При тестировании службы IDisplayMessage можно высмеять и предоставить ViewModel для выполнения того, что вы хотите выполнить во время теста.
Ответ 3
Я просто создаю интерфейс (IMessageDisplay или аналогичный), который вводится в виртуальную машину, и он имеет такие методы, как MessageBox (ShowMessage() и т.д.). Вы можете реализовать это, используя стандартный почтовый ящик или что-то большее, чем WPF (я использую этот на CodePlex какой-то парень по имени Prajeesh).
Таким образом, все разделено и проверяемо.
Ответ 4
Как насчет создания события типа "MessageBoxRequested"
, которое обрабатывается в кодовой форме представления (в любом случае это просмотр только кода, поэтому я не вижу проблемы с тем, что этот код имеет код).
Ответ 5
Чтобы развернуть на Dean Chalk, ответьте, что его ссылка kaput:
В файле App.xaml.cs мы подключаем диалог подтверждения к viewmodel.
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
похожее на this, но любая реализация 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
Ответ 6
Я создал простой элемент управления оболочкой MessageBox для использования в чистом решении MVVM и все еще допускаю возможности тестирования модулей. Подробности в моем блоге http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx
mukapu
Ответ 7
Я реализовал поведение, которое прослушивает сообщение из ViewModel. Это основано на решении Laurent Bugnion, но поскольку он не использует код и больше подходит для повторного использования, я считаю его более элегантным.
Проверьте здесь
Ответ 8
WPF и Silverlight MessageBoxes
Поддержка MVVM
http://slwpfmessagebox.codeplex.com/
Ответ 9
На всякий случай кто-то еще читает и неудовлетворен:
Я просто хотел обработать "MessageBox" типа "уведомления" (то есть меня не волнует DialogResult
), но проблема, с которой я сталкиваюсь в большинстве решений, о которых я читал, состоит в том, что они, по-видимому, косвенно вынуждают вас выберите свою реализацию вида (то есть, в настоящее время у меня есть MessageBox.Show
, но если я позже решу просто поиграть с видимостью скрытой панели непосредственно в моем представлении, это не будет очень хорошо связано с интерфейсом INotification
в ViewModel).
Итак, я пошел быстро и грязно:
ViewModel имеет свойство string NotificationMessage
, с изменениями, уведомленными о PropertyChanged
.
The View подписывается на PropertyChanged
, и если он видит свойство NotificationMessage
, он делает все, что захочет.
ОК, поэтому это означает, что View имеет код-позади, а имя PropertyChanged
жестко закодировано, но в любом случае оно будет жестко закодировано в XAML. И это означает, что я избегаю всех таких вещей, как конвертеры для видимости, и свойства, чтобы сказать, остается ли уведомление все еще видимым или нет.
(По общему признанию, это просто ограниченный случай использования (огонь и забыть), я не думал о том, как я могу его расширить.)
Ответ 10
Я просто выброшу его из виртуальной машины. Я не хочу использовать чужую службу или написать свой собственный, просто чтобы бросить сообщение.
Ответ 11
Недавно я столкнулся с этой проблемой, когда мне пришлось заменить MessageBox.Show в ViewModels некоторым механизмом механизма сообщения с жалобами MVVM.
Для этого я использовал InteractionRequest<Notification>
и InteractionRequest<Confirmation>
вместе с триггерами взаимодействия и написал свои собственные представления для окна сообщения.
Я опубликовал здесь
Ответ 12
В этой теме так много ответов, которые варьируются от создания пользовательского класса до использования сторонних библиотек. Я бы сказал, пользуюсь сторонней библиотекой, если вам нужны крутые всплывающие окна с приятными визуальными эффектами.
Но если вы просто хотите использовать регулярное окно сообщений из microsoft для своего приложения WPF, то это совместимая с MVVM/unit версия:
Первоначально я думал, что просто унаследовал бы от окна сообщения и обернул бы его интерфейсом, но я не мог из-за того, что окно Message не имело публичного конструктора, так что вот "простое" решение:
Декомпиляция окна сообщений в visual studio вы можете увидеть все перегрузки метода, я проверил, какие из них я хотел, а затем создал новый класс и добавил методы, завернул его с интерфейсом и ta-da! Теперь вы можете использовать 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);
}
}
Теперь просто используйте это при инъекциях и т.д., И бум у вас есть фальшивая абстракция, которая будет делать трюк... что отлично в зависимости от того, где вы будете его использовать. Мое дело - простое приложение, предназначенное только для того, чтобы сделать несколько вещей, поэтому не стоит конструировать решение. Надеюсь, это поможет кому-то.