locked
Writing WF xaml without VB RRS feed

  • Question

  • Hello Everyone,

         I was wondering if it is possible to hand write xaml code and not have to use VB at all, anywhere.  I'm guessing you can write an expression activity in code (C#) compile it, then use it in the xaml, that I plan to write out by hand.  Does anyone have an example of how I might do this?  If someone could write out a simple C# expression activity then show how you would use it in a xaml file that would be great.  Even if it is a Writeline activity, I just need the expression to be more than just a simple string (DateTime.Now would even work).  I just hate using VB mixed with C# knowing that I'm going to have to swap out all the VB once expressions can be done in C#.  I pray beta 2 offers salvation from this particular hassle.

    Thanks in advance,

    Bob
    Friday, June 26, 2009 3:37 AM

Answers

  • In all honesty, I'd suggest not doing this unless you really, really, really feel strongly about using C#.  As you'll see below there is a bit of parsing that is necessary to actually make this all work.  Also note that for small expressions the majority of VB => C# conversion can be done with a few regular expression based find and replace runs.

    http://msdn.microsoft.com/en-us/library/650ax5cx.aspx

    That article describes how to use classes in the CodeDom namespace to create and compile classes.

    http://msdn.microsoft.com/en-us/library/system.linq.expressions.aspx
    Contains a description of the Linq expression classes.

    The biggest issue you're going to find is that you need to convert from the way a user thinks about symbols to the way you need to access them within the runtime.  For example:

    Variable<string> nameVariable = new Variable<string> { Name = "name" };
    Sequence sequence = new Sequence
    {
        Variables = { nameVariable },
        Activities =
        {
            new WriteLine { Text = new CSharpExpression { ExpressionText = "\"Hello, \" + name" } }
        }
    }
    The user thinks of the variable in terms of the Name they've given it.  At runtime, however, this needs to be accessed in the context of the current environment.  The easiest way to set this up (again, easiest and not most performant) is to translate that expression string into something like the following class definition (expressed in CodeDom) and then compile it:

    class TemporaryClass
    {
        LocationEnvironment environment;
        Variable<string> nameVariable;
    
        public TemporaryClass(Variable<string> nameVariable)
        {
            this.nameVariable = nameVariable;
        }
    
        string name
        {
             get { return this.nameVariable.Get(this.environment) }
        }
    
        public string Evaluate(LocationEnvironment environment)
        {
             this.environment = environment;
             return "Hello, " + name;
        }
    }
    So, here are the tricky bits:
    * You need to parse the string to find all of the symbols so that you can turn them into properties.  Essentially you need to write a C# parser since there isn't one provided as part of the framework.
    * In CompileToExpressionTree you will be given a DeclaredEnvironment.  This can be used to convert from a symbol name ("name" in our example) to the backing variable or argument.  Once you have the backing variable or argument you can determine the symbol type.
    * After compiling you need to build up a Linq expression (the return value of CompileToExpressionTree) which calls your Evalute method on a preconstructed instance of your dynamically generated class.  You need to generate the class at this point so that it can keep a hold of the variable/argument that it needs to use at runtime.
    Friday, June 26, 2009 7:12 PM

All replies

  • You can use the CustomLanguageReference<TResult> and CustomLanguageValue<TResult> base classes to get started writing a C# expression activity.  There is an abstract CompileToExpressionTree method during which you'll need to convert your string into a Linq expression tree.  A quick and dirty way to do that (with questionable performance) is probably to use CodeDom to create a code snippet which represents a method and compile that in-memory to obtain a delegate to the method.  Then create a Linq expression which will call your delegate.

    We do not have plans to ship a pair of C# expression activities for this release.  We are, however, making a few enhancements to the CustomLanguage* base classes to make writing custom expression activities a little easier.
    Friday, June 26, 2009 5:59 PM
  • You may not have time to do this, but could you give more detail into how I would do this process you describe?  It sounds quite interesting, but I'm not sure how to proceed on an actual coding level.

    Bob
    Friday, June 26, 2009 6:38 PM
  • In all honesty, I'd suggest not doing this unless you really, really, really feel strongly about using C#.  As you'll see below there is a bit of parsing that is necessary to actually make this all work.  Also note that for small expressions the majority of VB => C# conversion can be done with a few regular expression based find and replace runs.

    http://msdn.microsoft.com/en-us/library/650ax5cx.aspx

    That article describes how to use classes in the CodeDom namespace to create and compile classes.

    http://msdn.microsoft.com/en-us/library/system.linq.expressions.aspx
    Contains a description of the Linq expression classes.

    The biggest issue you're going to find is that you need to convert from the way a user thinks about symbols to the way you need to access them within the runtime.  For example:

    Variable<string> nameVariable = new Variable<string> { Name = "name" };
    Sequence sequence = new Sequence
    {
        Variables = { nameVariable },
        Activities =
        {
            new WriteLine { Text = new CSharpExpression { ExpressionText = "\"Hello, \" + name" } }
        }
    }
    The user thinks of the variable in terms of the Name they've given it.  At runtime, however, this needs to be accessed in the context of the current environment.  The easiest way to set this up (again, easiest and not most performant) is to translate that expression string into something like the following class definition (expressed in CodeDom) and then compile it:

    class TemporaryClass
    {
        LocationEnvironment environment;
        Variable<string> nameVariable;
    
        public TemporaryClass(Variable<string> nameVariable)
        {
            this.nameVariable = nameVariable;
        }
    
        string name
        {
             get { return this.nameVariable.Get(this.environment) }
        }
    
        public string Evaluate(LocationEnvironment environment)
        {
             this.environment = environment;
             return "Hello, " + name;
        }
    }
    So, here are the tricky bits:
    * You need to parse the string to find all of the symbols so that you can turn them into properties.  Essentially you need to write a C# parser since there isn't one provided as part of the framework.
    * In CompileToExpressionTree you will be given a DeclaredEnvironment.  This can be used to convert from a symbol name ("name" in our example) to the backing variable or argument.  Once you have the backing variable or argument you can determine the symbol type.
    * After compiling you need to build up a Linq expression (the return value of CompileToExpressionTree) which calls your Evalute method on a preconstructed instance of your dynamically generated class.  You need to generate the class at this point so that it can keep a hold of the variable/argument that it needs to use at runtime.
    Friday, June 26, 2009 7:12 PM
  • I find the lack of support for Expressions in C# more than a little disappointing.  It's was the same story for SSIS in 2005 and BizTalk 2004.  I just hope this thing doesn't go to market with this limitation.

    Friday, June 26, 2009 8:57 PM
  • Please keep in mind that our VisualBasicValue/Reference activities are written on top of the CustomLanguageValue/Reference classes without any internal knowledge of the runtime.  Said another way, this type of activity is an extensibility point and not something that requires specific runtime support.

    So, it's not that we don't support C# expressions.  It is just that we do not currently have C# expression activities provided out of the box.

    Friday, June 26, 2009 9:17 PM
  • Thanks Nate!  Maybe I will consider the regular expression replacement, but it is helpful to understand what you discussed.

    Bob
    Friday, June 26, 2009 10:09 PM
  • The sample on this blog not only shows you how to use WF to supplant C# for customisable logic; it shows you how to deploy a designer with your app so that you can change code logic without recompiling your app:

    http://christianfindlay.blogspot.com/2011/02/soft-coding-logic-with-wf.html

    Wednesday, February 23, 2011 9:32 AM