2012-08-05 16 views
6

Actualmente estoy aprendiendo WPF y MVVM, creo que obtengo la mayor parte y cómo funciona, pero he encontrado algo sobre el uso del RelayCommand (o DelegateCommand) que no entiendo. Creo que tiene que ver con la forma en que trabajan los delegados.Comando de relé y método de ejecución sin parámetros

Tenga en cuenta que el código que se muestra a continuación solo se encuentra en soluciones de prueba en este momento, por lo que no hay código en vivo. También estoy considerando esto para comandos que no requieren un parámetro como close y para entender por qué funciona.

Así que si tomo el RelayCommand que Josh Smith creó (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030) que puede configurar un comando como este:

RelayCommand updateTextContentCommand; 

public ICommand UpdateTextContentCommand 
{ 
    get 
    { 
     if (updateTextContentCommand == null) 
     { 
      updateTextContentCommand = new RelayCommand(
       param => this.UpdateTextContentCommand_Execute()); 
     } 
     return updateTextContentCommand; 
    } 
} 

con este método de ejecución:

public void UpdateTextContentCommand_Execute() 
{ 
    this.TextContent = DateTime.Now.ToString(); 
} 

he usado una unión simple de un TextBlock para ver el resultado y el comando está vinculado a un botón. Esto funciona bien Lo que no entiendo es el uso de la expresión lambda para crear el comando. El Action<object> espera un parámetro, ¿no es así? Entonces, ¿por qué funciona este código?

Si cambio el código anterior para

if (updateTextContentCommand == null) 
{ 
    updateTextContentCommand = new RelayCommand(
     this.UpdateTextContentCommand_Execute()); 
} 

consigo estos errores:

* El partido mejor método sobrecargado para 'MVVM.RelayCommandTesting.Framework.RelayCommand.RelayCommand (System.Action)' tiene algunos argumentos no válidos

argumento 1: no se puede convertir de 'vacío' a 'System.Action' *

y extracción de la () después de ejecutar da este error:

Argumento 1: no se puede convertir de 'grupo Método' a 'System.Action'

Pero si cambio el código de la siguiente manera:

if (updateTextContentCommand == null) 
{ 
    updateTextContentCommand = new RelayCommand(
     this.UpdateTextContentCommand_Execute); 
} 

public void UpdateTextContentCommand_Execute(object param) 
{ 
    this.TextContent = DateTime.Now.ToString(); 
} 

se cumple y funciona bien Si cambio la vista para usar CommandParameter, puedo usar param para establecer el contenido del texto usando este método, pero si uso el estilo lambda, tengo que pasar un parámetro a la línea, así es como param =>this.UpdateTextContentCommand_Execute(param).

En mi prueba, me resulta difícil codificar el valor de CommandParameter, pero supongo que lo más probable es que esté enlazado a una propiedad del ViewModel en un sistema real para que pueda pasar el parámetro en el estilo lambda.

¿Alguien puede explicar por qué la versión sin parámetros funciona con el estilo lambda, por favor?

Gracias por tomarse el tiempo para leer esto.

Parece que la pregunta siguiente también tenía algunas preguntas sobre la lambda pero no veo que responda mi pregunta.

Passing a parameter using RelayCommand defined in the ViewModel (from Josh Smith example)

+0

+1 para una pregunta detallada que demuestre que ya ha intentado algo. –

+0

Saludos. Siempre trato de esforzarme al publicar preguntas, ya que encuentro preguntas como esta útiles cuando estoy buscando respuestas. – Kioshiki

Respuesta

8

El parámetro constructor es un delegado que tiene la siguiente firma:.

void MethodName(T parameter) 

donde parámetro es de tipo T (en el caso de la RelayCommand esto será de tipo system.Object

Este código:

param => this.UpdateTextContentCommand_Execute() 

es una expresión lambda que se expande esencialmente a esto:

void AnonymousMethod(object param) 
{ 
    this.UpdateTextContentCommand_Execute(); 
} 

Así que en este caso son pasando un parámetro (param) que simplemente no lo esté utilizando. Si comprende esto, ahora debería darse cuenta por qué sus otros ejemplos se comportan de la manera en que lo hacen.

Ejemplo 1

if (updateTextContentCommand == null) 
{ 
    updateTextContentCommand = new RelayCommand(
     this.UpdateTextContentCommand_Execute()); 
} 

Aquí está llamando el método que devuelve vacío. El constructor espera algo que coincida con el delegado Action<T>, de ahí el error.

Ejemplo 2

Si después de quitar los soportes de este tipo:

if (updateTextContentCommand == null) 
{ 
    updateTextContentCommand = new RelayCommand(
     this.UpdateTextContentCommand_Execute); 
} 

pensar en esto como siendo un poco como la suscripción de un evento:

myObject.myevent += new Action<object>(this.UpdateTextContentCommand_Execute); 

que puede acortar a:

myObject.myevent += this.UpdateTextContentCommand_Execute; 

Así que el constructor acepta cualquier método que tiene un firma que coincide con el Action<T> delegados firma es decir

void UpdateTextContentCommand_Execute(object parameter) 

Su método tiene la firma siguiente:

void UpdateTextContentCommand_Execute() 

Como se puede ver las firmas don No coincide, por lo que el compilador se queja.

Cuando actualiza su método UpdateTextContentCommand_Execute para aceptar un parámetro de objeto, su firma ahora coincide y por eso ahora funciona.

+0

Gracias, donde gastaste el método de ejemplo (método anónimo) hizo que todo cayera en mi lugar. Creo que fue un poco un caso de 'no puedo ver la madera para los árboles'. No he usado tanto expresiones lambda pero he hecho un poco con Linq. Simplemente no quiero ver la conexión. – Kioshiki

+0

Tuve exactamente el mismo problema. Cuando tuve ese momento 'aha', todo encajó en su lugar y de repente las expresiones lambda se volvieron mucho más fáciles de entender. Me alegro de poder articular mi experiencia de una manera que ayudó a alguien más. –

Cuestiones relacionadas