2012-08-05 13 views
6

Ich lerne derzeit WPF und MVVM, ich denke, ich bekomme das meiste davon und wie es funktioniert, aber ich habe etwas über die Verwendung der RelayCommand (oder DelegateCommand), die ich nicht verstehe. Ich denke, es hat damit zu tun, wie die Delegierten arbeiten.Relaycommand und parameterless execute-Methode

Bitte beachten Sie, dass der unten stehende Code zur Zeit nur Testlösungen enthält, also keinen Live-Code. Ich denke darüber auch nach Befehlen, die keinen Parameter wie Schließen benötigen, und um zu verstehen, warum es funktioniert.

Also, wenn ich nehme die RelayCommand dass Josh Smith erstellt (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030) Ich kann Setup einen Befehl wie folgt aus:

RelayCommand updateTextContentCommand; 

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

mit dieser Methode execute:

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

Ich benutzte eine einfache Bindung an ein TextBlock, um das Ergebnis zu sehen, und der Befehl ist an eine Schaltfläche gebunden. Das funktioniert gut. Was ich nicht bekomme, ist die Verwendung des Lambda-Ausdrucks, um den Befehl zu erstellen. Die Action<object> erwartet einen Parameter nicht wahr? Warum funktioniert dieser Code?

Wenn ich den obigen Code ändern zu

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

ich diese Fehlermeldung erhalten:

* Die beste überladene Methode Spiel für 'MVVM.RelayCommandTesting.Framework.RelayCommand.RelayCommand (System.Action)' hat einige ungültige Argumente

Argument 1: kann von 'Leere' auf 'System.Action' *

und Entfernen des () nicht konvertieren nach gibt Execute diesen Fehler:

Argument 1: kann nicht von 'Methodengruppe' auf 'System.Action'

konvertieren Aber wenn ich den Code wie folgt zu ändern:

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

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

es erfüllt und läuft gut. Wenn ich die Ansicht ändere, um CommandParameter zu verwenden, kann ich param benutzen, um den Textinhalt mit dieser Methode zu setzen, aber wenn ich den Lambda-Stil verwende, muss ich einen Parameter an die Linie übergeben, so wie dieser param =>this.UpdateTextContentCommand_Execute(param).

In meinem Test kodiere ich den CommandParameter-Wert hart, aber ich denke, es wäre höchstwahrscheinlich Daten an eine Eigenschaft des ViewModel in einem realen System gebunden, so dass Sie den Parameter im Lambda-Stil übergeben könnten.

Kann mir jemand erklären, warum die parameterlose Version mit dem Lambda-Style funktioniert?

Danke, dass Sie sich die Zeit genommen haben, dies zu lesen.

Es scheint, dass die Frage unten einige Fragen über das Lambda hatte, aber ich sehe nicht, dass es meine Frage beantwortet.

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

+0

+1 für eine detaillierte Frage, die zeigt, dass Sie bereits etwas versucht haben. –

+0

Prost. Ich versuche immer, mich zu bemühen, Fragen zu stellen, da ich Fragen wie diese nützlich finde, wenn ich nach Antworten suche. – Kioshiki

Antwort

8

Der Konstruktor Parameter ist ein delegieren, der die folgende Signatur hat.

void MethodName(T parameter) 

wo Parameter des Typs ist T (im Fall des RelayCommand diese system.Object vom Typ sein

Dieser Code:

param => this.UpdateTextContentCommand_Execute() 

ist ein lambda Ausdruck, der im Wesentlichen auf diese erweitert:

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

Also in diesem Fall, dass Sie sind in einem Parameter übergeben (param) Sie verwenden es einfach nicht. Wenn Sie das verstehen, sollten Sie jetzt erkennen, warum sich Ihre anderen Beispiele so verhalten, wie sie es tun.

Beispiel 1

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

Hier sind Sie die Methode aufrufen, die void zurückgibt. Der Konstruktor erwartet etwas, das dem Action<T> Delegaten entspricht, daher der Fehler.

Beispiel 2

Wenn Sie dann die Klammern wie folgt entfernen:

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

Betrachten Sie das als ein Bit ist auf ein Ereignis wie der abonnieren:

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

dem verkürzt werden zu:

myObject.myevent += this.UpdateTextContentCommand_Execute; 

So übernimmt der Konstruktor jede Methode, die eine Unterschrift, die die Action<T> Delegierten Unterschrift dh

void UpdateTextContentCommand_Execute(object parameter) 

Ihre Methode übereinstimmt hat die folgende Signatur:

void UpdateTextContentCommand_Execute() 

Wie Sie die Unterschriften don sehen können Passen Sie nicht zusammen, so beschwert sich der Compiler.

Wenn Sie Ihre UpdateTextContentCommand_Execute Methode aktualisieren, um einen Objektparameter zu akzeptieren, stimmt die Signatur jetzt überein, weshalb sie jetzt funktioniert.

+0

Danke, wo Sie die Beispielmethode (AnonymousMethod) aufgewandt haben, hat alles für mich Platz gemacht. Ich denke, es war ein bisschen "Ich kann den Wald nicht für die Bäume sehen". Ich habe Lambda-Ausdrücke nicht so oft verwendet, aber ich habe ein wenig mit Linq getan. Ich will die Verbindung nicht sehen. – Kioshiki

+0

Ich hatte genau das gleiche Problem. Als ich diesen "Aha" -Moment hatte, fiel alles zusammen und plötzlich wurden Lambda-Ausdrücke viel leichter zu verstehen. Ich bin froh, dass ich meine Erfahrung auf eine Weise artikulieren konnte, die jemand anderem geholfen hat. –

Verwandte Themen