2010-08-02 23 views
43

Estoy usando MVVM Light toolkit en mi aplicación WPF. Me gustaría saber cuál es el mejor enfoque para abrir una nueva ventana desde una ventana existente. Tengo este MainViewModel, que es responsable de MainWindow de mi aplicación. Ahora en el MainView, haciendo clic en un botón, me gustaría abrir una segunda ventana en la parte superior. Tengo RelayCommmand vinculado a Button 's Command. En el método de RelayCommand 's, puedo crear un nuevo objeto de la ventana y simplemente llamar Show(), algo como esto:Cómo abrir una nueva ventana usando MVVM Light Toolkit

var view2 = new view2() 
view2.Show() 

pero yo no creo que el modelo de vista debe ser responsable de la creación de la nueva view2 objeto. He leído esta publicación WPF MVVM Get Parent from VIEW MODEL donde Bugnion ha sugerido pasar el mensaje al view1 desde viewmodel1 y luego view1 debería crear el nuevo view2. Pero no estoy seguro de lo que realmente quiere decir al pasar el mensaje al view1? ¿Cómo debe manejar el mensaje el view1? En su código está detrás o qué?

Regards, Nabeel

+0

ver http://stackoverflow.com/questions/16993433/mvvm-light-wpf-binding-multiple-instances-of-a-window-to-a-viewmodel/16994523#16994523 – reggaeguitar

Respuesta

50

que pasan un mensaje de ViewModel1 a View1 medios para utilizar la messaging capabilities in the MVVM Light Toolkit.

Por ejemplo, su ViewModel1 podría tener un comando llamado ShowView2Command, luego enviaría un mensaje para mostrar la vista.

public class ViewModel1 : ViewModelBase 
{ 
    public RelayCommand ShowView2Command { private set; get; } 

    public ViewModel1() : base() 
    { 
     ShowView2Command = new RelayCommand(ShowView2CommandExecute); 
    } 

    public void ShowView2CommandExecute() 
    { 
     Messenger.Default.Send(new NotificationMessage("ShowView2")); 
    } 
} 

View1 se registraría para recibir mensajes en su código y mostrar View2 cuando reciba el mensaje correcto.

public partial class View1 : UserControl 
{ 
    public View1() 
    { 
     InitializeComponent(); 
     Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived); 
    } 

    private void NotificationMessageReceived(NotificationMessage msg) 
    { 
     if (msg.Notification == "ShowView2") 
     { 
      var view2 = new view2(); 
      view2.Show(); 
     } 
    } 
} 
+0

Gracias por la respuesta Matt. ¿Existen otros enfoques/mejores prácticas para abrir nuevas vistas en mvvm además del uso de mensajes? – nabeelfarid

+8

Otro enfoque que he visto utilizar a las personas es tener un estilo de servicio de clase que se usa para abrir la vista. Su ViewModel funcionaría con la interfaz de este servicio para mostrar ChildWindow, MessageBox o lo que sea. Este es un favorito particular de aquellos que quieren código cero en el código subyacente de su vista. Además, es un poco más comprobable ya que puede simular el servicio y afirmar que se llamó al método para mostrar su vista. –

+2

Sí, he visto gente hablando de eso también. Pero lo que no entiendo de este enfoque es que cuando abres una ventana hija desde un modelo de vista usando algún servicio digamos IDialogService.OpenChild(), ¿cómo configuraría el propietario de la ventana secundaria, como el modelo de vista que llama a IDialogService? OpenChild() no conoce o tiene una referencia a su propia vista? – nabeelfarid

2

A menos que me falta el punto aquí - si tuviera que usar el código subyacente, entonces ¿por qué no aplicar directamente evento Button_Click y abra el segundo punto de vista?

Lo Bugnion parece sugerir es Vista1 -> clic de botón -> mando del relé -> viewmodel1 -> mensaje -> Vista1 -> view1.cs -> vista abierta 2.

Usted va a sacrificar la capacidad de prueba de todos modos escribiendo código subyacente, ¿por qué tomar una ruta tan larga?

+4

la ruta larga se asegurará de que: cuando esté probando su modelo de vista, al menos puede probar que se ha emitido un mensaje/solicitud para abrir una nueva vista. Puede envolver el código de solicitud de mensaje en un IDialogService para hacerlo simulacro durante la prueba. – nabeelfarid

+2

Estoy de acuerdo con Pratz, es un poco loco tomar una ruta tan larga. – Vincent

+1

El código detrás del método está bien para una aplicación pequeña con un número pequeño de ventanas/vistas. La complejidad añadida parece excesiva si tiene una ventana principal que solo abre una segunda ventana ocasional solo para mostrar algunos detalles. Si la aplicación aumenta, el código subyacente no se escalará bien y las pruebas se verán afectadas. – srock

3

Puede hacer esto de la misma manera que necesita crear algunos eventos y registrarlos en ver y llamarlos en el modelo de visualización. Abra la ventana emergente.

como en este ejemplo

public class Mainclass : MainView 
{ 
    public delegate abc RegisterPopUp(abc A); 
    public RegisterPopUp POpUpEvent ; 

    public RelayCommand ShowCommand { private set; get; } 


    public void ShowCommand() 
    { 
     ShowCommand("Your parameter"); 
    } 
} 

dentro de la vista MainView mn=new MainView();

Registrar el evento aquí como thake mn.POpUpEvent += que haga clic en el botón de pestaña doble de tiempo

y en registros Emergente método correcto el código para la apertura la ventana emergente.

4

¿Por qué haces esta ruta? Es sencillo. Si reemplaza su botón con un botón de alternancia, o un hipervínculo, o cualquier otro número de controles tipo botón, no necesita actualizar su "código detrás", es un principio básico del patrón MVVM. En su nuevo toggleButton (o lo que sea), aún termina vinculando al mismo comando exacto.

Por ejemplo, estoy creando un proyecto para un cliente que quiere tener 2 UI, una va a ser fundamentalmente diferente en todos los sentidos, en términos de presentación. Pestañas horizontales frente a Vertical RadPanelBar (pensar Acordeón) para navegación. Ambas vistas pueden apuntar al mismo viewModel: cuando un usuario hace clic en la pestaña Orden de trabajo en la Vista 1, dispara el mismo "WorkOrderCommand" que se activa en el encabezado de la orden de trabajo en la barra del panel.

En un modelo de código subyacente, tendría que codificar dos eventos separados. Aquí solo tienes que codificar uno.

Además, le permite a un diseñador usar Blend para crear cualquier diseño que desee. Siempre que tengan los ganchos (control EventToCommand) en su lugar, a mí mismo (como desarrollador) no podría importarle menos cómo se ve el producto final.

El acoplamiento flojo es increíblemente potente.

2

Puede resumir las funciones específicas de la vista en servicios utilizando una interfaz genérica. En la capa de vista puede proporcionar instancias concretas de estos servicios y crear modelos de vista utilizando el contenedor IoC y la técnica de Inyección de dependencia.

En su caso puede construir una interfaz IWindowManager o algo similar que tenga el método requerido. Esto puede ser implementado en tu capa de vista. Escribí una pequeña publicación de blog que recientemente demostró cómo abstraer el comportamiento del diálogo del modelo que no se ve. investigaciones de enfoque similar se puede utilizar para cualquier servicio relacionado con la interfaz de usuario como la navegación, etc. cuadros de mensaje

Este enlace puede ser útil para usted http://nileshgule.blogspot.com/2011/05/silverlight-use-dialogservice-to.html

Muchas personas también utilizan el enfoque de arranques de modelos de vista que hayan sido suscritas en el archivo view.cs y desde allí se realiza el MessageBox o cualquier otra acción relacionada con la interfaz de usuario. Personalmente, me gusta el enfoque de la inyección de servicios porque luego puede proporcionar múltiples implementaciones del mismo servicio. Un ejemplo simple sería cómo se maneja la navegación en las aplicaciones de Silverlight y Windows Phone 7. Puede usar el mismo modelo de vista pero inyectar implementaciones diferentes del servicio de navegación según el tipo de aplicación.

0

Encuentro que la mejor manera de abordar esto es abriendo y cerrando la ventana desde el ViewModel. Como sugiere this enlace,

  1. crear una clase DialogCloser
 
    public static class DialogCloser 
    { 
     public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(DialogCloser), new PropertyMetadata(DialogResultChanged)); 

     private static void DialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var window = d as Window; 
      if (window != null) window.Close(); 
     } 

     public static void SetDialogResult(Window target, bool? value) 
     { 
      target.SetValue(DialogResultProperty, value); 
     } 
    } 
  1. Crear un modelo de vista Base heredando de GalaSoft.MvvmLight.ViewModelBase con allí miembros adicionales. Una vez hecho esto, use este modelo de vista como base para otros modelos de vista.
 
    bool? _closeWindowFlag; 
    public bool? CloseWindowFlag 
    { 
     get { return _closeWindowFlag; } 
     set 
     { 
      _closeWindowFlag = value; 
      RaisePropertyChanged("CloseWindowFlag"); 
     } 
    } 

    public virtual void CloseWindow(bool? result = true) 
    { 
     Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, 
     new Action(() => 
     { 
      CloseWindowFlag = CloseWindowFlag == null ? true : !CloseWindowFlag; 
     })); 
    }
  1. En la vista, enlazar la propiedad DialogCloser.DialogResult dependencia con la propiedad CloseWindowFlag en el modelo de vista base.

Luego puede abrir/cerrar/ocultar la ventana desde el modelo de vista.

Cuestiones relacionadas