Domanda

Ho un'applicazione WPF che chiama MessageBox.Show () nel lontano ViewModel (per controllare se l'utente vuole cancellare). Questo funziona davvero , ma va contro il chicco di MVVM dal momento che il ViewModel non dovrebbe esplicitamente stabilire che cosa accade sulla vista.

Così ora sto pensando come posso meglio implementare la funzionalità MessageBox.Show () nella mia applicazione MVVM, opzioni:

  1. ho potuto avere un messaggio con il testo "Sei sicuro ...?" insieme a due pulsanti Sì e No tutto in un bordo nel mio XAML, e creare un trigger sul modello in modo che sia crollata / visibile sulla base di un ViewModelProperty chiamato AreYourSureDialogueBoxIsVisible , e poi, quando ho bisogno di questo dialogo scatola, assegnare AreYourSureDialogueBoxIsVisible a "true", e anche gestire i due pulsanti tramite DelegateCommand indietro nel mio ViewModel.

  2. Potrei anche in qualche modo cercare di gestire questo con i trigger in XAML in modo che il pulsante Elimina in realtà fa solo qualche elemento di confine appaiono con il messaggio e pulsanti in essa, e il pulsante Sì ha fatto la realtà eliminazione.

Entrambe le soluzioni sembrano essere troppo complesso per quello che era un paio di righe di codice con MessageBox.Show ().

In che modo avete implementato con successo finestre di dialogo nelle applicazioni MVVM?

È stato utile?

Soluzione

Tra i due si parla, io preferisco l'opzione # 2. Il pulsante Elimina sulla pagina rende solo la "Conferma eliminazione Dialog" apparire. Il "Conferma eliminazione Dialog" in realtà prende il via il Canc.

Avete verificato di Karl Shifflett WPF linea di business diapositive e Demos ? So che fa qualcosa di simile. Cercherò di ricordare dove.

EDIT: Partenza Demo # 11 "Convalida dati in MVVM" (EditContactItemsControlSelectionViewModel.DeleteCommand). Karl chiama un popup dal ViewModal (Cosa !? :-). Io in realtà piace la tua idea migliore. Sembra più facile da Unità di prova.

Altri suggerimenti

Servizi per il salvataggio. Utilizzando Onyx (dichiarazione di non responsabilità, io sono l'autore) questo è facile come:

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

In un'applicazione in esecuzione, questo sarà indirettamente chiamare MessageBox.Show ( "Ciao, mondo!"). Durante il test, il servizio IDisplayMessage può essere preso in giro e ha fornito al ViewModel per fare ciò che mai si vuole realizzare durante il test.

Per espandere sulla risposta di Dean Chalk ora che il suo collegamento è kaput:

Negli App.xaml.cs file che abbiamo collegare il dialogo di conferma al 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;
    ...
}

Nella vista (MainWindowView.xaml) abbiamo un pulsante che richiama un comando nel ViewModel

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

Il ViewModel (MainWindowViewModel.cs) utilizza un comando delegato per mostrare la "Sei sicuro?" dialogo e eseguire l'azione. In questo esempio si tratta di un SimpleCommand simile a questo , ma qualsiasi implementazione di ICommand dovrebbe fare.

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

Ho appena creare un'interfaccia (IMessageDisplay o simile) che viene iniettato nella VM, e ha metodi come un MessageBox (ShowMessage () ecc). È possibile implementare che l'utilizzo di un MessageBox standard o qualcosa di più specifico WPF (io uso questo su CodePlex qualche ragazzo chiamato Prajeesh).

In questo modo del tutto separato e verificabile.

Che dire di sollevare un evento come "MessageBoxRequested" manipolato al codebehind della vista (in ogni caso è di sola visualizzazione codice in modo non vedo alcun problema di avere questo codice sul codebehind).

Ho fatto un semplice controllo wrapper MessageBox per noi da usare in soluzione MVVM pura e ancora permettendo capacità di test di unità. I dettagli sono nel mio blog http: //geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

mukapu

Ho implementato un comportamento che ascolta un messaggio dal ViewModel. Si basa su una soluzione Laurent Bugnion, ma dal momento che non fa uso di codice dietro ed è più riutilizzabile, penso che sia più elegante.

check it out qui

WPF e Silverlight MessageBox

MVVM supportato

http://slwpfmessagebox.codeplex.com/

Nel caso in cui nessun altro è ancora in lettura e insoddisfatto:

Volevo solo per gestire 'notifica' di tipo MessageBox (vale a dire non mi interessa circa il DialogResult), ma il problema che ho con la maggior parte delle soluzioni che ho letto circa è che sembrano ti costringono indirettamente a scegliere il vostro Visualizza implementazione (vale a dire, attualmente ho un MessageBox.Show, ma se poi decido di giocherellare solo con la visibilità di un pannello nascosto direttamente a mio avviso, che non sarà in rete molto bene con un'interfaccia INotification passata al ViewModel).

Così sono andato per una rapida e sporca:

Il ViewModel ha una proprietà string NotificationMessage, con i cambiamenti notificati ai PropertyChanged.

The View sottoscrive PropertyChanged, e se vede la proprietà NotificationMessage venire attraverso, fa tutto quello che vuole.

OK, quindi questo significa che il View ha code-behind, e il nome del PropertyChanged è hard-coded, ma sarebbe hard-coded in XAML comunque. E significa evito tutte le cose come convertitori di visibilità, e le proprietà di dire se la notifica è ancora visibile o meno.

(Certo questo è solo per un caso d'uso limitata (il fuoco e dimenticare), non ho pensato molto a come potrei voler estenderlo.)

Vorrei solo buttarlo dalla VM. Non voglio avere a utilizzare il servizio di qualcun altro o scrivere il mio solo per gettare un MessageBox.

Recentemente ho trovato questo problema in cui ho dovuto sostituire il MessageBox.Show nelle ViewModels con alcuni completamente MVVM denuncia meccanismo finestra di messaggio.

Per raggiungere questo obiettivo ho usato InteractionRequest<Notification> e InteractionRequest<Confirmation> insieme con l'interazione attiva e scritto i miei punti di vista per la finestra di messaggio.

Quello che ho implementato è pubblicato qui

Ci sono così tante risposte su questo argomento che variano dalla creazione di una classe personalizzata di utilizzare librerie di terze parti. Direi utilizzare una libreria di terze parti se si desidera pop up fresco con una bella grafica.

Ma se si desidera utilizzare la finestra di messaggio regolare da Microsoft per la vostra applicazione WPF qui è un'amichevole implementazione MVVM / unit test:

Inizialmente ho pensato vorrei solo ereditare da finestra di messaggio e avvolgerlo con un'interfaccia, ma non ho potuto a causa di finestra di messaggio non avere un costruttore pubblico, ecco la soluzione "facile":

casella Messaggio decompilazione in Visual Studio è possibile vedere tutti i sovraccarichi di metodo, ho controllato quali che volevo quindi creato una nuova classe e ha aggiunto i metodi, lo avvolse con un'interfaccia e ta-da! Ora è possibile utilizzare Ninject per legare l'interfaccia e la classe, iniettare e utilizzare Moq di unit test e.t.c.

Creare un'interfaccia (solo aggiunto alcuni dei sovraccarichi, come non ho bisogno di tutti):

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

Poi abbiamo la classe che erediterà da esso:

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

Ora basta usare questo quando l'iniezione e.t.c e boma u hanno un'astrazione fragile che farà il trucco ... che va bene a seconda di dove si intende utilizzare. Il mio caso è una semplice applicazione solo scopo di fare un paio di cose, quindi nessun punto nel corso di ingegneria una soluzione. Spero che questo aiuta qualcuno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top