How to bind WF 4.0 arguments to ExpressionTextbox in Code

14 ביוני 2010

tags:
4 comments

Almost every activity has arguments. The workflow designer presents only the root activity's arguments (these are the "Workflow Arguments")

image

The activity's arguments has to be binded to ExpressionTextbox placed on the activity canvas (i.e. The Activity designer).

When your activity is static and is completely defined in xaml there is no problem to define the binding in the xaml definition of the activity designer (there are tons of examples).The question is what happens when arguments and ExpressionTextBoxes are built in code?
How can we bind dynamically created arguments with dynamically created ExpressionTextBox?

Dynamically created arguments should be placed in an Arguments collection. I like to use a dictionary so I can refer to it later by name (the key of the dictionary).

The arguments are crated in the CacheMetadata method.

string[] MyArgumentsNames = { "arg1,arg2" };

public Dictionary<string,Argument> Arguments { get; set; }

 

protected override void CacheMetadata(CodeActivityMetadata metadata)

{

  base.CacheMetadata(metadata);

  Collection<RuntimeArgument> arguments = new Collection<RuntimeArgument>();

 

  foreach (var argumentName in MyArgumentsNames)

  {

    //Create a new input argument of type string

    RuntimeArgument rtArgument =
      new RuntimeArgument("MyArgumentName",
                        typeof(string), ArgumentDirection.In);

    Arguements.Add(argumentName,
       Argument.Create(typeof(string), ArgumentDirection.In));

    metadata.Bind(Arguments[argumentName], rtArgument);

    arguments.Add(rtArgument);

   }

 

  //Set the arguments collection that has been built as part of the Activity's metadata

  metadata.SetArgumentsCollection(arguments);

}

After the argument is created it is time to bind it to a dynamically created ExpressionBox.

I wrote a little method that does exactly that. I assume the activity designer is no more than a simple grid with two columns.

public void DrawExpressionBoxOnCanvas(Grid activityGrid,

            string argumentName,Type argumentType,

            string direction, ModelItem ownerActivity)

{

   //Create a new row in the activity grid

   int rowIndex = activityGrid.RowDefinitions.Count;

   var newRow = new RowDefinition();

   activityGrid.RowDefinitions.Insert(rowIndex, newRow);

 

   //Create a text block on the grid with the argument name

   var txtBlock = new TextBlock();

   txtBlock.Uid = "txtBlock" + argumentName;

   txtBlock.Text = argumentName;

   txtBlock.Margin =

      new Thickness() { Bottom = 5, Top = 5, Left = 5, Right = 5 };

   Grid.SetColumn(txtBlock, 0);

   Grid.SetRow(txtBlock, rowIndex);

   activityGrid.Children.Add(txtBlock);

 

   //Create a new ExpressionTextBox on the activity grid

   var expressionTbx = new ExpressionTextBox();

   expressionTbx.Uid = "ExpressionBox" + argumentName;

   expressionTbx.HintText = String.Format("Enter {0}", argumentName);

   expressionTbx.ExpressionType = argumentType;

   expressionTbx.Margin =

      new Thickness() { Bottom = 5, Top = 5, Left = 5, Right = 5 };

   expressionTbx.Width = 110;

   expressionTbx.OwnerActivity = ownerActivity;

 

   // Create binding between the expression block and the activity's arguments

   var bind = new Binding();

   bind.Mode = BindingMode.TwoWay;

   bind.Converter = new ArgumentToExpressionConverter();

   bind.ConverterParameter = direction;

   bind.Path = new PropertyPath(

   String.Format("ModelItem.Arguments[{0}]", argumentName));

 

   //Out arguments require L-Value expression

   if (direction == "out")

       expressionTbx.UseLocationExpression = true;

 

   //Set the binding and Add the expression block to the grid

   expressionTbx.SetBinding(ExpressionTextBox.ExpressionProperty, bind);

   Grid.SetRow(expressionTbx, rowIndex);

   Grid.SetColumn(expressionTbx, 1);

   activityGrid.Children.Add(expressionTbx);

}

Hope this will help

Manu

Add comment
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

תגי HTML מותרים: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

4 comments

  1. Alexander29 בדצמבר 2010 ב 16:30

    Hi Manu
    Thank you for the valuable input.
    I get this exception:

    System.InvalidOperationException was unhandled by user code
    Message=The argument of type 'System.String' cannot be used. Make sure that it is declared on an activity.

    trying to get Argument value in execute :

    foreach (Argument item in _arguments.Values){
    object v =item.Get(context);
    }

    Can you please help to resolve this ?
    Thanks

    להגיב
  2. Mike29 בנובמבר 2012 ב 10:48

    I don't even want to admit as to how much time I wasted on a task trying to do just this very thing. Thank you!!!

    להגיב
  3. Amit6 ביוני 2013 ב 10:31

    I've implemented your solution in my rehosted wf designer and everything is fine except that the dynamic arguments (which i load from xml) never shown in the property editor (the propertyinspectorview).
    Is this a known issue for the re-hosted designer implementation or might it be some bug in my solution?

    Please help me.
    Thank you!

    להגיב
  4. Amit9 ביוני 2013 ב 2:45

    I've implemented your solution in my rehosted wf designer and everything is fine except that the dynamic arguments (which i load from xml) never shown in the property editor (the propertyinspectorview).
    Is this a known issue for the re-hosted designer implementation or might it be some bug in my solution?

    Please help me.
    Thank you!

    להגיב