2010-11-16 15 views
11

Sto lavorando su un'applicazione MVVM wpf e ho bisogno di mostrare varie finestre di dialogo con ok cancel. Ne ho visti pochi in rete, ma l'aspetto è eccessivamente complicato o potrebbe essere il mio problema.Ok cancel Dialog MVVM Pattern wpf.Come posso farlo

ho notato che molti che utilizzano "IDialogService"

qualcuno mi può indicare un link o ha un frammento a portata di mano su come implementare una finestra di dialogo utilizzando un modello MVVM?

grazie mille

+0

Alcuni contesto potrebbe essere utile prima di fare un tentativo di una risposta: perché stai usando MVVM?Lavori in team o da solo? Metti alla prova il tuo livello di presentazione? Se sì, conosci i quadri di derisione? –

+0

Con cosa stai avendo problemi? (Visualizzazione della finestra di dialogo? Chiusura della finestra di dialogo? Cablaggio della finestra di dialogo sul ViewModel? Altro?) Inoltre, si sta utilizzando un framework MVVM e, in caso affermativo, quale? –

+0

Mi dispiace. Ho pensato che fosse una domanda molto generica. Quindi nessun codice. Sto usando Moq come framework Mocking. Preferibilmente vorrei testarlo unitamente. Nel vero progetto al lavoro ho un'architettura disconnessa usando PL-SL-BL-DAL. Non volevo confondere le persone o rendere la domanda implicata. Volevo semplicemente chiedere aiuto su come mostrare una finestra di dialogo usando un pattern MVVM. Non posso usare nessuno dei framework disponibili. Usiamo uno in house one.Once I grab il contesto e può trasferirlo al mio vero progetto. – user9969

risposta

10

ecco un dialogo barebone con i pulsanti OK e Annulla. Ho incluso il codice XAML, Vista, e ViewModel:

XAML:

<Window 
    x:Class="TestProject.Views.OKCancelDialog" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    Title="Window Title" 
    Height="300" 
    Width="600" 
    WindowStartupLocation="CenterOwner" 
    WindowStyle="ToolWindow" 
    ResizeMode="CanResize" 
    UseLayoutRounding="True" 
    TextOptions.TextFormattingMode="Display"> 

    <Grid> 
     <Button 
      Name="OKButton" 
      Content="OK" 
      Height="23" 
      HorizontalAlignment="Right" 
      Margin="0,0,93,12" 
      VerticalAlignment="Bottom" 
      Width="75" 
      Click="OKButton_Click" 
      IsDefault="True" 
      Command="{Binding OKButtonCommand}" /> 

     <Button 
      Name="CancelButton" 
      Content="Cancel" 
      Height="23" 
      HorizontalAlignment="Right" 
      Margin="0,0,12,12" 
      VerticalAlignment="Bottom" 
      Width="75" 
      IsCancel="True" /> 
    </Grid> 
</Window> 

Codebehind:

using System.Windows; 
using TestProject.ViewModel; 

namespace TestProject.Views 
{ 
    public partial class OKCancelDialog : Window 
    { 
     private readonly OKCancelViewModel viewModel; 

     //I use DI to inject the ViewModel into the View 
     //This will allow you to use the view for different ViewModels if you need to. 
     //Create an Interface for your ViewModel to implement to make ViewModel unit testing 
     //easier. Testing frameworks such as rhino mock require Interfaces to test methods 
     //in a class under test and it allows you to use an IoC Container to create the 
     //ViewModel for you.     
     public OpenReturnDialog(IOKCancelViewModel viewModel) 
     { 
      InitializeComponent(); 
      this.viewModel = viewModel; //Do this if you need access to the VM from inside your View. Or you could just use this.Datacontext to access the VM. 
      this.DataContext = viewModel; 
     } 

     private void OKButton_Click(object sender, RoutedEventArgs e) 
     { 
      DialogResult = true; 
     } 

    } 
} 

ViewModel

using Microsoft.Practices.Composite.Presentation.Commands; 


namespace TestProject.ViewModel 
{ 
    public class OKCancelViewModel 
    { 
     public OKCancelViewModel() 
     { 
      OKButtonCommand = new DelegateCommand<object>(HandleOKButtonCommand, CanExecuteOKButtonCommand); 
     } 

     public DelegateCommand<object> OKButtonCommand { get; private set; } 

     public void HandleOKButtonCommand(object obj) 
     { 
      //Here is where your code for OK button clicks go. 

     } 

     public bool CanExecuteOKButtonCommand(object obj) 
     { 
      //Put code to determine when the OK button will be enabled/disabled. 
     } 

     //You may want to add a command for the Cancel button also if you have a need to 
     //enable/disable the cancel button 
     //The command will look just like the OK button command above. 
    } 
} 

Ora, molto probabilmente vorrai che il tuo ViewModel implementa INotifyPropertyChanged nel caso in cui tu abbia altri controlli nell'interfaccia utente che si collegheranno alle proprietà nel ViewModel.

Spero che questo aiuti ...

+0

Grazie per la tua risposta con il codice. Ho appena creato un progetto noddy e ho inserito il tuo codice. Ho 2 finestre. Your OKCancelDialog e MainWindow. MainWindow ha un pulsante "Launch Dialog." Come lo fai con il tuo codice? – user9969

+0

Beh, c'è un posto in cui le opinioni delle persone sono diverse. Devo ancora trovare una best practice per questo, quindi ti dirò come lo faccio. La finestra principale dovrebbe anche avere una VM con un "LaunchDialogCommand" - proprio come i comandi nel mio codice sopra.Insieme "HandleLaunchDialogCommand" hai il codice per creare OKCancelViewModel e OKCancelView. Qualcosa di simile: var dlg = new OKCancelView (new OKCancelViewModel ( Ora, qui è dove entrano molte opinioni diverse. Puoi chiamare OKCancelView.ShowDialog(), ma dal momento che sei all'interno di una VM, molti ritengono che sia sbagliato chiamare ShowDialog() all'interno di una VM. – ihatemash

+0

La maggior parte delle persone in tal caso, genera un evento a cui unaltra classe si iscrive e chiama ShowDialog(). Sono un po 'pigro quindi di solito chiamiamo ShowDialog() all'interno del ViewModel. Dai un'occhiata a questo link: http://stackoverflow.com/q/1730290/195356 – ihatemash

7

penso tutti gli altri che utilizza un IDialogService o crea effettivamente le proprie finestre di dialogo è finita ingegnerizzazione del problema. Mi piace molto l'approccio semplicistico dell'uso di Func. Ecco un esempio. In primo luogo aggiungere questo al vostro ViewModel:

public abstract class ViewModelBase : INotifyPropertyChanged 
{ 
    /** Other ViewModel Code *// 

    public Func<string, string, bool> OkCancelDialog { get; set; } 
} 

Poi, quando si istanzia la classe derivata del vostro ViewModel, basta collegare il seguente codice: (Io di solito faccio in startup come Program.cs)

var myVM = new SomeSuperViewModel(); 
myVM.OkCancelDialog = (msg, caption) => MessageBox.Show(msg, caption, MessageBoxButton.OkCancel) == MessageBoxResult.OK; 

Nel codice ViewModel reale, tutto quello che dovete fare è chiamare:

if (OkCancelDialog("Some crazy message.", "Caption")) 
    //do something if true 
else 
    //else do something if false 

Nei vostri test di unità si può fare questo:

var myVMToTest = new SomeSuperViewModel(); 
myVMToTest.OkCancelDialog = (msg, caption) => true; //could be false too if you need to test that functionality. 

Preferisco questo approccio, in quanto è semplice e facile da testare. Cosa pensano gli altri?

0

si potrebbe avere uno sguardo alla ViewModel applicazione (emailclient) campione del WPF Application Framework (WAF). Mostra come scrivere finestre di dialogo personalizzate con MVVM e mostra come puoi utilizzare MessageBox senza violare il pattern MVVM.

0

Cosa c'è di sbagliato con solo chiamando System.Windows.MessageBox.Show() dal codice del vostro ViewModel

esempio

public bool GetConfirmation(string Message, string Caption) 
{ return MessageBox.Show(Message, 
         Caption, 
         System.Windows.MessageBoxButton.OKCancel, 
         System.Windows.MessageBoxImage.Question, 
         System.Windows.MessageBoxResult.Cancel) == System.Windows.MessageBoxResult.OK; } 
+0

Immagino che l'OP stia cercando di testare. –