Attività composta personalizzata tramite l'oggetto NativeActivity

L'esempio CustomCompositeNativeActivity illustra come scrivere un oggetto NativeActivity che pianifica altri oggetti Activity per controllare il flusso dell'esecuzione di un flusso di lavoro. In questo esempio vengono usati due flussi di controllo comuni, Sequence e While, per illustrate le operazioni da eseguire.

Dettagli dell'esempio

Iniziando da MySequence, la prima cosa da notare è che deriva da NativeActivity. NativeActivity è l'oggetto Activity che espone l'intero runtime del flusso di lavoro attraverso l'oggetto NativeActivityContext passato al metodo Execute.

L'oggetto MySequence espone una raccolta pubblica di oggetti Activity che viene popolata dall'autore del flusso di lavoro. Prima dell'esecuzione del flusso di lavoro, il relativo runtime chiama il metodo CacheMetadata in ogni attività di un flusso di lavoro. Durante questo processo, il runtime stabilisce relazioni padre-figlio per l'ambito dei dati e la gestione di durata. L'implementazione predefinita del metodo CacheMetadata usa la classe dell'istanza TypeDescriptor per indicare all'attività MySequence di aggiungere qualsiasi proprietà pubblica di tipo Activity o IEnumerable<Activity> come elementi figlio dell'attività MySequence.

Ogni volta che un'attività espone una raccolta pubblica di attività figlio, è probabile che queste ultime condividano lo stato. Una procedura consigliata per l'attività padre, in questo caso MySequence, consiste nell'esporre anche una raccolta di variabili tramite cui le attività figlio possono portare a termine questa operazione. Come nel caso delle attività figlio, il metodo CacheMetadata aggiunge proprietà pubbliche di tipo Variable o IEnumerable<Variable> come variabili associate all'attività MySequence.

Oltre alle variabili pubbliche che vengono modificate dagli elementi figlio dell'oggetto MySequence, quest'ultimo deve anche tenere traccia della posizione occupata nell'esecuzione dei relativi elementi figlio. Per eseguire questa operazione, usa una variabile privata, ovvero currentIndex. Questa variabile viene registrata come parte dell'ambiente MySequence mediante l'aggiunta di una chiamata al metodo AddImplementationVariable all'interno del metodo CacheMetadata dell'attività MySequence. Gli oggetti Activity aggiunti alla raccolta MySequence Activities non possono accedere alle variabili aggiunte in questo modo.

Quando l'oggetto MySequence viene eseguito dal runtime, quest'ultimo chiama il metodo Execute, passando un oggetto NativeActivityContext. NativeActivityContext è il proxy dell'attività che torna nel runtime per dereferenziare gli argomenti e le variabili, nonché per pianificare altri oggetti Activity o ActivityDelegates. MySequence usa un metodo InternalExecute per incapsulare la logica di pianificazione del primo elemento figlio e di tutti gli elementi figlio successivi in un singolo metodo. Inizia dereferenziando il riferimento currentIndex. Se è uguale al conteggio nella raccolta Activities, la sequenza è completata, l'attività viene restituita senza pianificare nessuna operazione e lo stato del runtime viene impostato su Closed. Se currentIndex è inferiore al numero delle attività, l'elemento figlio successivo viene ottenuto dalla raccolta Activities e MySequence chiama il metodo ScheduleActivity, passando l'elemento figlio da pianificare e un oggetto CompletionCallback che punta al metodo InternalExecute. Infine, viene incrementato l'oggetto currentIndex e il controllo viene di nuovo restituito al runtime. Finché un'istanza dell'oggetto MySequence dispone di un oggetto Activity figlio pianificato, il runtime considera che si trovi nello stato Executing.

Una volta completata l'attività figlio, viene eseguito l'oggetto CompletionCallback. Il ciclo continua dall'inizio. Come per Execute, un oggetto CompletionCallback accetta un oggetto NativeActivityContext, consentendo al responsabile dell'implementazione di accedere al runtime.

MyWhile è diverso da MySequence in quanto pianifica ripetutamente un singolo oggetto Activity e usa un oggetto Activity<TResult><bool> denominato Condition per determinare se è necessario eseguire questa pianificazione. Come per MySequence, l'oggetto MyWhile usa un metodo InternalExecute per centralizzare la relativa logica di pianificazione. Pianifica l'oggetto ConditionActivity<bool> con un oggetto CompletionCallback<TResult><bool> denominato OnEvaluationCompleted. Quando viene completata l'esecuzione di Condition, il risultato diventa disponibile tramite questo oggetto CompletionCallback in un parametro fortemente tipizzato denominato result. Se true, l'oggetto MyWhile chiama il metodo ScheduleActivity, passando gli oggetti BodyActivity e InternalExecute come oggetto CompletionCallback. Quando viene completata l'esecuzione dell'oggetto Body, l'oggetto Condition viene nuovamente pianificato in InternalExecute, avviando di nuovo il ciclo. Quando l'oggetto Condition restituisce false, un'istanza dell'oggetto MyWhile restituisce il controllo al runtime senza pianificare l'oggetto Body e il runtime ne imposta lo stato su Closed.

Per impostare, compilare ed eseguire l'esempio

  1. In Visual Studio aprire la soluzione di esempio Composite.sln.

  2. Compilare ed eseguire la soluzione.