Activity cannot set a Variable defined within its scope?
This one is making me scratch my head, and I'm wondering if I am understanding this correctly.
I'm trying to define a Variable within an Activity that can be used by child Activities. The Parent should be able to set a value in this Variable at runtime.
Here's the stripped down Parent class:
public sealed class Parent : NativeActivity, IActivityTemplateFactory
{
public Collection<Child> Children { get; private set; }
private CompletionCallback<string> _cc;
private Variable<int> _index;
public Collection<Variable> Variables { get; private set; }
public Parent()
{
Children = new Collection<Child>();
_index = new Variable<int>();
_cc = new CompletionCallback<string>(OnComplete);
Variables = new Collection<Variable>();
}
protected override void CacheMetadata(NativeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
metadata.AddImplementationVariable(_index);
metadata.SetVariablesCollection(Variables);
}
protected override void Execute(NativeActivityContext context)
{
_index.Set(context, 0);
var input = Variables.First(x => x.Name == "ThisIsTheVariable");
input.Set(context, "This is the Value");
context.ScheduleActivity(Children[0], _cc);
}
private void OnComplete(NativeActivityContext context, ActivityInstance instance, string result)
{
var index = _index.Get(context) + 1;
_index.Set(context, index);
Console.WriteLine(result);
if (index < Children.Count)
context.ScheduleActivity(Children[index], _cc);
}
Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
var retval = new Parent();
retval.Variables.Add(new Variable<string>("ThisIsTheVariable"));
return retval;
}
}
Now, if I add this to a workflow and run it, I get the following highly ironic exception:
Activity '1.1: Parent' cannot access this variable because it is declared at the scope of activity '1.1: Parent'. An activity can only access its own implementation variables.
The problem is that I need to pass a value to my child Activities that they can bind to at design time. That means that whatever holds the value must be visible within the intellisense of the child Activities. The only ways I can think of doing this is to define a Variable like above, or create an OutArgument on the parent. The second option flat out sucks.
How can I get around this?
Edit
Tried to do a little trickery with t开发者_如何学运维he variable that didn't work.
I declared a variable within my Parent:
// declaration
private Variable<string> _text;
// in ctor I create it
_text = new Variable<string>(InputName);
// in CacheMetadata I declare it an implementation variable
metadata.AddImplementationVariable(_text);
// in IActivityTemplateFactory.Create I add it to Variables
var retval = new Parent()
{
Input = new InArgument<string>()
};
retval.Variables.Add(retval._text);
return retval;
This works up until execution time. The variable appears in the design surface and my child activities can bind against it. But I still can't touch it at runtime. I can attempt to do this two ways:
// set text via the implementation variable
protected override void Execute(NativeActivityContext context)
{
_text.Set(context, "DERP");
context.ScheduleActivity(Children[0], _cc);
}
This doesn't throw, but the child activities never see DERP
, as the instance of the Variable they are bound against apparently isn't the same as _text
as the binding evaluates to null
.
The second way is to grab the Variable from the Variables collection and set it.
protected override void Execute(NativeActivityContext context)
{
Variables.First().Set(context, "DERP");
context.ScheduleActivity(Children[0], _cc);
}
This results in the same exception being thrown. I can't touch a variable defined within my own scope.
You need to use an ActivityAction to wrap the child activities that need access to the same variable and pass it through there. The variable itself needs to be added using NativeActivityMetadata.AddImplementationVariable to the parent activity itself can manipulate it like you are doing. That is the way activities like the ForEach are doing it as well.
See my blog post here for more details.
Old question, but since I was looking for a solution, maybe someone else is still looking too...
I found a way to do this using the context.DataContext.
In your original example, replace;
var input = Variables.First(x => x.Name == "ThisIsTheVariable");
input.Set(context, "This is the Value");
with;
var input = context.DataContext.GetProperties()["ThisIsTheVariable"];
input.SetValue(context.DataContext, "This is the Value");
精彩评论