2012-08-05 10 views
6

Obecnie uczę się WPF i MVVM, myślę, że mam większość z nich i jak to działa, ale natrafiłem na coś na temat używania RelayCommand (lub DelegateCommand), którego nie rozumiem. Myślę, że ma to związek ze sposobem pracy delegatów.Metoda ponownego sprawdzania i wykonywania parametrów bez parametrów

Należy pamiętać, że poniższy kod jest tylko w rozwiązaniach testowych, więc nie ma kodu na żywo. Rozważam to również dla poleceń, które nie wymagają parametrów takich jak close i aby zrozumieć, dlaczego to działa.

Więc jeśli biorę RelayCommand że Josh Smith stworzył (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030) mogę skonfigurować polecenie tak:

RelayCommand updateTextContentCommand; 

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

z tej metody Execute:

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

użyłem prostego wiązania a TextBlock, aby zobaczyć wynik, a polecenie jest przypisane do przycisku. To działa dobrze. Czego nie otrzymuję, to użycie wyrażenia lambda do utworzenia polecenia. Action<object> oczekuje, że parametr nie jest? dlaczego ten kod działa?

Jeśli zmienić powyższy kod do

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

uzyskać te błąd:

* Najlepszym przeciążona metoda mecz dla 'MVVM.RelayCommandTesting.Framework.RelayCommand.RelayCommand (System.Action)' ma pewne nieprawidłowe argumenty

Argument 1: nie można przekonwertować z 'void' do 'System.Action' *

i usuwania () po Execute daje ten błąd:

Argument 1: nie można przekonwertować z 'grupy metodą' na 'System.Action'

Ale jeśli mogę zmienić kod tak:

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

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

ona zgodna i działa dobrze. Jeśli zmienię widok, aby użyć CommandParameter, mogę użyć parametru param, aby ustawić zawartość tekstową za pomocą tej metody, ale jeśli używam stylu lambda, muszę przekazać parametr do linii, aby był podobny do tego param =>this.UpdateTextContentCommand_Execute(param).

W moim teście ciężko koduję wartość CommandParameter, ale przypuszczam, że najprawdopodobniej byłaby to data powiązana z właściwością ViewModel w rzeczywistym systemie, abyś mógł przekazać parametr w stylu lambda.

Może ktoś wyjaśnić, dlaczego wersja bez parametrów działa ze stylem lambda proszę?

Dzięki za poświęcenie czasu na przeczytanie tego.

Wygląda na to, że poniższe pytanie zawierało również kilka pytań na temat lambda, ale nie widzę odpowiedzi na moje pytanie.

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

+0

+1 za szczegółowe pytanie, które pokazuje, że już coś wypróbowałeś. –

+0

Pozdrawiam. Zawsze staram się wysilać, zamieszczając pytania, ponieważ takie pytania są przydatne, gdy szukam odpowiedzi. – Kioshiki

Odpowiedz

8

Parametr konstruktor jest delegatem, który ma następujący podpis.

void MethodName(T parameter) 

gdzie parametr jest typu T (w przypadku RelayCommand to będzie od rodzaju system.Object

Ten kod:

param => this.UpdateTextContentCommand_Execute() 

jest lambda wyrażenie, które zasadniczo rozszerza się następująco:

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

Więc w tym przypadku przechodzącą w parametrze (param) jesteś po prostu nie jest używany. Jeśli to zrozumiesz, powinieneś teraz zrozumieć, dlaczego twoje inne przykłady zachowują się tak, jak oni.

Przykład 1

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

Tutaj jesteś nazywając metoda, która zwraca void. Konstruktor oczekuje czegoś, co pasuje do delegata Action<T>, stąd błąd.

Przykład 2

Jeśli następnie usuń nawiasy tak:

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

myśleć o tym, jak jest trochę jak subskrybowanie zdarzenie:

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

które mogą być skrócone do:

myObject.myevent += this.UpdateTextContentCommand_Execute; 

Więc konstruktor przyjmuje żadnej metody, która ma podpis, który pasuje do podpisu Action<T> delegatów tj

void UpdateTextContentCommand_Execute(object parameter) 

metoda ma następujący podpis:

void UpdateTextContentCommand_Execute() 

Jak widać podpisów don pasuje, więc kompilator narzeka.

Po zaktualizowaniu metody UpdateTextContentCommand_Execute, aby zaakceptować parametr obiektu, jego sygnatura jest zgodna i właśnie teraz działa.

+0

Dzięki, gdzie wydałeś przykładową metodę (AnonymousMethod), wszystko to pasowało do mnie. Myślę, że było to trochę "nie widziałem drewna dla drzew". Nie używałem wyrażeń lambda, ale zrobiłem trochę z Linq. Po prostu nie chcę widzieć połączenia. – Kioshiki

+0

Miałem dokładnie ten sam problem. Kiedy miałem "aha", wszystko zaczęło się układać i nagle wyrażenia lambdy stały się o wiele łatwiejsze do zrozumienia. Cieszę się, że mogłem wyrazić moje doświadczenie w sposób, który pomógł komuś innemu. –

Powiązane problemy