2010-02-10 21 views
8

He estado usando el patrón MVVM desde hace un tiempo, pero todavía tengo problemas en situaciones de la vida real. Aquí hay otro: Uso comando y burbuja hasta el evento para ser manejado en el ViewModel. Hasta aquí todo bien. Pero el proyecto para el que estoy usando MVVM es en realidad una biblioteca de clases. Una vez que ejecuto el código de comando, necesito poder enviar un objeto de vuelta a la aplicación de llamada. ¿Cuáles son las formas sugeridas de hacerlo?Comando en MVVM (WPF): cómo devolver un valor?

Específicamente: En mi aplicación de llamada tengo una página XAML ligada directamente al ViewModel de la biblioteca, que contiene un objeto "Thing1". Cuando se hace clic en un botón, se llama a un método en ViewModel (llámelo "CopyThing1()"). Copia "Thing1" para crear "Thing2". Entonces necesito enviar "Thing2" a la aplicación de llamada.

Gracias !!!

Respuesta

1

Aunque la información sobre Commanding fue clara y correcta, no se pudo aplicar en mi caso porque la respuesta requerida era que una aplicación de llamada NO utilizara MVVM y que no fuera solo una respuesta de IU. Investigué Prism, pero me pareció demasiado complejo para lo que necesito en este momento. Terminé la crianza y manejo de eventos, tal como se describe aquí -> WPF MVVM Correct Way to Fire Event on View From ViewModel

1

Si Thing2 es otra propiedad en su viewmodel, puede utilizar INotifyPropertyChanged normal para informar a la interfaz de usuario del cambio.

También es posible usar Prism 's EventAggregator de un enfoque más disociadas

+0

Gracias. Este fue mi pensamiento original, pero la respuesta en la aplicación de llamada no será únicamente una respuesta UI. Así que no estaba seguro de cómo hacer que la creación de Thing2 inicie un evento al que el código subyacente de la aplicación que llama puede responder. –

+0

En realidad, ¿conoces un buen ejemplo del uso de EventAggregator? Además, ¿cuál es la ventaja de la versión de Prism más allá de la caja? –

+0

OK, lo entiendo ahora. No me di cuenta de dónde vino Prism. ¿QuickStart es el ejemplo más simple que conoces? –

10

Los comandos no devuelven valores, cambian el estado de su solicitud. En el caso de ICommands adjuntos a ViewModels es bastante simple, porque puedes hacer esto simplemente mutando el ViewModel cuando se ejecuta el comando.

Utilizando el RelayCommand de Josh Smith's excellent MVVM article:

public class MyViewModel : INotifyPropertyChanged 
{ 
    private readonly ICommand mutateCommand; 
    private Thing thing; 

    public MyViewModel() 
    { 
     this.mutateCommand = new RelayCommand(this.Mutate); 
    } 

    public ICommand MutateCommand 
    { 
     get { return this.mutateCommand; } 
    } 

    public Thing Thing 
    { 
     get { return this.thing; } 
     set 
     { 
      this.thing = value; 
      // raise PropertyChanged event here... 
     } 
    } 

    private void Mutate(object parameter) 
    { 
     this.Thing = new Thing(); 
    } 
} 

Después de llamar myVM.MutateCommand.Execute(new object()); se puede acceder al nuevo valor de myVM.Thing.

+0

Gracias. Yo había pensado en esto. En realidad, mi ejemplo no fue el mejor.Lo que realmente trato de hacer es tener un objeto (Thing1) al cual mi página XAML esté enlazada, y luego hacer clic en un botón en esa página y tener una segunda cosa (Thing2 - la misma estructura que Thing1, pero no Thing1) instanciada . Entonces puedo declarar un Thing1 y un Thing2 en mi ViewModel. Cuando se crea Thing2, la página enlazada debe responder en código subyacente, es decir, no se trata simplemente de una respuesta relacionada con la interfaz de usuario que se necesita. No estoy seguro de cómo obtener el código subyacente para responder a este evento que no es UI. –

+0

@ml_black: No use código subyacente; use ViewModels y permita que las Vistas simplemente reflejen que los Modelos de Vista cambian. La comunicación va solo de una manera. Es un enfoque mucho más limpio. –

+0

Estoy de acuerdo. Pero la aplicación de llamada no está usando ViewModels. Y este ViewModel está diseñado para más de una aplicación de llamadas. Entonces, en este caso, la información de Thing2 tiene que ser consumida por cada aplicación de llamadas a su manera. La biblioteca debe ser puramente MVVM. –

1

El enfoque ideal es definir una nueva clase heredada de ICommand de la siguiente manera:

public abstract class Command2<T1, T2> : ICommand { 
    public abstract T2 Execute2(T1 parameter); 
} 

public class DelegateCommand2<T1, T2> : Command2<T1, T2> { 
    public DelegateCommand2(Func<T1, T2> execute, Predicate<T1> canExecute) { 
     _execute = execute; 
     _canExecute = canExecute; 
    } 

    public override T2 Execute2(T1 parameter) { 
     if (CanExecute(parameter) == false) 
      return default(T2); 
     else 
      return _execute((T1)parameter); 
    } 
} 

Tenga en cuenta que Execute2 devuelve el valor igual una función normal. He aquí cómo usarlo.

private readonly ICommand _commandExample = new DelegateCommand2<int, Point3D>(
     commandExample_Executed, 
     commandExample_CanExecute 
    ); 

    public Command2<int, Point_3D> CommandExample { 
     get { 
      return (Command2<int, Point_3D>) _commandExample; 
     } 
    } 

    private static Point3D commandExample_Executed(int index) { 
     return Fun1(index); //Fun1 returns a Point_3D 
    } 

    private static bool commandExample_CanExecute(int index) { 
     return true; 
    } 

Llamadas Execute2 en lugar de Execute devolverá el valor.