locked
Questions on Implementing a Custom Expression Editor RRS feed

  • Question

  • Hello,

    Cathy Dumas wrote a blog post titled Implementing a Custom Expression Editor, which features a sample application by Eric Wong. I've reviewed the blog post and the sample application.  Thanks to both Cathy and Eric for sharing this information.  I have a number of questions that I hope Cathy, Eric or someone else can help answer.

    1. The first question I have is how to invoke the various methods in MyExpressionEditorInstance.  When I click into the expression text block, I get a "Focus" message box displayed.  Otherwise, when I interact with the text of the edit box with my keyboard and mouse, I don't get many additional message boxes.  The only message boxes I see are when I use the few keyboard shortcuts Cathy mentions in her blog.  My questions are:
      a. Is triggering the various methods restricted to keyboard shortcuts, as currently implemented in the sample application?
      b. Is there some documentation you can point me to that lists some of these keyboard shortcuts (are they the same as in the "big" VB editor, and are they subject to any user profile settings)?
      c. Should I get some sort of message box when the expression editor is destroyed?  (In the sample app, it appears that once a text box is entered, the expression editor is never destroyed, but I'm not sure).

    2. The blog post says that one use case of this expression editor is to support the scenario where the end user is not familiar with VB.  This is a use case I'm very much interested in.  But I'm not sure how to achieve this.  Does this mean that if I somehow created my own language (service?) I could replace the VB editing experience with my own language?  If so, can you please point me to any resources that would get me started?  The sample app is a good starting point in terms of implemting the two expression interfaces, but I would like to see a primer on a simple language itself.

    3. Related to the above question, my understanding is that with the 2010 release, expressions are restricted to VB.  I don't know if this means the expressions must be VB during expression authoring at design time, at the time validation occurs in the designer, at the time validation occurs at runtime, or at the point where the expression is executed at runtime.   Asked another way, can I completely replace the VB at design time and runtime, or can I only replace it in certain points but, e.g., at the point in time where the worfklow is set to run, it must be a VB expression?

    4. Is the expression editing discussed here restricted to an intellisense like experience?  That is, is it necessarily a code base/typing interaction with a text box where intellisense features guide the user to authoring expressions?  Or would it be possible for me to create a different model, where the user builds an expression from a (context or other) menu of some sort?  (This model provides more guidance/discovability to the end user, than just guessing and typing a few characters).  This ties back to the previous question as well, with the assumption that part or all of the VB pieces can be replaced.

    Thank you,
    Notre
    Tuesday, November 10, 2009 5:47 PM

Answers

  • 1. Adriano is right, these are commands that can be routed as you please in your rehosted UI. However the default VS mappings, and the mechanism for dumping out per-user mappings, are documented on MSDN here: http://msdn.microsoft.com/en-us/library/dd576362(VS.100).aspx (scroll to text editor, though post beta 2 the keyboard shortcuts will be in a Workflow Designer scope not a Text Editor scope). Your custom editor should be destroyed when you lose focus. You won't get a message box in a real implementation. However, you should deal with loss of focus appropriately, and trigger loss of focus on text change if necessary.

    2. We haven't planned a sample for this. It's a lot of work. It is not easy to write your own, but it is possible.

    3. You will get validation errors at design time in the out of the box activities and at runtime if you do not use VB. However, you will probably want to write your own custom activities, because right now there is no way to override the default "Enter a VB expression" hint text in the text block mode (I'll file a bug for that, seems that should be easier). In those custom activities, you can either use untyped arguments or type your arguments as Object (since invalid VB expressions will always evaluate to Object). Then, because you aren't requiring validation in your activity, you should be able to proceed with editing your workflow without the validation icon showing in the designer.

    4. Yes you can use whatever you want for an editor. Keep in mind though that whenever you are not in edit mode you will be flipped to TextBlock and the expression text will be displayed. Also the HintText for the activity will be displayed in the empty TextBlock.

    • Marked as answer by Scott Mason - MSFT Monday, November 16, 2009 10:20 PM
    • Unmarked as answer by Notre Tuesday, November 17, 2009 6:09 PM
    • Marked as answer by Notre Tuesday, December 1, 2009 5:53 PM
    Monday, November 16, 2009 7:51 PM
  • Hi Notre,

    Sorry for the delay in the reply.   I was out of town and did not have internet access.

    #1: You have more or less complete control over the HostControl.  All you have to do in add in the right event handlers and you can call whichever intellisense function you wish to call.  (ie: in the textbox control the KeyDown event can be leveraged)

    #2: Ohboy....  This is a really hard thing to do.  Unfortunately, we don't have any documentation or samples on this.

    The general gist of what you need to do is create your own hosted compiler that will convert your expressions into things that the runtime can understand. 
    2 major difficulties in doing this (that I know of) are handling references properly, and handling L-values and R-values properly.

    Your compiler has to be able to convert an expression such as a + b (where a and b are defined in your workflow as variables/arguments, etc) into a.get(context) + b.get(context).

    L-values need to be converted into CodeActivity<Location<T>> and R-values need to be converted into CodeActivity<T>.

    I'm sorry I'm not really able to give you much more on this as I have not done anything like this myself.


    #4: The sample isn't quite complete in that it doesn't actually call the lost focus event (which will revert the control back into a textblock) or commit the text into the activity.  To do so, you need to raise the LostAggregateFocus event at a logical time and set the Text property of the editor.

    Adding the following code to the sample should solve this issue.

     

     

     

    public System.Windows.Controls.Control HostControl {

    get

    {

    this.textBox.TextChanged += new TextChangedEventHandler(textbox_textchanged);

    this.textBox.LostFocus += new RoutedEventHandler(textbox_lostFocus);

    return textBox;

    }

    }

    public void textbox_textchanged(object sender, EventArgs e)

    {

    this.Text = textBox.Text;

    }

     

     

     

    public void textbox_lostFocus(object sender, EventArgs e)

    {

    LostAggregateFocus(sender, e);

    }


    I hope this helps.

    -Eric

    • Marked as answer by Notre Tuesday, December 1, 2009 5:53 PM
    Monday, November 30, 2009 7:33 PM
  • Hi Notre,

    4#: The behavior of that is because my sample really was a quick hack.  Each time we give focus to the editor, we actually create a new instance of the IExpressionEditorInstance (hence why we pass in the text in the service).  (Note: The place I put the event handlers in my previous reply is actually a really bad place to put them, but due to this behavior, we don't actually get many event handlers added on each gain focus event - Apologies on the poor coding style on my part)

    In the service we should probably have something similar to:

    MyExpressionEditorInstance instance = new MyExpressionEditorInstance();
     instance.Text = text;
    return instance;

    Thanks, Eric
    • Edited by Eriwong - MSFT Tuesday, December 1, 2009 1:59 AM Copying and pasting is causing lots of formatting problems
    • Marked as answer by Notre Tuesday, December 1, 2009 5:53 PM
    Tuesday, December 1, 2009 1:53 AM
  • Hi Eric,

    Thank your for your reply.  I appreciate that you made your sample public, and that you are supporting it through the forums.

    In addition to your code segment, I also had to modify the textbox.Text property, such that it was also reasssigned the text value.

    Thanks,

    Notre
    • Marked as answer by Notre Tuesday, December 1, 2009 5:54 PM
    Tuesday, December 1, 2009 5:53 PM

All replies

  • Hi Notre, based on what I know/understood analyzing it, (and please Matt/Cathy/Eric tell me if I am wrong) :

    1. You should provide on your implementation what methods you support (can*) on your own designer, and the actual call forwarded IF you support that action to you so that you can manage (for instance: CanParameterInfo -> ParameterInfo. Basically you declare your "capabilities", and respond to designer requests on the supported caps.

    2/3. They mean that Intellisense help people not familiar with VB syntax to deal with logic behind it. But based on my knowledge it's not possible to replace, at this time, the VB editing language with other languages. At least, not using public interfaces.

    4. You can "host" your own control through IExpressionEditorInstance, not only a TextBox, for instance I think you can also put a button that opens your own "formula editing" dialog...

    Currently I am thinking about doing both the Intellisense as well as the "expression wizard dialog" (or whatever you like) in order to simplify user experience by providing also formula "templates", and so on...

    Hope it helps,

    Adriano


    Adriano
    Wednesday, November 11, 2009 2:13 PM
  • 1. Adriano is right, these are commands that can be routed as you please in your rehosted UI. However the default VS mappings, and the mechanism for dumping out per-user mappings, are documented on MSDN here: http://msdn.microsoft.com/en-us/library/dd576362(VS.100).aspx (scroll to text editor, though post beta 2 the keyboard shortcuts will be in a Workflow Designer scope not a Text Editor scope). Your custom editor should be destroyed when you lose focus. You won't get a message box in a real implementation. However, you should deal with loss of focus appropriately, and trigger loss of focus on text change if necessary.

    2. We haven't planned a sample for this. It's a lot of work. It is not easy to write your own, but it is possible.

    3. You will get validation errors at design time in the out of the box activities and at runtime if you do not use VB. However, you will probably want to write your own custom activities, because right now there is no way to override the default "Enter a VB expression" hint text in the text block mode (I'll file a bug for that, seems that should be easier). In those custom activities, you can either use untyped arguments or type your arguments as Object (since invalid VB expressions will always evaluate to Object). Then, because you aren't requiring validation in your activity, you should be able to proceed with editing your workflow without the validation icon showing in the designer.

    4. Yes you can use whatever you want for an editor. Keep in mind though that whenever you are not in edit mode you will be flipped to TextBlock and the expression text will be displayed. Also the HintText for the activity will be displayed in the empty TextBlock.

    • Marked as answer by Scott Mason - MSFT Monday, November 16, 2009 10:20 PM
    • Unmarked as answer by Notre Tuesday, November 17, 2009 6:09 PM
    • Marked as answer by Notre Tuesday, December 1, 2009 5:53 PM
    Monday, November 16, 2009 7:51 PM
  • Thanks for your reply Cathy (and Adriano too)!

    Cathy, for #1, you've partially answered my multipart question. (I know, there are many questions here; thanks for taking the time to answer).  Thank you for providing information about the default keyboard mappings.  And thank you for the information that the commands can be routed as pleased. For question #1, I still have some outstanding questions:
    a) Is triggering the various methods restricted to keyboard shortcuts, as currently implemented in the sample application?  By your comment that these are commands (presumably WPF commands), I asssume the answer is 'no'.  Any example of something other than using a keyboard shortcut to invoke any of these methods, would be very much appreciated.
    b) I assume by your answer that the keyboard shortcuts are the same as in the "big" VB editor in Visual Studio.  Is that correct?  If so, is the expression editor's shortcuts also subject to any personalization done in VS?
    c) I understand that I shouldn't get a message box in a real implementation and that I should deal with loss of focus appropriately.  In Eric's sample application, when I leave focus of the edit box I don't get any breakpoints hit and no message box is displayed.  Perhaps naively, I would have expected IExpressionEditorInstance.Close to be called and a message box dispalyed, but I don't see that happening.

    For #2, I understand that the effort in producing a sample of a custom language might be quite a bit.  In lieu of a complete example, could you instead point me to any existing documentation that would get me started?  I understand that Visual Studio provides some facilities for creating custom language services, but I don't imagine that these apply when rehosting the workflow designer outside of visual studio.


    For #3, you have answered my questions re: out of the box activities.  Thank you for filing the bug report.  I will be writing my own custom activities, except for FlowDecision and FlowSwitch, since it's not possible to add my own custom 'flow' activites in a FlowChart workflow (which is what I want to use) :(.

    For #4, thank you for your answer.  I modified Eric's sample to use a Button control rather than a TextBox as the IExpressionEditorInstance.HostControl.  The button control did show up when I clicked in the editor. However, when I left focus of the control, the button did not change back to a TextBlock.  I guess this goes back to my question #1c above.

    Thanks,

    Notre

    Tuesday, November 17, 2009 6:09 PM
  • Hi Cathy and Eric,

    Could you please comment further on the questions above?

    Thank you,

    Notre
    Monday, November 30, 2009 5:17 PM
  • Hi Notre,

    Sorry for the delay in the reply.   I was out of town and did not have internet access.

    #1: You have more or less complete control over the HostControl.  All you have to do in add in the right event handlers and you can call whichever intellisense function you wish to call.  (ie: in the textbox control the KeyDown event can be leveraged)

    #2: Ohboy....  This is a really hard thing to do.  Unfortunately, we don't have any documentation or samples on this.

    The general gist of what you need to do is create your own hosted compiler that will convert your expressions into things that the runtime can understand. 
    2 major difficulties in doing this (that I know of) are handling references properly, and handling L-values and R-values properly.

    Your compiler has to be able to convert an expression such as a + b (where a and b are defined in your workflow as variables/arguments, etc) into a.get(context) + b.get(context).

    L-values need to be converted into CodeActivity<Location<T>> and R-values need to be converted into CodeActivity<T>.

    I'm sorry I'm not really able to give you much more on this as I have not done anything like this myself.


    #4: The sample isn't quite complete in that it doesn't actually call the lost focus event (which will revert the control back into a textblock) or commit the text into the activity.  To do so, you need to raise the LostAggregateFocus event at a logical time and set the Text property of the editor.

    Adding the following code to the sample should solve this issue.

     

     

     

    public System.Windows.Controls.Control HostControl {

    get

    {

    this.textBox.TextChanged += new TextChangedEventHandler(textbox_textchanged);

    this.textBox.LostFocus += new RoutedEventHandler(textbox_lostFocus);

    return textBox;

    }

    }

    public void textbox_textchanged(object sender, EventArgs e)

    {

    this.Text = textBox.Text;

    }

     

     

     

    public void textbox_lostFocus(object sender, EventArgs e)

    {

    LostAggregateFocus(sender, e);

    }


    I hope this helps.

    -Eric

    • Marked as answer by Notre Tuesday, December 1, 2009 5:53 PM
    Monday, November 30, 2009 7:33 PM
  • Hi Eric,

    Thank you very much for the reply!

    Regarding #1, I think I have a feeling for what you mean, based on your answer to my fourth question. I may have more questions on this, but can ask them in a separate question.

    Regarding #2, I didn't expect any samples (because of Cathy's reply) but I am disappointed to find no documentation exists :(  C'est la vie.  In terms of the high level points, you said "create your own hosted compiler that will convert your expressions into things that the runtime can understand".  Some examples of what the runtime can understand are presumably CodeActivity<Location<T>> and CodeActivity<T>.  But, what other examples/guidance can you give in terms of "what the runtime can understand"?  Does my language need to be ultimately translated into VB, so that it can be understood by the workflow runtime?  I know you're not an expert in this area; whatever you can tell me is helpful.

    For #4. the code sample you gave helps.  However, what I find now is that when I edit an expression, leave focus of the control, and then re-enter the control, the text of the control is cleared upon regaining focus.  I put a breakpoint in text_textChanged, but it is not called upon clearing.  I expanded the Text property for the MyExpressionEditorInstance class and defined an explicit member variable and put breakpoints in the getter and setter for the property, but they weren't hit at the time I expected them to be (when the Text property's value is reset to null).  I'm not sure what is wrong, but the net effect is that when I reenter the control for editing, my value is cleared.  (I set breakpoints in other spots and this.Text is set to a non-null value, before re-entering the editor control).

    Thanks,

    Notre
    Tuesday, December 1, 2009 12:26 AM
  • Hi Notre,

    4#: The behavior of that is because my sample really was a quick hack.  Each time we give focus to the editor, we actually create a new instance of the IExpressionEditorInstance (hence why we pass in the text in the service).  (Note: The place I put the event handlers in my previous reply is actually a really bad place to put them, but due to this behavior, we don't actually get many event handlers added on each gain focus event - Apologies on the poor coding style on my part)

    In the service we should probably have something similar to:

    MyExpressionEditorInstance instance = new MyExpressionEditorInstance();
     instance.Text = text;
    return instance;

    Thanks, Eric
    • Edited by Eriwong - MSFT Tuesday, December 1, 2009 1:59 AM Copying and pasting is causing lots of formatting problems
    • Marked as answer by Notre Tuesday, December 1, 2009 5:53 PM
    Tuesday, December 1, 2009 1:53 AM
  • Hi Eric,

    Thank your for your reply.  I appreciate that you made your sample public, and that you are supporting it through the forums.

    In addition to your code segment, I also had to modify the textbox.Text property, such that it was also reasssigned the text value.

    Thanks,

    Notre
    • Marked as answer by Notre Tuesday, December 1, 2009 5:54 PM
    Tuesday, December 1, 2009 5:53 PM
  • In WF 4.5, will Microsoft be providing a mechanism for doing a custom expression language? BTW, my request is not to force it to be a computer language, but to make it a simple expression that does not require instanciation. We have done this in WF 3.0/3.5 with FLEE. This maximized the UX and ease of use for our customers over having to learn a computer language like VB or C#. This becomes rather urgent since MS has decided to mark WF 3.5 classes obsolete. We heavily invested in customizing the WF 3.5 to work for our customers.

    Wednesday, February 22, 2012 1:42 AM
  • Hi Eric,

    Thanks for posting the corrected code here.  I am having a problem that in my Custom Expression Editor when I click for the second time on an already populated field, it wipes it out.  Should I commen tout all together the ClearSelection method?  If not can  you please let me know what I need to do? 

    Thanks in advance.


    TaMa


    • Edited by Artapan Tuesday, October 8, 2013 6:38 PM
    Tuesday, October 8, 2013 5:58 PM