例如,我要实现一个组件For2,它有一个集合,是List
我们先实现逻辑代码,此代码参考了.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参数了,我们可以依次处理集合的值。