e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
132 lines
4.4 KiB
C#
132 lines
4.4 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities.Statements
|
|
{
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Runtime;
|
|
using System.Runtime.Serialization;
|
|
using System.Windows.Markup;
|
|
using System.Activities;
|
|
using System.Activities.Validation;
|
|
using SA = System.Activities;
|
|
|
|
[ContentProperty("Body")]
|
|
public sealed class ForEach<T> : NativeActivity
|
|
{
|
|
Variable<IEnumerator<T>> valueEnumerator;
|
|
CompletionCallback onChildComplete;
|
|
|
|
public ForEach()
|
|
: base()
|
|
{
|
|
this.valueEnumerator = new Variable<IEnumerator<T>>();
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
public ActivityAction<T> Body
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[RequiredArgument]
|
|
[DefaultValue(null)]
|
|
public InArgument<IEnumerable<T>> Values
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
CompletionCallback OnChildComplete
|
|
{
|
|
get
|
|
{
|
|
if (this.onChildComplete == null)
|
|
{
|
|
this.onChildComplete = new CompletionCallback(GetStateAndExecute);
|
|
}
|
|
|
|
return this.onChildComplete;
|
|
}
|
|
}
|
|
|
|
protected override void OnCreateDynamicUpdateMap(DynamicUpdate.NativeActivityUpdateMapMetadata metadata, Activity originalActivity)
|
|
{
|
|
metadata.AllowUpdateInsideThisActivity();
|
|
}
|
|
|
|
protected override void CacheMetadata(NativeActivityMetadata metadata)
|
|
{
|
|
RuntimeArgument valuesArgument = new RuntimeArgument("Values", typeof(IEnumerable<T>), ArgumentDirection.In, true);
|
|
metadata.Bind(this.Values, valuesArgument);
|
|
|
|
metadata.AddArgument(valuesArgument);
|
|
metadata.AddDelegate(this.Body);
|
|
metadata.AddImplementationVariable(this.valueEnumerator);
|
|
}
|
|
|
|
protected override void Execute(NativeActivityContext context)
|
|
{
|
|
IEnumerable<T> values = this.Values.Get(context);
|
|
if (values == null)
|
|
{
|
|
throw SA.FxTrace.Exception.AsError(new InvalidOperationException(SA.SR.ForEachRequiresNonNullValues(this.DisplayName)));
|
|
}
|
|
|
|
IEnumerator<T> valueEnumerator = values.GetEnumerator();
|
|
this.valueEnumerator.Set(context, valueEnumerator);
|
|
|
|
if (this.Body == null || this.Body.Handler == null)
|
|
{
|
|
while (valueEnumerator.MoveNext())
|
|
{
|
|
// do nothing
|
|
};
|
|
valueEnumerator.Dispose();
|
|
return;
|
|
}
|
|
InternalExecute(context, null, valueEnumerator);
|
|
}
|
|
|
|
void GetStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance)
|
|
{
|
|
IEnumerator<T> valueEnumerator = this.valueEnumerator.Get(context);
|
|
Fx.Assert(valueEnumerator != null, "GetStateAndExecute");
|
|
InternalExecute(context, completedInstance, valueEnumerator);
|
|
}
|
|
|
|
void InternalExecute(NativeActivityContext context, ActivityInstance completedInstance, IEnumerator<T> valueEnumerator)
|
|
{
|
|
Fx.Assert(this.Body != null && this.Body.Handler != null, "Body and Body.Handler should not be null");
|
|
|
|
if (!valueEnumerator.MoveNext())
|
|
{
|
|
if (completedInstance != null)
|
|
{
|
|
if (completedInstance.State == ActivityInstanceState.Canceled ||
|
|
(context.IsCancellationRequested && completedInstance.State == ActivityInstanceState.Faulted))
|
|
{
|
|
context.MarkCanceled();
|
|
}
|
|
}
|
|
valueEnumerator.Dispose();
|
|
return;
|
|
}
|
|
|
|
// After making sure there is another value, let's check for cancelation
|
|
if (context.IsCancellationRequested)
|
|
{
|
|
context.MarkCanceled();
|
|
valueEnumerator.Dispose();
|
|
return;
|
|
}
|
|
|
|
context.ScheduleAction(this.Body, valueEnumerator.Current, this.OnChildComplete);
|
|
}
|
|
}
|
|
}
|