ActivityFunc示例 - 实现自定义组件

浏览:1623 发布日期:2022-03-03 15:34:43

ActivityFunc示例 - 实现自定义组件

例如,我要实现一个BxFindNumber组件,它有一个集合,是List {3, 4, 7, 8},我们的组件遍历所有元素,当自定义活动返回true时,停止遍历,逻辑代码如下:

[Designer(typeof(FindNumberView))]
public sealed class BxFindNumer : NativeActivity<string>, IActivityTemplateFactory
{
    private List<int> list = new List<int>() { 3, 4, 7, 8 };
    private Variable<IEnumerator<int>> listEnumerator;
    private CompletionCallback<bool> onChildComplete;

    [Browsable(false)]
    public ActivityFunc<int, bool> Body { get; set; }

    private CompletionCallback<bool> OnChildComplete
    {
        get
        {
            if (this.onChildComplete == null)
            {
                this.onChildComplete = new CompletionCallback<bool>(this.getStateAndExecute);
            }

            return this.onChildComplete;
        }
    }

    public BxFindNumer()
    {
        this.listEnumerator = new Variable<IEnumerator<int>>();
    }

    public Activity Create(DependencyObject target)
    {
        return new BxFindNumer()
        {
            Body = new ActivityFunc<int, bool>()
            {
                Argument = new DelegateInArgument<int>() { Name = "n1" },
                Result = new DelegateOutArgument<bool> { Name = "r" },
                Handler = new Sequence()
            }
        };
    }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        metadata.AddDelegate(this.Body);
        metadata.AddImplementationVariable(this.listEnumerator);
        base.CacheMetadata(metadata);
    }

    protected override void Execute(NativeActivityContext context)
    {
        IEnumerator<int> enumerator = this.list.GetEnumerator();
        this.listEnumerator.Set(context, enumerator);
        if (this.Body == null || this.Body.Handler == null)
        {
            enumerator.Dispose();
        }
        else
        {
            internalExecute(context, null, enumerator);
        }
    }

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

    private void getStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance, bool result)
    {
        if (! result)
        {
            IEnumerator<int> listEnumerator = this.listEnumerator.Get(context);
            this.internalExecute(context, null, listEnumerator);
        }
        else
        {
            Console.WriteLine("结束执行");
        }
    }

我们的组件实现了IActivityTemplateFactory,它定义了ActivityFunc<int, bool>的输入参数n1,返回参数r,委托主体时一个Sequence对象:

public Activity Create(DependencyObject target)
{
    return new BxFindNumer()
    {
        Body = new ActivityFunc<int, bool>()
        {
            Argument = new DelegateInArgument<int>() { Name = "n1" },
            Result = new DelegateOutArgument<bool> { Name = "r" },
            Handler = new Sequence()
        }
    };
}

这样,我们在前台,可以使用n1来获取当前遍历值,我们通过把r设为true来停止遍历:

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

private void getStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance, bool result)
{
    if (! result)
    {
        IEnumerator<int> listEnumerator = this.listEnumerator.Get(context);
        this.internalExecute(context, null, listEnumerator);
    }
    else
    {
        Console.WriteLine("结束执行");
    }
}

它的视图代码如下:

<sap:ActivityDesigner x:Class="FindNumer.FindNumberView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sa="clr-namespace:System.Activities;assembly=System.Activities"
    xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
    xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
    xmlns:sadc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib">

    <sap:ActivityDesigner.Resources>
        <sadc:ArgumentToExpressionConverter x:Key="argConverter"></sadc:ArgumentToExpressionConverter>

        <DataTemplate x:Key="Collapsed">
            <StackPanel>
                <TextBlock><Run Text="FindNumberView"/></TextBlock>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="Expanded">
            <StackPanel MinWidth="250" MaxWidth="850">
                <StackPanel Orientation="Horizontal" Margin="0,10,0,0" MinWidth="400">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Margin="0,0,0,0" LineHeight="20">当前值</TextBlock>
                        <TextBox Name="directoryPathBox" x:Uid="directoryPathBox" AutomationProperties.Name="directory"
                            AutomationProperties.AutomationId="ArgumentName1" HorizontalAlignment="Stretch"
                            VerticalAlignment="Center" TextBlock.LineHeight="20" MinWidth="100" MaxLength="10"
                            Text="{Binding Path=ModelItem.Body.Argument.Name, Mode=TwoWay, ValidatesOnExceptions=true}" />
                    </StackPanel>

                    <StackPanel Orientation="Horizontal">
                        <TextBlock Margin="20,0,0,0" LineHeight="20">是否已找到</TextBlock>
                        <TextBox Name="filePathBox" x:Uid="filePathBox" AutomationProperties.Name="file"
                            AutomationProperties.AutomationId="ArgumentName2" HorizontalAlignment="Stretch"
                            VerticalAlignment="Center" TextBlock.LineHeight="20" MinWidth="100" MaxLength="10"
                            Text="{Binding Path=ModelItem.Body.Result.Name, Mode=TwoWay, ValidatesOnExceptions=true}" />
                    </StackPanel>
                </StackPanel>

                <sap:WorkflowItemPresenter x:Uid="sad:WorkflowItemPresenter_1" AutomationProperties.AutomationId="Activity"
                            IsDefaultContainer="true" HintText="把活动添加到这里"
                            AllowedItemType="{x:Type sa:Activity}" MinWidth="100" MinHeight="100"
                            Item="{Binding Path=ModelItem.Body.Handler, Mode=TwoWay}"/>
            </StackPanel>
        </DataTemplate>

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

    <Grid>
        <ContentPresenter Style="{DynamicResource ExpandOrCollapsedStyle}" Content="{Binding}" />
    </Grid>
</sap:ActivityDesigner>