例如,我要实现一个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>