2011-06-21 10 views
17

Estoy trabajando en la segunda versión de una aplicación, y como parte de la reescritura tengo que moverme a una arquitectura MVVM. Me está presionando para poner absolutamente todo el código en la clase de modelo de vista - tener C# en el código detrás del archivo está mal visto. (Lo sé, lo sé ... entiendo que el código subyacente no es malo, pero no es mi decisión esta vez).WPF Evento enlazado a ViewModel (para clases que no son de comando)

Para los objetos que implementan la interfaz de comando, es fácil. Pude encontrar muchísima información sobre cómo vincular el Comando de estos objetos a un ICommand en el modelo de vista. El problema es para objetos que no tienen esta interfaz, p.

<ListBox 
    x:Name="myListBox" 
    MouseDoubleClick="myCallbackFunction"> 

<!-- ... --> 

</ListBox> 

Quiero saber cómo enlazar el evento MouseDoubleClick para el cuadro de lista a MyCallbackFunction, que se implementa en el modelo de vista. ¿Esto es posible?

Gracias!

+1

interrogación Duplicar http://stackoverflow.com/questions/939388/binding-commands-to-events –

Respuesta

8

Esto no es directamente posible. Podría hacerse a través de una Propiedad o Comportamiento Asociado, aunque aún sería un poco complicado encontrar e invocar el método apropiado (esto podría hacerse a través de Reflection con bastante facilidad).

Dicho esto, esto normalmente se maneja a través de ICommand - Por ejemplo, MVVM Light tiene un gran comportamiento EventToCommand para asignar cualquier evento a un ICommand en el ViewModel. La ventaja de usar ICommand es que aún puede usar DataBinding, ya que ICommand está expuesto como una propiedad.

1

Una forma podría ser para controlar el evento en el código subyacente y llamar al método apropiado de vista del modelo de código detrás

También puede ir a algún listo biblioteca de mando de hecho como this tutorial que está utilizando ACB

4

Para responder directamente a su pregunta, consulte Why to avoid the codebehind in WPF MVVM pattern?. Sugiere dos cosas posibles que desee.

Sin embargo, ¿por qué quiere vincular el MouseDoubleClick de ListBox a su ICommand en el modelo de vista?

La forma alternativa es escribir un método en un código subyacente para registrar MouseDoubleClick. No está mal debido a los hechos de lo siguiente.

  1. El enlace de datos significativo es la interacción entre una vista y un modelo de vista. Por ejemplo, cuando un usuario ingresa texto en un cuadro de texto, también se actualiza un modelo de vista. Por el contrario, si un modelo de vista obtiene datos de una base de datos, se mostrará en una vista. Sin embargo, no es este el caso de que ICommand en su viewmodel se una a la vista.

  2. Por supuesto, el CanExcute de la ICommand sería importante para su modelo de vista, pero en muchos casos, no está relacionado con el modelo de vista o no se refiere. En este caso, la diferencia entre el enlace de ICommand y la escritura del código subyacente es cuando el evento MouseDoubleClick se vincula con un ICommand o se registra con un controlador de eventos.

+0

El evento en MouseDoubleClick el ListBox era solo un ejemplo que existía en el código heredado, y no puedo mantener ese evento en particular. Sin embargo, quiero saber si hay una forma de evitar el código detrás de cualquier evento como este. Y mi código actualmente tiene un controlador de eventos simple en el código detrás del cual invoca un método en el modelo de vista. Pero por razones políticas en mi oficina, me dieron instrucciones para encontrar una manera de evitar escribir código en el código subyacente. – RobotNerd

+0

Como la parte superior de mi respuesta y @Reed Copsey también se mencionaron anteriormente, hay dos cosas posibles que desea usar, que es la Propiedad adjunta o el Comportamiento. Se describen en [mi pregunta] (http://stackoverflow.com/questions/6421372/why-to-avoid-the-codebehind-in-wpf-mvvm-pattern). Sin embargo, quiero saber por qué se le anima a evitar escribir código en el código que está detrás. Creo que la respuesta de @ slugster de [mi pregunta] (http://stackoverflow.com/questions/6421372/why-to-avoid-the-codebehind-in-wpf-mvvm-pattern) ayudaría con usted. –

+0

La razón es que la lógica de negocios debe estar completamente desacoplada del HMI (estoy trabajando con "puristas"). Sin embargo, probé las soluciones que vinculó anteriormente, pero todavía no he podido trabajar. Cada solución potencial es mucho menos elegante que simplemente usar el código como intermediario. Decidí seguir con mi código original y ver si puedo continuar con mi próxima revisión por pares. – RobotNerd

4

WPF admite extensiones de marcado en eventos a partir de .NET 4.5.El uso de esa capacidad, he implementado una extensión enlace de método muy versátil y escribió sobre ello aquí:

http://www.singulink.com/CodeIndex/post/building-the-ultimate-wpf-event-method-binding-extension

se puede utilizar para unirse a un método que utiliza la sintaxis de la ruta completa propiedad, es compatible con fijaciones y otras extensiones de marcado como argumentos, y se dirige automáticamente al método que coincide con la firma de los argumentos proporcionados. Aquí están algunos ejemplos de uso:

<!-- Basic usage --> 
<Button Click="{data:MethodBinding OpenFromFile}" Content="Open" /> 

<!-- Pass in a binding as a method argument --> 
<Button Click="{data:MethodBinding Save, {Binding CurrentItem}}" Content="Save" /> 

<!-- Another example of a binding, but this time to a property on another element --> 
<ComboBox x:Name="ExistingItems" ItemsSource="{Binding ExistingItems}" /> 
<Button Click="{data:MethodBinding Edit, {Binding SelectedItem, ElementName=ExistingItems}}" /> 

<!-- Pass in a hard-coded method argument, XAML string automatically converted to the proper type --> 
<ToggleButton Checked="{data:MethodBinding SetWebServiceState, True}" 
       Content="Web Service" 
       Unchecked="{data:MethodBinding SetWebServiceState, False}" /> 

<!-- Pass in sender, and match method signature automatically --> 
<Canvas PreviewMouseDown="{data:MethodBinding SetCurrentElement, {data:EventSender}, ThrowOnMethodMissing=False}"> 
    <controls:DesignerElementTypeA /> 
    <controls:DesignerElementTypeB /> 
    <controls:DesignerElementTypeC /> 
</Canvas> 

    <!-- Pass in EventArgs --> 
<Canvas MouseDown="{data:MethodBinding StartDrawing, {data:EventArgs}}" 
     MouseMove="{data:MethodBinding AddDrawingPoint, {data:EventArgs}}" 
     MouseUp="{data:MethodBinding EndDrawing, {data:EventArgs}}" /> 

<!-- Support binding to methods further in a property path --> 
<Button Content="SaveDocument" Click="{data:MethodBinding CurrentDocument.DocumentService.Save, {Binding CurrentDocument}}" /> 

Ver Método de los modelos de firmas:

public void OpenFromFile(); 
public void Save(DocumentModel model); 
public void Edit(DocumentModel model); 

public void SetWebServiceState(bool state); 

public void SetCurrentElement(DesignerElementTypeA element); 
public void SetCurrentElement(DesignerElementTypeB element); 
public void SetCurrentElement(DesignerElementTypeC element); 

public void StartDrawing(MouseEventArgs e); 
public void AddDrawingPoint(MouseEventArgs e); 
public void EndDrawing(MouseEventArgs e); 

public class Document 
{ 
    // Fetches the document service for handling this document 
    public DocumentService DocumentService { get; } 
} 

public class DocumentService 
{ 
    public void Save(Document document); 
} 
+1

Esta es la forma correcta de hacerlo. – John

Cuestiones relacionadas