Comment avez-vous mis en œuvre avec succès la fonctionnalité MessageBox.Show () dans MVVM?

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

  •  11-09-2019
  •  | 
  •  

Question

J'ai une application WPF qui appelle MessageBox.Show () retour dans le ViewModel (pour vérifier si l'utilisateur veut vraiment supprimer). Cela fonctionne en fait , mais va à l'encontre du grain de MVVM depuis le ViewModel ne devrait pas déterminer explicitement ce qui se passe dans la vue.

Alors maintenant, je pense Comment puis-je mieux mettre en œuvre la fonctionnalité MessageBox.Show () dans mon application MVVM options:

  1. Je pourrais avoir un message avec le texte « Êtes-vous sûr ...? » ainsi que deux boutons Oui et Non tout dans une frontière dans mon XAML, et créer un déclencheur sur le modèle de sorte qu'il est réduit / visible basée sur un ViewModelProperty appelé AreYourSureDialogueBoxIsVisible , puis quand j'ai besoin de ce dialogue boîte, assigner AreYourSureDialogueBoxIsVisible à "true", et gérer aussi les deux boutons via DelegateCommand dans mon ViewModel.

  2. Je pourrais aussi essayer une certaine façon de gérer cela avec des déclencheurs dans XAML de sorte que le bouton Supprimer en fait juste fait un élément de frontière apparaît avec le message et les boutons en lui, et le bouton Oui a fait la suppression de fait.

Les deux solutions semblent être trop complexes pour ce qui était autrefois quelques lignes de code avec MessageBox.Show ().

De quelle manière avez-vous mis en œuvre avec succès les boîtes de dialogue dans vos applications MVVM?

Était-ce utile?

La solution

les deux que vous mentionnez, je préfère l'option # 2. Le bouton Supprimer sur la page fait juste la « Confirmer la suppression de dialogue » apparaît. La « Confirmer la suppression de dialogue » coups de pied fait de la suppression.

Avez-vous vérifié Karl Shifflett WPF ligne de diapositives affaires et démonstrations ? Je sais qu'il fait quelque chose comme ça. Je vais essayer de me rappeler où.

EDIT: Voir la démo # 11 "Validation des données dans MVVM" (EditContactItemsControlSelectionViewModel.DeleteCommand). Karl appelle un pop-up de la ViewModal (What !? :-). J'aime réellement votre meilleure idée. Il semble plus facile à l'unité de test.

Autres conseils

Services à la rescousse. En utilisant Onyx (disclaimer, je suis l'auteur), c'est aussi facile que:

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

Dans une application en cours d'exécution, ce appellera indirectement MessageBox.Show ( "Bonjour, monde!"). Lors du test, le service IDisplayMessage peut être moqué et fourni au ViewModel pour faire ce que vous voulez accomplir pendant le test.

Pour développer la réponse de Dean Chalk maintenant que son lien est kaput:

Dans le fichier App.xaml.cs nous accrochons la boîte de dialogue de confirmation à l'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;
    ...
}

Dans la vue (MainWindowView.xaml), nous avons un bouton qui appelle une commande dans le ViewModel

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

Le viewmodel (MainWindowViewModel.cs) utilise une commande de délégué pour montrer le « Êtes-vous sûr? » dialogue et exécuter l'action. Dans cet exemple, est un SimpleCommand similaire à cette , mais toute mise en œuvre de ICommand devrait faire.

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

Je viens de créer une interface (IMessageDisplay ou similaire) qui obtient injecté dans la machine virtuelle, et il a des méthodes comme un MessageBox (ShowMessage (), etc.). Vous pouvez mettre en œuvre que l'utilisation d'un messagebox standard, ou quelque chose de plus spécifique WPF (j'utilise celui-ci sur CodePlex un gars appelé Prajeesh).

De cette façon, tout est séparé et testables.

Qu'en est-il un événement comme élever "MessageBoxRequested" manipulé dans le codebehind de la vue (de toute façon, il est Afficher uniquement le code, donc je ne vois aucun problème d'avoir ce code sur le codebehind).

Je l'ai fait d'un simple contrôle d'emballage MessageBox pour nous d'utiliser en solution MVVM pure et en permettant une capacité de tests unitaires. Les détails sont dans mon blog http: //geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

mukapu

Je l'ai mis en place un comportement qui écoute un message du ViewModel. Il est basé sur la solution Laurent Bugnion, mais comme il n'utilise pas le code derrière et est plus réutilisable, je pense qu'il est plus élégant.

Check it out ici

WPF et Silverlight MessageBoxes

MVVM supporté

http://slwpfmessagebox.codeplex.com/

Juste au cas où quelqu'un d'autre est lu encore et insatisfait:

Je voulais juste traiter de type « notification » MessageBoxes (c.-à-je ne me soucie pas du DialogResult), mais le problème que j'ai avec la plupart des solutions que j'ai lu est à ce sujet qu'ils semblent vous forcer indirectement à choisir Voir la mise en œuvre (qui est, actuellement, j'ai un MessageBox.Show, mais si je décide plus tard à jouer du violon juste avec la visibilité d'un panneau caché directement à mon avis, ce ne sera pas maille très bien avec une interface INotification passé dans la ViewModel).

Alors je suis allé pour rapide et sale:

Le ViewModel possède une propriété string NotificationMessage, avec des changements notifiés à PropertyChanged.

Le point de vue à abonne PropertyChanged, et si elle voit la propriété NotificationMessage venir à travers, fait ce qu'il veut.

OK, donc cela signifie que la vue a code-behind, et le nom de PropertyChanged est codé en dur, mais il serait codé en dur dans le XAML de toute façon. Et cela signifie que j'évite tous les trucs comme convertisseurs de visibilité, et les propriétés de dire si la notification est encore visible ou non.

(Il est vrai que cela est juste pour un cas d'utilisation limitée (incendie et d'oublier), je ne l'ai pas beaucoup réfléchi à la façon dont je pourrais vouloir l'étendre.)

Je voudrais juste jeter de la machine virtuelle. Je ne veux pas avoir à utiliser le service de quelqu'un d'autre ou d'écrire mon propre juste pour jeter un messagebox.

Je suis récemment tombé sur ce problème où je devais remplacer le MessageBox.Show dans les ViewModels avec un mécanisme de boîte de message entièrement MVVM plainte.

Pour cela je InteractionRequest<Notification> et InteractionRequest<Confirmation> ainsi que l'interaction déclenche et écrit mes propres vues pour la boîte de message.

Ce que j'ai mis est publié

Il y a tant de réponses à ce sujet qui varient de créer une classe personnalisée à l'aide de bibliothèques de tiers. Je dirais utiliser une bibliothèque tierce partie si vous voulez pop ups cool avec des visuels de Nice.

Mais si vous voulez juste utiliser la boîte de message régulier de Microsoft pour votre application WPF est ici un MVVM / test unitaire mise en œuvre amicale:

Dans un premier temps je pensais simplement hériter de boîte de message et l'envelopper avec une interface, mais je ne pouvais pas en raison de boîte de message ne pas avoir un constructeur public, alors voici la solution « facile »:

décompilation boîte de message en studio visuel que vous pouvez voir toutes les surcharges de méthode, j'ai vérifié que ceux que je voulais ensuite créé une nouvelle classe et ajouté les méthodes, enveloppa avec une interface et ta-da! Maintenant, vous pouvez utiliser ninject pour lier l'interface et la classe, injecter et utiliser Moq pour e.t.c de test unitaire.

Créer une interface (seulement ajouté quelques-unes des que je ne surcharge pas besoin d'eux tous):

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);
    }

Ensuite, nous avons la classe qui héritera de celui-ci:

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);
        }
    }

Maintenant, il suffit d'utiliser ce lors de l'injection e.t.c et boum u ont une abstraction qui fragile l'affaire ... ce qui est bien en fonction de l'endroit où vous allez l'utiliser. Mon cas est une application simple que destiné à faire quelques petites choses, donc pas de point sur l'ingénierie d'une solution. Espérons que cela aide quelqu'un.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top