2015-08-08 18 views
5

Ho trascorso alcuni giorni a cercare di capire WPF e MVVM. Sta andando molto lentamente, soprattutto perché ho una mancanza di conoscenza in termini di eventi e cose. Qui Bellow cercherò di spiegare la mia comprensione di tutte queste cose:Delegati, Azioni, Eventi, espressione Lambda e MVVM


Metodo - Questo è semplice e non credo che ha bisogno di alcuna spiegazione. Ingrediente di base in qualsiasi programma.

delegato - il modo in cui lo vedo è il puntatore sul metodo. Posso pensare solo a poche applicazioni in cui vorrei usarlo su un metodo.

Azione - quella è ancora più complicata. Le informazioni che sono riuscito a trovare dicono che è un delegato che non restituisce valore ... quindi è solo un puntatore sul metodo void? Non vedo il punto di quello

Evento - questo non riesco affatto. Era stato spiegato con un delegato e non capivo come funziona e a cosa serve. Nota Stavo usando eventi che scrivevano applicazioni winforms ma era solo scegliendo l'evento desiderato dalla lista.

Gestore di eventi - ancora più chiaro.

Espressione lambda - anche un altro modo di utilizzare il metodo. Ancora una volta capisco che non restituisce nulla, posso passare qualche argomento in esso, ma ancora non è molto diverso dal metodo del vuoto. Ho visto alcune applicazioni come quando uso LINQ ma ancora non capisco come funziona.


Vorrei iniziare dicendo che comprendo il costrutto di base di MVVM, cosa sta facendo cosa e così via. Il problema che ho è che non capisco parte del codice, come funziona e quindi non posso scrivere nulla per conto mio. Userò alcuni tutorial come esempio così qui va:

S1: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030

S2: http://social.technet.microsoft.com/wiki/contents/articles/18199.event-handling-in-an-mvvm-wpf-application.aspx

Cosa mi aspetto da voi ragazzi è una guida o una spiegazione come posso affrontare e capire quelli pensa di renderli almeno un po 'meno spaventosi per me. Qui inserirò alcuni esempi che si spera possano mostrarti che tipo di problemi ho.


1) In primo luogo si viene da S1 dalla ben nota classe RelayCommand:

public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

So cosa è supponiamo di fare (nome parla da sé). Ma non capisco come funzioni questa cosa? Come sa quando realizzare qualcosa eseguibile e quando no. Quali sono esattamente quelli che aggiungono e rimuovono i "comandi"? Ho provato a leggerlo ma non è stato d'aiuto.

2) Un altro esempio modulo S1:

#region CloseCommand 

    /// <summary> 
    /// Returns the command that, when invoked, attempts 
    /// to remove this workspace from the user interface. 
    /// </summary> 
    public ICommand CloseCommand 
    { 
     get 
     { 
      if (_closeCommand == null) 
       _closeCommand = new RelayCommand(param => this.OnRequestClose()); 

      return _closeCommand; 
     } 
    } 

    #endregion // CloseCommand 

    #region RequestClose [event] 

    /// <summary> 
    /// Raised when this workspace should be removed from the UI. 
    /// </summary> 
    public event EventHandler RequestClose; 

    void OnRequestClose() 
    { 
     EventHandler handler = this.RequestClose; 
     if (handler != null) 
      handler(this, EventArgs.Empty); 
    } 

    #endregion // RequestClose [event] 

Anche in questo caso so che cosa è supponiamo di fare, ho anche capito che cosa sta succedendo qui, ma in fondo non vedo dove questa “cosa” è in realtà fare qualcosa. OnRequestClose() sta creando un gestore che ai miei occhi non fa nulla per chiudere qualunque cosa si supponga di chiudere. Il problema è che se non vedo nemmeno dove viene eseguito il comando, come posso scrivere i miei comandi.

3) Penso che questa sarà l'ultima ad esempio, questa volta da S2:

public ViewModel() 
{ 
    _clickCommand = new DelegateCommand<string>(
     (s) => { /* perform some action */ }, //Execute 
     (s) => { return !string.IsNullOrEmpty(_input); } //CanExecute 
     ); 
} 

Qui problema è abbastanza semplice. Sta creando un comando usando RelayCommand ctor (o almeno la sua versione in questo progetto, qui chiamata "DelegateCommand"). Non capisco quelli (s) e l'uso di lambda. Cosa serve?


Ovviamente non è tutto quello che ho problemi, ma penso che darà un'idea di quale sia il mio problema per chiunque sia disposto ad aiutare. Ho cercato di spiegare il mio problema nel miglior modo possibile e apprezzerei davvero qualsiasi aiuto o guida. Forse mi aspetto molto da me stesso ma sento che ho bisogno di sapere tutte quelle cose per scrivere qualcosa di serio.

In ogni caso grazie a tutti in anticipo per qualsiasi aiuto.

+3

Hai fatto un ottimo lavoro nel mettere insieme un sacco di materiale eccezionale per supportare ciò che penso sia probabilmente il migliore tra le tante domande. Quello che hai finito per chiedere è troppo ampio - una risposta qui sarebbe epicamente lunga. Dovresti interrompere questa domanda in parti più piccole e chiedere loro separatamente, ma sospetto che ogni parte sia stata chiesta e risposta. Probabilmente hai bisogno di scrivere una domanda relativa a ciascuna parte, con un codice che hai scritto per testare la tua comprensione e facci sapere dove sei rimasto bloccato. Quindi è probabile che tu abbia delle buone risposte. – Enigmativity

+0

Per la cronaca, la tua comprensione di Lambda Expressions è sbagliata. Un lambda non restituisce necessariamente "void" o prende alcun argomento specifico. Considera la seguente espressione lambda valida: '() =>" Hello! "' Che non accetta parametri e restituisce 'string'. –

+0

@Enigmativity Avevo paura che la domanda potesse essere troppo ampia, ma ho sentito che la maggior parte di queste cose sono collegate tra loro, quindi ho deciso di metterlo in questo grande argomento. Quando apprendo queste cose c'è un problema che capisco semplicemente x => x * x ma quando si tratta di cose serie diventa più complicato. Aspetterò un po 'per alcune risposte aggiuntive e se non compare nulla userò il tuo consiglio e cercherò di separarlo. Grazie per la risposta e i suggerimenti. – Bielik

risposta

2

Una lunga risposta per la tua ampia domanda.

Permettetemi di scavare in Eventi e EventHandler prima utilizzando un approccio semplice

Supponiamo che ci sia una grande funzione organizzata nella tua città che ospiterà molti personaggi famosi dal vostro paese.

Consideriamo tre ospiti per questo esempio
ospiti uno è una persona che si conosce da altri ospiti
Giudizi due è una persona famosa dalla vostra zona e molto pochi sanno
Giudizi tre è molto famoso in tutto il Paese

si consideri il seguente ipotesi

Nessuno è in attesa di un ospite (0 EventHandler)

Ci sono quattro persone che sono in attesa per gli ospiti due (4 di EventHandler ogni persona è un gestore di eventi in attesa di salutare)

ci sono tre personale di sicurezza e 10 ospiti (di cui uno persona è anche in attesa di ospite 2) in attesa di ospite 3 (13 EventHandler di)

Scenario 1 Quando ospite si arriva alla sede (Event alzato) non succede nulla

Scenario 2 W ospite gallina due arriva presso la sede (Event sollevato) le quattro persone si muovono verso di lui/lei e danno saluti

Scenario 3 Quando ospite tre arriva (Event) si vedrà le forze di sicurezza che fornisce copertura e dieci le persone si muovono verso di lui/i suoi saluti e dare

semplici punti da osservare
1. evento è solo una notifica che è successo qualcosa (come un delegato con una firma del metodo)
2. EventHandler è un'azione da ciò che accade quando si è verificato un evento specifico (un metodo che implementa la firma del metodo definita del delegato)
3. Un evento può avere molti eventhandler (ad esempio, scenario 2,3). Di qui la sintassi + = nel codice di esempio sotto

Il codice qui sotto vi rispondere ad alcune delle vostre domande di base

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new Example(); 
     Console.ReadLine(); 
    } 
} 


class Example 
{ 
    //This is the event definition 
    delegate void ActionDelegate(string input1, string input2); 

    // Two event handler which implements the signature of the event 
    void ActionMethod(string a, string b) 
    { 
     Console.WriteLine(a + " " + b); 
    } 
    void ActionMethod2(string c, string d) 
    { 
     Console.WriteLine("Wow one more function called with parameter {0} and {1}", c, d); 
    } 

    delegate Tuple<string, string> LamdaDelegate(string input1, string input2); 
    public Example() 
    { 
     //Did not declare any delegate member variable explicitly. 
     //Clean and easy to understand 
     Action<string, string> action = ActionMethod; 

     // Had to define the delegate with method signature explicitly before using it 
     ActionDelegate actionDelegate = ActionMethod; 
     actionDelegate += ActionMethod2; // Attaching more event handlers to the event 

     //The below lambda expression implicitly means that it will take two inputs each of type string 
     // and does not return anything. 
     //The type information is implicitly derived from the method signature of the delegate 
     actionDelegate += (a, b) => Console.WriteLine("Called using lambda expression"); 


     //Below is a Lambda expression in which s and e each is of type string 
     //Since the return type of the delegate is Tuple<string,string> the same is returned by the expression 
     //Lambda expression is using a delegate without defining a delegate explicitly. 
     LamdaDelegate myTuple = (s, e) => { return Tuple.Create(s, e); }; 

     //The above Lambda can be rewritten as 
     myTuple += delegate (string a, string b) { return Tuple.Create(a, b); }; 

     //Invoking the event handlers. The event handlers are executed automatically when ever the event occurs 
     action("Hi", "called from action"); 
     actionDelegate("Hi", "called using explicitly defined delegate"); 
    } 
} 

Perché dovremmo usare i delegati?
Nell'esempio precedente hai visto che lo ActionMethod viene utilizzato da due diversi delegati (leggi Evento). Senza delegati, l'esempio precedente sarebbe sporco e illeggibile.
L'esempio precedente mostra anche Action che semplifica la necessità di definire i delegati in modo esplicito.

Ora ritornassi ai comandi
In MVVM la tradizionale manifestazione è sostituito dal Command ed i parametri di evento (leggi delegato firma del metodo) è sostituita dalla CommandParameter

Nella sua terza questione, il DelegateCommand ha un parametro di tipo che è string . Quindi la (s) che vedi è una variabile che memorizza la stringa di input inviata dall'interfaccia utente. Ora spetta a te decidere se vuoi utilizzare l'input (s) o ignorarlo tutto insieme.Nella parte CanExecute è possibile vedere che anche quando viene passato l'input (s), esso lo ha ignorato e utilizza l'altra variabile membro _input.

La seconda domanda è un evento RequestClose cui è collegato un gestore di eventi nella Figura 7 del collegamento. Osservare inoltre che nella stessa figura lo MenuItem è associato allo CloseCommand nello ViewModel.
Così ora quando si fa clic su MenuItem viene invocato il CloseCommand e quindi chiama la funzione OnRequestClose. La prima cosa che controlla questa funzione è che è lì chiunque sia interessato (leggi l'ascolto) nel caso in cui il RequestCloseMainWindow è in ascolto e chiede il window.Close()

Per ulteriori chiarimenti si prega fatemi sapere da qui.

EDIT

L'esempio di codice di cui sopra è stato solo per Action<T> e delegate.

In parole povere Mettiamola in questo modo

Se voglio fare qualcosa sulla base di qualche azione esterna userei evento. Definirò semplicemente un evento e lo collegherò a un EventHandler e attendo solo che l'azione si verifichi. (Nell'esempio di cui sopra non so quando sarà l'ospite arriva ma ogni volta che lo fanno arrivare il EventHandlerrisponderà automaticamente)

D'altra parte userò delegate se voglio chiamare singole funzioni/multipli contemporaneamente basato su alcune condizioni interne definite nel codice. Nell'esempio di codice sopra puoi vedere che Ho dovuto richiamare manualmente il delegato.

Si prega di ignorare lo Tuple in quanto è solo un valore di ritorno senza importanza reale.

EDIT 2

Lo scenario (_) o (s) è simile. Entrambi significano che si otterrà un parametro come input, ma nel primo scenario lo sviluppatore sta cercando di dire che questo parametro non sarà utilizzato o ignorata, mentre nel (s) intendono usarlo

Non è possibile utilizzare solo () poiché ciò significa che l'espressione lambda non contiene alcun parametro di input errato in quanto la definizione dice che riceverà un input come string.

+0

Grazie per la risposta, è molto utile e spiega molto. Ho ancora alcune domande, ma penso che proverò a rileggere quello che hai scritto un paio di volte e fare qualche ricerca prima di chiederle. Comunque grazie ancora una volta per la tua risposta ed essere sicuro che scriverò di nuovo con alcune domande. – Bielik

+0

E assicurati che proverò a rispondere :-) – Sandesh

+0

Vorrei iniziare dicendo che in realtà non so cosa sia questa Tupla. Ho iniziato a leggere qualcosa ma sembra abbastanza complesso e voglio concentrarmi su una cosa alla volta. Problema con gli eventi che mi hai mostrato è che non vedo alcuna differenza da parte dei delegati multicast Ho provato a cercare qualcosa a riguardo, compresa questa domanda: http://stackoverflow.com/questions/563549/difference-between-events- e-delegati-e-le-rispettive applicazioni Ma in realtà non ha risposto alla mia domanda, in particolare che dalla tua risposta sembrano esattamente quei delegati multicast. – Bielik

2

1.Delegare

il mio modo di vedere è puntatore sul metodo

corretta. Tuttavia, poiché C# è fortemente tipizzato, è necessario definire quali parametri e tipo di restituzione devono avere il metodo. Questo è ciò che i delegati sono.

Posso pensare solo a poche applicazioni in cui vorrei utilizzarlo su un metodo .

Non si tratta di metodo vs deledato. Quando è necessario passare il metodo come parametro, il parametro viene definito utilizzando delegato.

2. Azione

Action è tipo concreto di delegato. Mentre il delegato può fare riferimento a qualsiasi metodo, Action dice che è un metodo senza parametri con tipo di ritorno void. Action<string> significa che il parametro è di tipo stringa. Action<string, int> significa che il primo parametro del metodo deve essere di tipo stringa e secondo di tipo int.

Un altro esempio concreto di delegato è Func delegate. Func<bool> significa che il metodo non ha parametri e restituisce bool. Func<string, bool> significa che esiste un parametro di input di tipo string e restituisce bool.

EventHandler è solo un altro delegato, che rappresenta il metodo di tipo void ritorno e due parametri di ingresso: oggetto e EventArgs

3. Evento

basti pensare evento Button.Click. I programmatori di Microsoft che hanno lavorato sulla classe Button hanno dovuto fornire un modo per notificare il programma, facendo clic su quel pulsante. Quindi hanno definito un evento e tu puoi gestire l'evento fornendo un metodo che verrà eseguito quando si verifica l'evento. Il metodo è chiamato eventhandler.

4. EventHandler sono utilizzate sia come nome comune per i metodi che sono assinged ad eventi oppure è delegato calcestruzzo che definisce i parametri di ingresso e di uscita o è usato come.

ad esempio: Button.Click += DoSomehing;Click è un evento. Il metodo DoSomething è ed eventhandler. È necessario restituire void e avere due parametri di input di tipo object e EventArgs, perché quando si guarda la definizione di evento click, è possibile vedere il tipo di delegato concreto che è EventHandler (o RoutedEventHandler - solo un altro delegato utilizzato in WPF in alcuni eventi).

5. espressione Lambda

è molto semplice. L'espressione Lambda è solo un'altra sintassi per scrivere un metodo. Il compilatore traduce comunque lambda in metodi. Lambdas sono solo zucchero sintattico.

seguente metodo e lambda sono uguali

bool IsGreaterThan5(int number) 
{ 
    return number > 5; 
} 

var isGreaterThan5 = new Func<int, bool>(number => number > 5); 

per esempio, se si dispone di un array di interi, allora si può utilizzare il metodo estensione Where LINQ per filtrare l'array. Intelli sense ti dice che il parametro del metodo Where è Func<int, bool>. Pertanto è necessario passare il metodo che accetta un parametro di tipo int e restituisce bool.

int[] numbers = new []{ 1, 2, 3 4, 5, 6, 7 }; 
var filteredNumbers = numbers.Where(IsGreaterThan5); //method IsGreaterThan5 is defined in previus example 

//just another syntax: 
var filteredNumbers = numbers.Where(number => number > 5); 

//just another syntax: 
var filteredNumbers = numbers.Where(new Func<int, bool>(number => number > 5)); 

//just another syntax: 
Func<int, bool> isGreaterThan5 = i => i > 5; //it does not matter how you name the input parameter 
var filteredNumbers = numbers.Where(isGreaterThan5); 
+0

Grazie anche per la grande risposta e mettendo tutto insieme. C'è ancora qualcosa sugli eventi che mi infastidiscono. Capisco la semplice definizione che questa è una notifica ma sembra che rimanga qualcosa di inosservato su di loro. Sono riuscito a creare semplici pulsanti di lavoro, abilitando e disabilitando le aree usando le proprietà in MVVM ma quegli eventi non riesco a vederle chiaramente. Non so ancora come creare eventi specifici, ad esempio, che notificheranno ogni volta che qualcuno preme il pulsante freccia. Non riuscivo a trovarlo su google, quindi presumo che ci sia qualcosa di sbagliato nella mia comprensione di loro. – Bielik

+0

Di solito non è necessario definire i propri eventi. Non è necessario notificare a qualcuno che qualcuno ha premuto il tasto freccia, poiché esiste un framework WPF che attiva tali notifiche, ad esempio l'evento 'Window.KeyPress'. Hai solo bisogno di scrivere ciò che dovrebbe accadere quando si verifica l'evento. – Liero

+1

In WPF, esiste un evento specifico chiamato "PropertChanged" che notifica i controlli dell'interfaccia utente del database per aggiornarsi quando l'oggetto di origine cambia. In questo caso devi attivare l'evento quando cambi qualcosa in viewmodel e WPF è collegato all'evento e lo gestisce. Quindi questo è opposto allo scenario precedente con i tasti Si noti che eventi, delegati, ecc. Non sono specifici per MVVM, né WPF. Stai cercando di ingoiare due morsi contemporaneamente. – Liero