1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 5 namespace System.Activities.Statements 6 { 7 using System.Collections; 8 using System.Collections.Generic; 9 using System.ComponentModel; 10 using System.Runtime; 11 using System.Runtime.Serialization; 12 using System.Windows.Markup; 13 using System.Activities; 14 using System.Activities.Validation; 15 using SA = System.Activities; 16 17 [ContentProperty("Body")] 18 public sealed class ForEach<T> : NativeActivity 19 { 20 Variable<IEnumerator<T>> valueEnumerator; 21 CompletionCallback onChildComplete; 22 ForEach()23 public ForEach() 24 : base() 25 { 26 this.valueEnumerator = new Variable<IEnumerator<T>>(); 27 } 28 29 [DefaultValue(null)] 30 public ActivityAction<T> Body 31 { 32 get; 33 set; 34 } 35 36 [RequiredArgument] 37 [DefaultValue(null)] 38 public InArgument<IEnumerable<T>> Values 39 { 40 get; 41 set; 42 } 43 44 CompletionCallback OnChildComplete 45 { 46 get 47 { 48 if (this.onChildComplete == null) 49 { 50 this.onChildComplete = new CompletionCallback(GetStateAndExecute); 51 } 52 53 return this.onChildComplete; 54 } 55 } 56 OnCreateDynamicUpdateMap(DynamicUpdate.NativeActivityUpdateMapMetadata metadata, Activity originalActivity)57 protected override void OnCreateDynamicUpdateMap(DynamicUpdate.NativeActivityUpdateMapMetadata metadata, Activity originalActivity) 58 { 59 metadata.AllowUpdateInsideThisActivity(); 60 } 61 CacheMetadata(NativeActivityMetadata metadata)62 protected override void CacheMetadata(NativeActivityMetadata metadata) 63 { 64 RuntimeArgument valuesArgument = new RuntimeArgument("Values", typeof(IEnumerable<T>), ArgumentDirection.In, true); 65 metadata.Bind(this.Values, valuesArgument); 66 67 metadata.AddArgument(valuesArgument); 68 metadata.AddDelegate(this.Body); 69 metadata.AddImplementationVariable(this.valueEnumerator); 70 } 71 Execute(NativeActivityContext context)72 protected override void Execute(NativeActivityContext context) 73 { 74 IEnumerable<T> values = this.Values.Get(context); 75 if (values == null) 76 { 77 throw SA.FxTrace.Exception.AsError(new InvalidOperationException(SA.SR.ForEachRequiresNonNullValues(this.DisplayName))); 78 } 79 80 IEnumerator<T> valueEnumerator = values.GetEnumerator(); 81 this.valueEnumerator.Set(context, valueEnumerator); 82 83 if (this.Body == null || this.Body.Handler == null) 84 { 85 while (valueEnumerator.MoveNext()) 86 { 87 // do nothing 88 }; 89 valueEnumerator.Dispose(); 90 return; 91 } 92 InternalExecute(context, null, valueEnumerator); 93 } 94 GetStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance)95 void GetStateAndExecute(NativeActivityContext context, ActivityInstance completedInstance) 96 { 97 IEnumerator<T> valueEnumerator = this.valueEnumerator.Get(context); 98 Fx.Assert(valueEnumerator != null, "GetStateAndExecute"); 99 InternalExecute(context, completedInstance, valueEnumerator); 100 } 101 InternalExecute(NativeActivityContext context, ActivityInstance completedInstance, IEnumerator<T> valueEnumerator)102 void InternalExecute(NativeActivityContext context, ActivityInstance completedInstance, IEnumerator<T> valueEnumerator) 103 { 104 Fx.Assert(this.Body != null && this.Body.Handler != null, "Body and Body.Handler should not be null"); 105 106 if (!valueEnumerator.MoveNext()) 107 { 108 if (completedInstance != null) 109 { 110 if (completedInstance.State == ActivityInstanceState.Canceled || 111 (context.IsCancellationRequested && completedInstance.State == ActivityInstanceState.Faulted)) 112 { 113 context.MarkCanceled(); 114 } 115 } 116 valueEnumerator.Dispose(); 117 return; 118 } 119 120 // After making sure there is another value, let's check for cancelation 121 if (context.IsCancellationRequested) 122 { 123 context.MarkCanceled(); 124 valueEnumerator.Dispose(); 125 return; 126 } 127 128 context.ScheduleAction(this.Body, valueEnumerator.Current, this.OnChildComplete); 129 } 130 } 131 } 132