Creazione di attività composte personalizzate
Quando si creano attività composte personalizzate, sono disponibili varie opzioni per la progettazione e creazione della logica predefinita per l'attività composta personalizzata.
Aggiunta del supporto in fase di progettazione a un'attività composta personalizzata
Se l'attività deriva da CompositeActivity e si desidera il supporto in fase di progettazione per l'attività, è necessario impostare DesignerAttribute su un derivato di CompositeActivityDesigner, ad esempio ParallelActivityDesigner o SequentialActivityDesigner. Ovviamente, è anche possibile creare il proprio CompositeActivityDesigner derivando direttamente da CompositeActivityDesigner.
Ad esempio, se si desidera creare un'attività composta personalizzata che rispecchia l'esperienza della fase di progettazione dell'attività ParallelActivity, è necessario aggiungere il codice seguente alla definizione di attività personalizzata:
<Designer(GetType(ParallelActivityDesigner), GetType(IDesigner))> _
Public Class CustomCompositeActivity
Inherits CompositeActivity
' Define custom activity here.
End Class
[Designer(typeof(ParallelActivityDesigner), typeof(IDesigner))]
public class CustomCompositeActivity : CompositeActivity
{
// Define custom activity here.
}
È anche possibile utilizzare SequentialActivityDesigner per creare un'attività personalizzata che rispecchia l'esperienza fase di progettazione dell'attività SequenceActivity, anche se un metodo più semplice è di derivare l'attività personalizzata dalla SequenceActivity stessa. Inoltre, la disponibilità di questa attività come classe di base per l'attività personalizzata, la logica predefinita per la pianificazione dell'esecuzione delle attività in modo sequenziale viene fornita automaticamente.
Per contro, se si desidera nascondere la struttura interna dell'attività composta personalizzata, come nel caso di una derivata da SequenceActivity, è necessario impostare DesignerAttribute su ActivityDesigner perché questo tipo non fornisce il supporto in fase di progettazione per le attività composte.
Aggiunta di attività figlio a un'attività composta personalizzata.
È possibile scegliere come aggiungere le attività figlio all'attività personalizzata. È possibile utilizzare due metodi per aggiungere attività figlio all'attività composta personalizzata:
Derivando l’attività personalizzata da SequenceActivity.
Derivando l’attività personalizzata da CompositeActivity.
L'attività CompositeActivity non contiene logica predefinita per la gestione delle attività figlio. Se si desidera creare un'attività composta personalizzata, è comunque necessario eseguire l'override di Execute per gestire l'esecuzione delle attività figlio e di Cancel per annullare le attività figlio e chiudere l'attività personalizzata.
Nell'esempio seguente è mostrato come aggiungere le attività CodeActivity a un'attività composta personalizzata che si comporta come un'attività ParallelActivity. È inoltre necessario ereditare da IActivityEventListener per ricevere la notifica della generazione degli eventi Closed e Executing su un'attività figlio.
<Designer(GetType(ParallelActivityDesigner), GetType(IDesigner))> _
Public Class CustomCompActivity
Inherits CompositeActivity
Implements IActivityEventListener(Of ActivityExecutionStatusChangedEventArgs)
' Declare variables.
Private ca1 As CodeActivity
Private ca2 As CodeActivity
Private ca3 As CodeActivity
Private ca4 As CodeActivity
Private index As Integer
Public Sub New()
InitializeComponent()
End Sub
' Initialize your child activities and add them to your custom
' composite activity.
Private Sub InitializeComponent()
Me.CanModifyActivities = True
Me.ca1 = New CodeActivity("CodeActivity1")
Me.ca2 = New CodeActivity("CodeActivity2")
Me.ca3 = New CodeActivity("CodeActivity3")
Me.ca4 = New CodeActivity("CodeActivity4")
AddHandler ca.ExecuteCode, AddressOf ca_ExecuteCode
AddHandler ca2.ExecuteCode, AddressOf ca_ExecuteCode
AddHandler ca4.ExecuteCode, AddressOf ca_ExecuteCode
AddHandler ca4.ExecuteCode, AddressOf ca_ExecuteCode
Me.Activities.Add(ca1)
Me.Activities.Add(ca2)
Me.Activities.Add(ca3)
Me.Activities.Add(ca4)
' Cache index value of last child activity in the collection.
index = Me.Activities.Count - 1
Me.CanModifyActivities = False
End Sub
Protected Overrides Function Execute(ByVal ExecutionContext As ActivityExecutionContext) As ActivityExecutionStatus
If (ExecutionContext Is Nothing) Then
Throw New ArgumentNullException("ExecutionContext")
End If
' If there are no child activities initialized, then close
' the parent activity.
If (Me.EnabledActivities.Count = 0) Then
Return ActivityExecutionStatus.Closed
End If
' Cycle through all of the enabled child activities in your
' activity, register for their Closed and Executing events,
' and then run the child activity.
Dim i As Integer
For i = 0 To Me.EnabledActivities.Count - 1 Step +1
Dim ChildActivity As Activity = Me.EnabledActivities(i)
ChildActivity.RegisterForStatusChange(Activity.ClosedEvent, Me)
ChildActivity.RegisterForStatusChange(Activity.ExecutingEvent, Me)
ExecutionContext.ExecuteActivity(ChildActivity)
Next
Return ActivityExecutionStatus.Executing
End Function
' This event handler is used for the ExecuteCode event that
' each CodeActivity activity will raise during its execution.
Private Sub ca_ExecuteCode(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine("In event handler for {0}.ExecuteCode event...", CType(sender, Activity).Name)
End Sub
' Implement the IActivityEventListener.OnEvent method to
' display the current activity state and close your
' parent custom activity when all of the child activities are
' are either in the Initialized or Closed state. Otherwise, keep
' the parent activity running.
Sub OnEvent(ByVal Sender As Object, ByVal E As ActivityExecutionStatusChangedEventArgs) Implements IActivityEventListener(Of System.Workflow.ComponentModel.ActivityExecutionStatusChangedEventArgs).OnEvent
If (Sender Is Nothing) Then
Throw New ArgumentNullException("Sender")
End If
If (E Is Nothing) Then
Throw New ArgumentNullException("E")
End If
Dim Context As ActivityExecutionContext = CType(Sender, ActivityExecutionContext)
If (Context Is Nothing) Then
Throw New ArgumentException("The sender must be an ActivityExecutionContext object", "Sender")
End If
Dim CustActivity As CustomCompActivity = CType(Context.Activity, CustomCompActivity)
' Display the current state of the child activity.
Console.WriteLine("{0} is in the {1} state.", E.Activity.Name, E.ExecutionStatus)
' As a good coding practice, unregister for the Closed event if
' the child activity is in the closed state.
If (E.Activity.ExecutionStatus = ActivityExecutionStatus.Closed) Then
E.Activity.UnregisterForStatusChange(Activity.ClosedEvent, Me)
End If
' Check whether the activity passed into the payload of the
' ActivityExecutionStatusChangedEventArgs object is the last
' child activity and if it is in either the Initialized state
' or Closed state before closing the parent activity.
If (E.Activity.Equals(CustActivity.EnabledActivities(index)) And (E.ExecutionStatus = ActivityExecutionStatus.Closed Or E.ExecutionStatus = ActivityExecutionStatus.Initialized)) Then
' The child activities are now in a closed state, so it is
' safe to put your custom activity in a closed state as well.
Context.CloseActivity()
End If
End Sub
End Class
[Designer(typeof(ParallelActivityDesigner), typeof(IDesigner))]
public class CustomCompActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
{
// Declare variables.
private CodeActivity ca1;
private CodeActivity ca2;
private CodeActivity ca3;
private CodeActivity ca4;
private int index;
public CustomCompActivity()
{
InitializeComponent();
}
// Initialize your child activities and add them to your custom
// composite activity.
private void InitializeComponent()
{
this.CanModifyActivities = true;
this.ca1 = new CodeActivity("CodeActivity1");
this.ca2 = new CodeActivity("CodeActivity2");
this.ca3 = new CodeActivity("CodeActivity3");
this.ca4 = new CodeActivity("CodeActivity4");
ca1.ExecuteCode += new EventHandler(ca_ExecuteCode);
ca2.ExecuteCode += new EventHandler(ca_ExecuteCode);
ca3.ExecuteCode += new EventHandler(ca_ExecuteCode);
ca4.ExecuteCode += new EventHandler(ca_ExecuteCode);
this.Activities.Add(ca1);
this.Activities.Add(ca2);
this.Activities.Add(ca3);
this.Activities.Add(ca4);
// Cache index value of last child activity in the collection.
index = this.Activities.Count - 1;
this.CanModifyActivities = false;
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (executionContext == null)
throw new ArgumentNullException("executionContext");
// If there are no child activities initialized, then close
// the parent activity.
if (this.EnabledActivities.Count == 0)
{
return ActivityExecutionStatus.Closed;
}
// Cycle through all of the enabled child activities in your
// activity, register for their Closed event, and then run the
// child activity.
for (int i = 0; i < this.EnabledActivities.Count; ++i)
{
Activity childActivity = this.EnabledActivities[i];
childActivity.RegisterForStatusChange(Activity.ClosedEvent, this);
childActivity.RegisterForStatusChange(Activity.ExecutingEvent, this);
executionContext.ExecuteActivity(childActivity);
}
return ActivityExecutionStatus.Executing;
}
// This event handler is used for the ExecuteCode event that
// each CodeActivity activity will raise during its execution.
void ca_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine ("In event handler for {0}.ExecuteCode event...", ((Activity)sender).Name);
}
// Implement the IActivityEventListener.OnEvent event handler to
// display the current activity state and close your parent custom
// activity when all of the child activities are either in the
// Initialized or Closed state. Otherwise, keep the parent activity
// running.
public void OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
{
if (sender == null)
throw new ArgumentNullException("sender");
if (e == null)
throw new ArgumentNullException("e");
ActivityExecutionContext context = sender as ActivityExecutionContext;
if (context == null)
throw new ArgumentException("The sender must be an ActivityExecutionContext object", "sender");
CustomCompActivity custActivity = context.Activity as CustomCompActivity;
// Display the current state of the child activity.
Console.WriteLine ("{0} is in the {1} state.", e.Activity.Name, e.ExecutionStatus);
// As a good coding practice, unregister for the Closed event
// if the child activity is in the closed state.
if (e.Activity.ExecutionStatus == ActivityExecutionStatus.Closed)
{
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
}
// Check whether the activity passed into the payload of the
// ActivityExecutionStatusChangedEventArgs object is the last
// child activity and if it is in either the Initialized state
// or Closed state before closing the parent activity.
if (e.Activity.Equals(custActivity.EnabledActivities[index]) && (e.ExecutionStatus == ActivityExecutionStatus.Closed || e.ExecutionStatus == ActivityExecutionStatus.Initialized))
{
// The child activities are now in a closed state, so it is
// safe to put your custom activity in a closed state as
// well.
context.CloseActivity();
}
}
}
Utilizzando l'esempio precedente, l'attività personalizzata verrà bloccata quando viene utilizzata in una progettazione flussi di lavoro. Se si desidera fornire un'attività personalizzata che contiene attività figlio che possono essere modificate in fase di progettazione, è necessario creare una classe personalizzata che deriva da ActivityToolboxItem.
Elementi della casella degli strumenti personalizzati
Nell'esempio di codice seguente viene illustrato un elemento della casella degli strumenti personalizzato per un'attività composta personalizzata. L'elemento della casella degli strumenti aggiunge un'attività CodeActivity all'attività composta personalizzata.
<Serializable()> _
Public Class SampleToolboxItem
Inherits ActivityToolboxItem
Protected Overrides Function CreateComponentsCore(ByVal designerHost As IDesignerHost) As IComponent()
Dim CompActivity As CustomCompositeActivity = New CustomCompositeActivity()
CompActivity.Activities.Add(New CodeActivity())
CompActivity.Activities.Add(New CodeActivity())
Return (New IComponent() {CompActivity})
End Function
End Class
[Serializable]
public class SampleToolboxItem: ActivityToolboxItem
{
protected override IComponent[] CreateComponentsCore(IDesignerHost designerHost)
{
CustomCompositeActivity CompActivity = new CustomCompositeActivity();
CompActivity.Activities.Add(new CodeActivity());
CompActivity.Activities.Add(new CodeActivity());
return new IComponent[] {CompActivity};
}
}
Quando si utilizza SampleToolboxItem con l'attività composta personalizzata, è necessario dichiararlo tramite ToolboxItemAttribute come mostrato nell'esempio seguente.
<ToolboxItem(GetType(SampleToolboxItem))> _
[ToolboxItem(typeof(SampleToolboxItem))]
Come è stato osservato in una sezione precedente, se per l'attività composta personalizzata è necessaria la finestra di progettazione per mostrare le attività figlio, quali le attività CodeActivity in questo esempio, l'attività personalizzata deve essere associata a un CompositeActivityDesigner come ParallelActivityDesigner o a una finestra di progettazione personalizzata che deriva da una delle classi di bade del CompositeActivityDesigner.
Vedere anche
Riferimenti
CompositeActivity
SequenceActivity
CompositeActivityDesigner
ParallelActivityDesigner
SequentialActivityDesigner
ActivityToolboxItem
Concetti
Creazione di attività personalizzate
Informazioni sul contesto di esecuzione delle attività
Informazioni sul modello di stati dell'attività
Altre risorse
Attività di Windows Workflow Foundation
Copyright © 2007 Microsoft Corporation. Tutti i diritti riservati.