locked
Change Variable and Argument editor in workflow designer? RRS feed

  • Question

  • Is it possible, in Beta 2, to customize the behaviour of the editing grids use for entering data about a workflow's variables or arguments in the workflow designer?  Can I:

    - add my own custom column to the grid?
    - can I customize the variable type drop down editor? (e.g. have my own editor or otherwise filter the list of types)
    - can I change the "default" expression editor (and possibly remove it)?

    Thanks,

    Notre
    Thursday, November 5, 2009 5:39 PM

Answers

  • - add my own custom column to the grid?
             > No, this type of extensibility is not planned for the vs2010 release
    - can I customize the variable type drop down editor? (e.g. have my own editor or otherwise filter the list of types)
             > No,
    - can I change the "default" expression editor (and possibly remove it)?
             > Yes (I wouldn't go 3 for 3 :) ), you can do this by registering a property editor for the type.  Tim has been working on some of that, so I will ping him to reply to this thread.  The extensibility there is similar to the property grid extensibility, and the API is a bit rougher than we would have liked, but it will enable you to replace the default expression editor in teh variables and arguments designer.




    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Thursday, November 5, 2009 7:00 PM
  • Hi, one of our testers wrote an app that demonstrates the process. See Implementing a Custom Expression Editor on my blog. Some sample code is attached.

    Thanks
    Cathy Dumas

    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Thursday, November 5, 2009 11:13 PM
  • Adriano,

    Thanks for the information about the scenario, it's useful to understand how you want to be able to use the designer.  We definitely want to be able to enable you to build these kind of experiences for your end users. 

    As Cathy mentions, we do have the capability to wholesale replace the expression editor with something more friendly for an end user than typing in code.  What we don't have is the ability to override the whole argument/variable design experience.  If you want to be able to do that, the best path for that is to disable the display of ours and invoke the display of your in your app (maybe the bottom of the designer isn't the best place for your app, maybe you want to have a menu item, a task icon on the left side, etc).  If you want it to display in a similarl place, the best we can do in vs2010 is have you put your buttons right below the designer (you could try to get fancy and overlay the buttons, but I'm not sure how critical it is for your scenario.

    Notre, you asked a couple of questions:

    a) get the information about arguments in scope for a given activity (its own explicitly declared variables and any of those in 'parent' activities)

    There is not a public API that returns this information.  I will followup with a blog post on how we determine what variables are in scope and what you would need to do to figure that out.  Basically we just walk up the tree via the Parent pointer and find out if containing activities have variables and we add those into a collection.


    b) update the set of variables/arguments myself, after having added a new variable/argument in my custom editor?

    Certainly, you can do this directly from your custom editor by binding to the model items that represent the variables or arguments items.  For the case of arguments, you would navigate to the root activity builder and bind your UI to the Properties property of ActivityBuilder's model item.  For variables, you would likely build a colleciton of the variable model items from above and build your UI to edit this.


    Is there any object model exposed that allows me to query/update the arguments and variables for an activity?  If not, could I safely read/write to the XAML directly (or are there issues like caching of variables/argument in memory that might be out of sync with XAML at a given time, or the XAML schema is subject to change in later releases)?

    If you start write to the XAML (or underlying OM) directly, you will get out of sync, and there isn't a good way of flushing the entire designer. The right OM to interact with at design time is the Model Item tree, it will make sure that your view and source stay in sync, will take care of things like Undo/Redo, and in general, will be the best way to manipulate objects at design time.

    I hope this helps,

    matt



    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Thursday, November 5, 2009 11:39 PM
  • One additional bit of information, after looking through a little bit more of the source.  If you choose to implement your own expression text box, the implementation of IExpressionEditorService.CreateExpressionEditor will pass you a list of ModelItems which correspond to the variables, so within your implementation of IExpressionTextBoxService, you will be able to list the variables.

    I'm working on a blog post for how you can compute the same list that would be passed to you here.

    matt


    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Friday, November 6, 2009 12:19 AM
  • Hi Notre,
    To try to answer the outstanding question, you should be able to create your own editor for Arguments or Varibables which updates the variables/arguments by updating the ModelItem tree. There are a couple minor complications for Arguments.

    At Design time, as seen in other threads, ActivityBuilder represents the class definition (<Activity x:Class=...> in xaml). Look at an instance of ActivityBuilder class, and you will notice that its arguments are stored within the collection 'Properties', and the arguments also have a special design time representation, DynamicActivityProperty (which pretty much corresponds to :Members> tag in XAML). For Variables it is slightly easier, but remember that they live on the activities that are part of the workflow, not the ActivityBuilder.

    Example code to add an InArgument to a workflow:

        class Program

        {

            [STAThread]

            static void Main(string[] args)

            {

                WorkflowDesigner wd = new WorkflowDesigner();

                wd.Load(new ActivityBuilder { Implementation = new Sequence() });

                ModelTreeManager mtm = wd.Context.Services.GetService<ModelTreeManager>();

                ModelItem ab = mtm.Root;

                ModelItemCollection argsAndProperties = ab.Properties["Properties"].Collection;

                argsAndProperties.Add(new DynamicActivityProperty

                {

                    Name = "Fred",

                    Type = typeof(InArgument<string>),

                });

                Window w = new Window();

                w.Content = wd.View;

                w.ShowDialog();           

            }

        }


    Tim
    • Marked as answer by Notre Tuesday, November 10, 2009 5:17 PM
    Friday, November 6, 2009 12:37 AM
  • Blog post away!  Notre, the blog post i've written takes you through what you would need to do to find the valid in scope "tokens" that can be referenced by expressions.

    Let me know if that helps,

    thanks,

    matt
    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:17 PM
    Friday, November 6, 2009 6:51 AM
  • >Would I need to use a DynamicActivityProperty for variables as well?

    No, that's just a special case for Arguments or Properties which live on the activity X:Class. Variables are nice and simple, for instance if you have the ModelItem of a Sequence, I believe it's something like this:

    void AddStringVariableToSequence(ModelItem seqModelItem)
    {
        seqModelItem.Properties["Variables"].Collection.Add(new Variable<string>());
    }

    Tim
    • Marked as answer by Notre Tuesday, November 10, 2009 5:17 PM
    Saturday, November 7, 2009 3:38 AM

All replies

  • - add my own custom column to the grid?
             > No, this type of extensibility is not planned for the vs2010 release
    - can I customize the variable type drop down editor? (e.g. have my own editor or otherwise filter the list of types)
             > No,
    - can I change the "default" expression editor (and possibly remove it)?
             > Yes (I wouldn't go 3 for 3 :) ), you can do this by registering a property editor for the type.  Tim has been working on some of that, so I will ping him to reply to this thread.  The extensibility there is similar to the property grid extensibility, and the API is a bit rougher than we would have liked, but it will enable you to replace the default expression editor in teh variables and arguments designer.




    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Thursday, November 5, 2009 7:00 PM
  • Thank you Matt for your reply.  The answer is disappointing from my perspective, but thank you very much for answering.

    My goal is to rehost the designer. My user base is not developers but less technical "business analysts".  While the new workflow designer is much more friendly to this audience than either the sequential or state matchine workflows, there are still a few areas that I feel would be too complicated for this user base. 

    One of these areas is the variables and arguments editor.  The list of argument and variable types would be too overwhelming for these users, so I would like to restrict the set of type to a much smaller set, and in many case expose custom types that make sense to their business domain, rather than more generic .NET types.

    For this same user base, I would like to have my own editor (hiding the VB one, and replacing it with my propreitary editor).  It sounds like there may be some hope on that front.

    In a question I asked in another post, I found that it is possible to hide any or all of the workshell bar buttons.  My hope then is I can add my own workflow shell buttons, which I could use to invoke my own variable or arguments editor (the subject of another post).  Failing that, perhaps I can create a context menu item on the activity designer to edit variables or arguments.  Or, expose this directly (inline editor) in the designer for the activity.  Or make it appear in the property grid for an activity.  (I don't currently know how to do any of these, but will try to figure out this on my own, and post a different question, if I cannot figure something out).

    My outstanding question then (in addition to how to change the default expression editor), is given that I can somehow bring up my own editor, how can I
    a) get the information about arguments in scope for a given activity (its own explicitly declared variables and any of those in 'parent' activities)
    b) update the set of variables/arguments myself, after having added a new variable/argument in my custom editor?

    Is there any object model exposed that allows me to query/update the arguments and variables for an activity?  If not, could I safely read/write to the XAML directly (or are there issues like caching of variables/argument in memory that might be out of sync with XAML at a given time, or the XAML schema is subject to change in later releases)?

    Thank you,
    Notre
    Thursday, November 5, 2009 8:41 PM
  • Thank you Matt for your reply.  The answer is disappointing from my perspective, but thank you very much for answering.

    My goal is to rehost the designer. My user base is not developers but less technical "business analysts".  While the new workflow designer is much more friendly to this audience than either the sequential or state matchine workflows, there are still a few areas that I feel would be too complicated for this user base. 

    One of these areas is the variables and arguments editor.  The list of argument and variable types would be too overwhelming for these users, so I would like to restrict the set of type to a much smaller set, and in many case expose custom types that make sense to their business domain, rather than more generic .NET types.

    For this same user base, I would like to have my own editor (hiding the VB one, and replacing it with my propreitary editor).  It sounds like there may be some hope on that front.

    In a question I asked in another post, I found that it is possible to hide any or all of the workshell bar buttons.  My hope then is I can add my own workflow shell buttons, which I could use to invoke my own variable or arguments editor (the subject of another post).  Failing that, perhaps I can create a context menu item on the activity designer to edit variables or arguments.  Or, expose this directly (inline editor) in the designer for the activity.  Or make it appear in the property grid for an activity.  (I don't currently know how to do any of these, but will try to figure out this on my own, and post a different question, if I cannot figure something out).

    My outstanding question then (in addition to how to change the default expression editor), is given that I can somehow bring up my own editor, how can I
    a) get the information about arguments in scope for a given activity (its own explicitly declared variables and any of those in 'parent' activities)
    b) update the set of variables/arguments myself, after having added a new variable/argument in my custom editor?

    Is there any object model exposed that allows me to query/update the arguments and variables for an activity?  If not, could I safely read/write to the XAML directly (or are there issues like caching of variables/argument in memory that might be out of sync with XAML at a given time, or the XAML schema is subject to change in later releases)?

    Thank you,
    Notre

    HI Matt/Notre,

    I am doing exactly the same kind of rehosting Notre is doing, and I think the same about the current "limitations" are somewhat too much.

    Matt, I think that the current implementation of WF is awesome, however it lacks some important features that could boost its usage/I hope you can shed some light and consider possible quick additions on the current extensibility of the designer to accomodate this kind of customizations at a certain extent, obviously.

    I mean, we really need some sort of interface or service to plug in our implementation when we need to provide some sort of designer targeting a non-developer user. The ability to choose from application-specific types, for instance, is quite a must.

    Notre, I see that we are doing something very similar on doing this kind of rehosting, may be we can share our experiences on doing this stuff(?). Please let me know if you are interesting in sharing some details on the same.

    Thank you all!
    Keep up the great job!
    Cheers
    Adriano
    Thursday, November 5, 2009 9:01 PM
  • Hi, one of our testers wrote an app that demonstrates the process. See Implementing a Custom Expression Editor on my blog. Some sample code is attached.

    Thanks
    Cathy Dumas

    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Thursday, November 5, 2009 11:13 PM
  • Adriano,

    Thanks for the information about the scenario, it's useful to understand how you want to be able to use the designer.  We definitely want to be able to enable you to build these kind of experiences for your end users. 

    As Cathy mentions, we do have the capability to wholesale replace the expression editor with something more friendly for an end user than typing in code.  What we don't have is the ability to override the whole argument/variable design experience.  If you want to be able to do that, the best path for that is to disable the display of ours and invoke the display of your in your app (maybe the bottom of the designer isn't the best place for your app, maybe you want to have a menu item, a task icon on the left side, etc).  If you want it to display in a similarl place, the best we can do in vs2010 is have you put your buttons right below the designer (you could try to get fancy and overlay the buttons, but I'm not sure how critical it is for your scenario.

    Notre, you asked a couple of questions:

    a) get the information about arguments in scope for a given activity (its own explicitly declared variables and any of those in 'parent' activities)

    There is not a public API that returns this information.  I will followup with a blog post on how we determine what variables are in scope and what you would need to do to figure that out.  Basically we just walk up the tree via the Parent pointer and find out if containing activities have variables and we add those into a collection.


    b) update the set of variables/arguments myself, after having added a new variable/argument in my custom editor?

    Certainly, you can do this directly from your custom editor by binding to the model items that represent the variables or arguments items.  For the case of arguments, you would navigate to the root activity builder and bind your UI to the Properties property of ActivityBuilder's model item.  For variables, you would likely build a colleciton of the variable model items from above and build your UI to edit this.


    Is there any object model exposed that allows me to query/update the arguments and variables for an activity?  If not, could I safely read/write to the XAML directly (or are there issues like caching of variables/argument in memory that might be out of sync with XAML at a given time, or the XAML schema is subject to change in later releases)?

    If you start write to the XAML (or underlying OM) directly, you will get out of sync, and there isn't a good way of flushing the entire designer. The right OM to interact with at design time is the Model Item tree, it will make sure that your view and source stay in sync, will take care of things like Undo/Redo, and in general, will be the best way to manipulate objects at design time.

    I hope this helps,

    matt



    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Thursday, November 5, 2009 11:39 PM
  • One additional bit of information, after looking through a little bit more of the source.  If you choose to implement your own expression text box, the implementation of IExpressionEditorService.CreateExpressionEditor will pass you a list of ModelItems which correspond to the variables, so within your implementation of IExpressionTextBoxService, you will be able to list the variables.

    I'm working on a blog post for how you can compute the same list that would be passed to you here.

    matt


    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:16 PM
    Friday, November 6, 2009 12:19 AM
  • Hi Notre,
    To try to answer the outstanding question, you should be able to create your own editor for Arguments or Varibables which updates the variables/arguments by updating the ModelItem tree. There are a couple minor complications for Arguments.

    At Design time, as seen in other threads, ActivityBuilder represents the class definition (<Activity x:Class=...> in xaml). Look at an instance of ActivityBuilder class, and you will notice that its arguments are stored within the collection 'Properties', and the arguments also have a special design time representation, DynamicActivityProperty (which pretty much corresponds to :Members> tag in XAML). For Variables it is slightly easier, but remember that they live on the activities that are part of the workflow, not the ActivityBuilder.

    Example code to add an InArgument to a workflow:

        class Program

        {

            [STAThread]

            static void Main(string[] args)

            {

                WorkflowDesigner wd = new WorkflowDesigner();

                wd.Load(new ActivityBuilder { Implementation = new Sequence() });

                ModelTreeManager mtm = wd.Context.Services.GetService<ModelTreeManager>();

                ModelItem ab = mtm.Root;

                ModelItemCollection argsAndProperties = ab.Properties["Properties"].Collection;

                argsAndProperties.Add(new DynamicActivityProperty

                {

                    Name = "Fred",

                    Type = typeof(InArgument<string>),

                });

                Window w = new Window();

                w.Content = wd.View;

                w.ShowDialog();           

            }

        }


    Tim
    • Marked as answer by Notre Tuesday, November 10, 2009 5:17 PM
    Friday, November 6, 2009 12:37 AM
  • Thank you Tim, Matt, and Cathy.  I have a lot of information to absorb (I also look forward to Matt's blog post) and it will likely take me a number of days to go through all the tips you have provided.   I will post back later, if I have any questions (or will mark the answers as complete).

    Thank you,
    Notre
    Friday, November 6, 2009 1:19 AM
  • Blog post away!  Notre, the blog post i've written takes you through what you would need to do to find the valid in scope "tokens" that can be referenced by expressions.

    Let me know if that helps,

    thanks,

    matt
    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Tuesday, November 10, 2009 5:17 PM
    Friday, November 6, 2009 6:51 AM
  • Thanks Matt!  The blog post was extremely helpful.  I had to go back to your previous blog post re: deep dive of model items and model properties to get this fully working.  Part of this is because of my relative lack of knowledge of WPF, so I had some trouble figuring out how to the data binding to the ListBox, so instead I used the ModelItem.GetCurrentValue() method to get what I needed in a more code oriented way (rather than using the XAML).

    I had a little bit of trouble getting the variables out of the model item tree when I:

    1) added my variables to the "root" activity added to the ActivityBuilder, in my case a FlowChart activity and
    2) had the "root" flowchart activity selected in the designer

    I had to modify the sample code a little bit to get the variables in this case:

                    while (mi.Parent != null)
                    {
                        Type parentType = mi.Parent.ItemType;
                        if (typeof(Activity).IsAssignableFrom(parentType))
                        {
                            // we have encountered an activity derived type
                            // look for variable collection
                            ModelProperty mp = mi.Parent.Properties["Variables"];
                            if (null != mp && mp.PropertyType == typeof(Collection<Variable>))
                            {
                                mp.Collection.ToList().ForEach(item => variables.Add(item));
                            }
                        }
                        else if (typeof(ActivityBuilder).IsAssignableFrom(mi.Parent.ItemType))
                        {
                            ModelProperty mp = mi.Properties["Variables"];
                            if (null != mp && mp.PropertyType == typeof(Collection<Variable>))
                            {
                                mp.Collection.ToList().ForEach(item => variables.Add(item));
                            }
                        }
    
                        //Other code goes here, as per original post
    
                        mi = mi.Parent;
                    }
    I added the else clause above, where I check if the parent model item is an ActivityBuilder.  I'm not sure if this is strictly speaking necessary, or if I have my own bugs as I haven't tested this thoroughly yet.

    Thanks again Matt.  I need to go back and read all your blog posts (when I get time), as I've found the few I've read so far to be invaluable.

    Notre
    Saturday, November 7, 2009 1:30 AM
  • Hi Tim,

    Your code sample worked flawlessly for arguments.  I haven't tried dynamically adding a variable yet.  Would I need to use a DynamicActivityProperty for variables as well?

    Thanks,

    Notre
    Saturday, November 7, 2009 1:33 AM
  • >Would I need to use a DynamicActivityProperty for variables as well?

    No, that's just a special case for Arguments or Properties which live on the activity X:Class. Variables are nice and simple, for instance if you have the ModelItem of a Sequence, I believe it's something like this:

    void AddStringVariableToSequence(ModelItem seqModelItem)
    {
        seqModelItem.Properties["Variables"].Collection.Add(new Variable<string>());
    }

    Tim
    • Marked as answer by Notre Tuesday, November 10, 2009 5:17 PM
    Saturday, November 7, 2009 3:38 AM
  • Thanks Tim, works perfectly.  Now I need to look at Cathy's post re: custom expression editor then I can finally mark this thread as answered.

    Notre
    Monday, November 9, 2009 11:19 PM
  • I have a number of questions regarding implementing a custom expression editor, so rather than continuing with this long thread, I post a new question.

    Thanks,

    Notre
    Tuesday, November 10, 2009 5:16 PM
  • Thank you Matt for the answer! It definitely helps.

    Adriano


    Adriano
    Wednesday, November 11, 2009 8:00 AM
  • Look here for an example with intellisense:

    http://social.msdn.microsoft.com/Forums/en-US/wfprerelease/thread/07f89fc0-81ff-4e85-a974-013b15b62f50
    Friday, September 3, 2010 10:40 PM
  •  

    I have flowchart as implementation  of activitybuilder and added two dynamicactivityproperty to it. The flowchart is having flowdecision and 3 other customized activities with same defined arguments. But when i invoke the workflow and pass dictionary, it gives the error:

    The values provided for the root activity's arguments did not satisfy the root activity's requirements:
    'Sample Workflow': The following keys from the input dictionary do not map to arguments and must be removed: FolderName, FolderSize.  Please note that argument names are case sensitive.
    Parameter name: rootArgumentValues

    Flowchart

     

     

    fc = new Flowchart();

     

     

    protected override void OnInitialized(EventArgs e)

    { wd.Load(new ActivityBuilder { Implementation =  fc});

                ModelTreeManager mtm = wd.Context.Services.GetService<ModelTreeManager>();

                ModelItem ab = mtm.Root;

                ModelItemCollection argsAndProperties = ab.Properties["Properties"].Collection;           

    argsAndProperties.Add(

     

    new DynamicActivityProperty

    {Name = "FolderName",

    Type =

     

    typeof(InArgument<string>),

    });

    argsAndProperties.Add(

     

    new DynamicActivityProperty

    {

    Name =

     

    "FolderSize",

    Type =

     

    typeof(InArgument<double>),

    });

    }

    My invoke method:

     

     

    Dictionary<string, object> Para = new Dictionary<string, object>();

    Para.Add(

     

    "FolderName", "Workflow");

    Para.Add(

     

    "FolderSize", 100);

    WorkflowInvoker

     

     

    .Invoke(fc, Para);

    Guide me through my mistake.

    Thanks in advance.

    Monday, September 6, 2010 2:23 AM
  • Hi,

    You should post your question as a new question in the forum, rather than adding to an existing question (particularly one that has already been marked as answered).  You will get much better feedback and visibility by doing so.  The only reason I saw your question was because I get notifications of changes to the forum question I started; most people (including MS) won't even notice your question.

    Notre

    Wednesday, September 8, 2010 4:10 PM
  • - add my own custom column to the grid?
             > No, this type of extensibility is not planned for the vs2010 release
    - can I customize the variable type drop down editor? (e.g. have my own editor or otherwise filter the list of types)
             > No,
    - can I change the "default" expression editor (and possibly remove it)?
             > Yes (I wouldn't go 3 for 3 :) ), you can do this by registering a property editor for the type.  Tim has been working on some of that, so I will ping him to reply to this thread.  The extensibility there is similar to the property grid extensibility, and the API is a bit rougher than we would have liked, but it will enable you to replace the default expression editor in teh variables and rguments designer.




    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle

    Thanks for your instruction! Nice writing, It is exactly what I need.
    Thursday, September 16, 2010 2:01 PM