Condividi tramite


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

Footer image

Copyright © 2007 Microsoft Corporation. Tutti i diritti riservati.