Wie haben Sie die Funktionalität von messageBox.show () in MVVM erfolgreich implementiert?

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

  •  11-09-2019
  •  | 
  •  

Frage

Ich habe eine WPF -Anwendung Welches Anruf von messageBox.show () zurück im ViewModel (Um zu überprüfen, ob der Benutzer wirklich löschen möchte). Das funktioniert tatsächlich, aber geht gegen das Korn von MVVM Da das ViewModel nicht explizit bestimmen sollte, was in der Ansicht passiert.

Also denke ich jetzt nach Wie kann ich die Funktionalität von MessageBox.show () am besten implementieren? In meiner MVVM -Anwendung Optionen:

  1. Ich könnte eine Nachricht mit dem Text haben "Bist du sicher ...?" Zusammen mit zwei Schaltflächen Ja und nein in einem Rand in meinem XAML und erstellen AreyoursuredialogueBoxisvisible, Und dann, wenn ich dieses Dialogfeld brauche, weisen Sie "areyoursureuredialogueBoxisible" zu "True" zu und behandeln Sie die beiden Schaltflächen über DelegateCommand wieder in meinem ViewModel.

  2. Ich könnte auch irgendwie versuchen, dies mit Triggern in XAML zu verarbeiten, so dass die Schaltfläche Löscher tatsächlich nur ein Randelement mit der Nachricht und den Schaltflächen in der Taste erscheint, und die Ja -Taste hat das tatsächlich gelöscht.

Beide Lösungen scheinen zu komplex zu sein für das, was früher ein paar Codezeilen mit MessageBox.show () waren.

Inwiefern haben Sie Dialogfelder in Ihren MVVM -Anwendungen erfolgreich implementiert?

War es hilfreich?

Lösung

Von den beiden, die Sie erwähnen, bevorzuge ich Option Nr. 2. Auf der Schaltfläche Löschen auf der Seite wird das Dialogfeld "Dialog" "Löschen bestätigen" angezeigt. Der Dialogfeld "Löschen bestätigen" startet tatsächlich das Löschen.

Haben Sie Karl Shiffletts ausgecheckt WPF -Linie von Geschäftsfolien und Demos? Ich weiß, dass er so etwas tut. Ich werde versuchen, mich zu erinnern, wo.

Bearbeiten: Überprüfen Sie die Demo #11 "Datenvalidierung in MVVM" (editContactItemsControlSectionViewModel.DeletEcommand). Karl ruft ein Popup aus dem ViewModal an (was!? :-). Ich mag deine Idee tatsächlich besser. Scheint leichter zu Unit -Test zu sein.

Andere Tipps

Dienstleistungen zur Rettung. Verwendung Onyx (Haftungsausschluss, ich bin der Autor) Dies ist so einfach wie:

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

In einer laufenden Anwendung wird dies indirekt MessageBox.show ("Hallo, Welt!"). Beim Testen kann der IDISPlayMessage -Service verspottet und dem ViewModel zur Verfügung gestellt werden, um das zu tun, was Sie während des Tests erreichen möchten.

Um Dean Chalks Antwort zu erweitern, ist sein Link Kaput:

In der Datei app.xaml.cs verbinden wir den Dialogfeld "Bestätigung" an das 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;
    ...
}

In der Ansicht (MainWindowview.xaml) haben wir eine Schaltfläche, die einen Befehl im ViewModel aufruft

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

Das ViewModel (MainWindowViewModel.cs) verwendet einen Delegiertenbefehl, um das "Bist du sicher?" Anzuzeigen? Dialog und führen Sie die Aktion aus. In diesem Beispiel ist es a SimpleCommand ähnlich zu Dies, aber jede Implementierung von Icommand sollte tun.

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

Ich erstelle nur eine Schnittstelle (iMessageDisplay oder ähnliches), die in die VM eingefügt wird, und es verfügt über Methoden wie eine MessageBox (ShowMessage () usw.). Sie können diese mithilfe eines Standard -MessageBox oder etwas mehr WPF -Spezifikums implementieren (ich verwende ich Dieser auf Codeplex Ein Typ nannte Prajeesh).

Auf diese Weise ist alles getrennt und überprüfbar.

Was ist mit der Erhöhung eines Ereignisses wie "MessageBoxRequested" Im Codebehind der Ansicht gehandhabt (trotzdem ist es nur Codes -Codes, sodass ich kein Problem damit sehe, diesen Code auf dem CodeBehind zu haben).

Ich habe eine einfache MessageBox -Wrapper -Steuerung für uns in reiner MVVM -Lösung erstellt und dennoch die Funktionen für die Einheitstests ermöglicht. Die Details sind in meinem Blog http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvm.aspx

mukapu

Ich habe ein Verhalten implementiert, das eine Nachricht aus dem ViewModel hört. Es basiert auf Laurent Bugnion -Lösung, aber da es keinen Code dahinter verwendet und wiederverwendbarer ist, denke ich, dass es eleganter ist.

Schau es dir hier an

WPF & Silverlight MessageBoxes

MVVM unterstützt

http://slwpfmessagebox.codeplex.com/

Nur für den Fall, dass jemand anderes noch liest und unzufrieden ist:

Ich wollte nur "Benachrichtigung" -Typ -MessageBoxes verarbeiten (dh ich kümmere mich nicht um die DialogResult), aber das Problem, das ich mit den meisten Lösungen habe, die ich gelesen habe MessageBox.Show, aber wenn ich mich später entscheide, nur mit der Sichtbarkeit eines versteckten Panels direkt zu verwirklichen INotification Schnittstelle an das ViewModel übergeben).

Also ging ich schnell und schmutzig:

Das ViewModel hat a string NotificationMessage Eigenschaft, mit Änderungen, die an benachrichtigt werden können PropertyChanged.

Die Ansicht zeichnet sich an PropertyChanged, und wenn es das sieht NotificationMessage Eigentum kommt durch, tut alles, was es will.

Ok, das bedeutet also, dass die Ansicht Code-Behind und den Namen von enthält PropertyChanged ist hartcodiert, aber es wäre sowieso hart im XAML. Und es bedeutet, dass ich alle Dinge wie Konverter für die Sichtbarkeit und Eigenschaften vermeide, um zu sagen, ob die Benachrichtigung noch sichtbar ist oder nicht.

(Zugegeben, dies ist nur für einen begrenzten Anwendungsfall (Feuer und Vergessen), ich habe nicht viel darüber nachgedacht, wie ich es erweitern möchte.)

Ich würde es einfach von der VM werfen. Ich möchte nicht den Dienst eines anderen verwenden oder meinen eigenen schreiben müssen, um eine MessageBox zu werfen.

Ich bin kürzlich auf dieses Problem gestoßen, bei dem ich die MessageBox ersetzen musste.

Um dies zu erreichen, habe ich verwendet InteractionRequest<Notification> und InteractionRequest<Confirmation> Zusammen mit Interaktionsauslöschern und schrieb meine eigenen Ansichten für das Nachrichtenfeld.

Was ich implementiert habe, wird veröffentlicht hier

Es gibt so viele Antworten zu diesem Thema, die vom Erstellen einer benutzerdefinierten Klasse bis zur Verwendung von Bibliotheken von Drittanbietern variieren. Ich würde sagen, verwenden Sie eine Bibliothek von Drittanbietern, wenn Sie coole Popups mit schönen Visuals wünschen.

Wenn Sie jedoch nur das reguläre Nachrichtenfeld von Microsoft für Ihre WPF -App verwenden möchten, finden Sie hier eine mvvm/unit -Testfreundliche Implementierung:

Anfangs dachte ich, ich würde einfach aus dem Nachrichtenfeld erben und mit einer Schnittstelle einwickeln, aber ich konnte es nicht, weil es keinen öffentlichen Konstruktor hat, also ist hier die "einfache" Lösung:

Dekompilieren des Nachrichtenfelds in Visual Studio Sie können alle Methodenüberladungen sehen. Ich habe überprüft, welche ich wollte, dann eine neue Klasse erstellt und die Methoden hinzugefügt, sie mit einer Schnittstelle und TA-DA gewickelt haben! Jetzt können Sie Ninject verwenden, um die Schnittstelle und Klasse zu binden, injizieren und MOQ zum Unit -Test usw. verwenden

Erstellen Sie eine Schnittstelle (nur einige der Überladungen fügte hinzu, da ich sie nicht alle brauche):

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

Dann haben wir die Klasse, die daraus erben wird:

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

Verwenden Sie dies jetzt, wenn Sie usw. injizieren, und Boom Sie haben eine dünne Abstraktion, die den Trick macht ... was in Ordnung ist, je nachdem, wo Sie sie verwenden werden. Mein Fall ist eine einfache App, die nur ein paar Dinge erledigen soll, also keinen Sinn für die Entwicklung einer Lösung. Hoffe das hilft jemandem.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top