ActivityAction示例 - 实现自定义组件

浏览:1681 发布日期:2021-11-21 08:36:15

ActivityAction示例 - 实现自定义组件

例如,我要实现一个组件For2,它有一个集合,是List {1, 2, 3},我们要把遍历的每一项,传递到前台,以实现自定义处理:

我们先实现逻辑代码,此代码参考了.net Foreach的实现:

[Designer(typeof(For2View))]
[ContentProperty("Body")]
public sealed class For2 : NativeActivity
{
    private Variable<IEnumerator<int>> valueEnumerator;
    private CompletionCallback onChildComplete;

    [DefaultValue(null)]
    public ActivityAction<int> Body { get; set; }

    private List<int> values = new List<int>{ 1, 2, 3 };

    public For2()
    {
        this.DisplayName = "我的For2";
        this.valueEnumerator = new Variable<IEnumerator<int>>();
    }

    private CompletionCallback OnChildComplete
    {
        get
        {
            if (this.onChildComplete == null)
                this.onChildComplete = new CompletionCallback(this.GetStateAndExecute);
            return this.onChildComplete;
        }
    }

    private void GetStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance)
    {
        IEnumerator<int> valueEnumerator = this.valueEnumerator.Get((ActivityContext)context);
        this.InternalExecute(context, completedInstance, valueEnumerator);
    }

    protected override void OnCreateDynamicUpdateMap(
        NativeActivityUpdateMapMetadata metadata,
        Activity originalActivity)
    {
        metadata.AllowUpdateInsideThisActivity();
    }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        metadata.AddDelegate(this.Body);
        metadata.AddImplementationVariable(this.valueEnumerator);

        base.CacheMetadata(metadata);
    }

    protected override void Execute(NativeActivityContext context)
    {
        IEnumerator<int> enumerator = values.GetEnumerator();
        this.valueEnumerator.Set(context, enumerator);


        if (this.Body == null || this.Body.Handler == null)
        {
            do
                ;
            while (enumerator.MoveNext());
            enumerator.Dispose();
        }
        else
        {
            this.Body.Argument.Name = "item";
            Console.WriteLine("Name: " + this.Body.Argument.Name);
            this.InternalExecute(context, (ActivityInstance)null, enumerator);
        }

    }

    private void InternalExecute(NativeActivityContext context, ActivityInstance completedInstance, 
        IEnumerator<int> valueEnumerator)
    {
        if (!valueEnumerator.MoveNext())
        {
            if (completedInstance != null && (completedInstance.State == ActivityInstanceState.Canceled || context.IsCancellationRequested && completedInstance.State == ActivityInstanceState.Faulted))
                context.MarkCanceled();
            valueEnumerator.Dispose();
        }
        else if (context.IsCancellationRequested)
        {
            context.MarkCanceled();
            valueEnumerator.Dispose();
        }
        else
        {
            context.ScheduleAction<int>(this.Body, valueEnumerator.Current, this.OnChildComplete);
        }

    }
}

For2View实现如下:

<sap:ActivityDesigner.Resources>
        <sapc:ArgumentToExpressionConverter x:Key="argumentToExpressionConverter" x:Uid="sadv:ArgumentToExpressionConverter_1"/>

        <DataTemplate x:Key="Expanded"  x:Uid="DataTemplate_1">
            <Grid x:Uid="Grid_1" Width="Auto">
                <Grid.RowDefinitions>
                    <RowDefinition x:Uid="RowDefinition_1"/>
                    <RowDefinition x:Uid="RowDefinition_2"/>
                    <RowDefinition x:Uid="RowDefinition_3"/>
                </Grid.RowDefinitions>
                <StackPanel x:Uid="StackPanel_1" Grid.Row="0" Orientation="Horizontal">
                    <TextBlock x:Uid="TextBlock_1" TextAlignment="Center" HorizontalAlignment="Center" 
                                VerticalAlignment="Center" Text="For2"
                        Margin="0"  />
                    <TextBox Name="argumentNameBox" x:Uid="argumentNameBox" 
                        AutomationProperties.AutomationId="ArgumentName"
                        AutomationProperties.Name="ForEach" Width="50" Margin="7,0,0,0" HorizontalAlignment="Stretch"
                        VerticalAlignment="Center" 
                        Text="{Binding Path=ModelItem.Body.Argument.Name, Mode=TwoWay, ValidatesOnExceptions=true}"/>
                </StackPanel>
                <StackPanel Grid.Row="1"></StackPanel>
                <TextBlock Margin="0,10,0,7" Text="Body" x:Uid="Label_11" Grid.Row="1"/>
                <Border x:Uid="GroupBox_1" Grid.Row="2" CornerRadius="2" BorderThickness="1">
                    <sap:WorkflowItemPresenter x:Uid="sad:WorkflowItemPresenter_1" AutomationProperties.AutomationId="Activity"
                                        IsDefaultContainer="true" HintText="拖动活动到这里"
                                        AllowedItemType="{x:Type sa:Activity}" MinWidth="100" MinHeight="100" Margin="7"
                                        AutomationProperties.Name="Body: Drop activity here"
                                        Item="{Binding Path=ModelItem.Body.Handler, Mode=TwoWay}"/>
                </Border>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="Collapsed">
            <TextBlock>我折叠了</TextBlock>
        </DataTemplate>

        <Style x:Key="ExpandOrCollapsedStyle" TargetType="{x:Type ContentPresenter}">
            <Setter Property="ContentTemplate" Value="{DynamicResource Collapsed}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=ShowExpanded}" Value="true">
                    <Setter Property="ContentTemplate" Value="{DynamicResource Expanded}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

    </sap:ActivityDesigner.Resources>

    <Grid>
        <ContentPresenter x:Uid="ContentPresenter_1" Style="{DynamicResource ExpandOrCollapsedStyle}" Content="{Binding}" />
    </Grid>

可是我们会发现,无法使用每一项,因为我们在Textbox中绑定了委托的Argument.Name,但由于我们还没有拖动Activity到视图中,所以Body.Argument.Name是null的,无法实现我们的功能:

所以我们添加一个For2WithBody类,它实现了IActivityTemplateFactory

public class For2WithBody : IActivityTemplateFactory
{
    public Activity Create(DependencyObject target)
    {
        return new For2()
        {
            Body = new ActivityAction<int>()
            {
                Argument = new DelegateInArgument<int>()
                {
                    Name = "item"
                }
            }
        };
    }
}

我们创建了For2的实例,并设置了参数的名称,这样就可以在前台使用item参数了,我们可以依次处理集合的值。