locked
Rehosted WorkflowDesigner.Load(myActivityBuilderInstance) doesn't show errors until something is changed RRS feed

  • Question

  • I'm loading a WorkflowDesigner with an ActivityBuilder using the overload WorkflowDesigner.Load(myActivityBuilderInstance), and in this situation, if the implementation of my ActivityBuilder has errors (for instance only a Assign activity without anything set on it), the errors don't show up in the designer until I do some change in the designer. The same situation occurs if instead of using an ActivityBuilder has the root activity I use any other activity, like a Sequence for example.

    If instead of using the overload described above, I use the overload WorkflowDesigner.Load(fileName) where the fileName is the path to the same file that was used to create the myActivityBuilderInstance mentioned previously, in this case, the errors appear in the designer as soon as the file is loaded (has expected). This expected behavior also occurs if I set the Text Property of the WorkflowDesigner and then use the Load() overload.

    Using .NET Reflector to inspect a little bit what was going on, it seems to me that there's a different behavior in terms of running the validation when using the previously Load(...) overloads. It seems to me that when using the WorkflowDesigner.Load(myActivityBuilderInstance) the ModelItemTree is not being updated to reflect the errors, and that seems to be the reason why the errors don't show up in the designer until something is changed.

    To demonstrate the scenario here's an example:

    var rootActivity = new System.Activities.Statements.Sequence();
    rootActivity.Activities.Add(new System.Activities.Statements.Assign());
    WorkflowDesigner.Load(rootActivity);
    

    This code, loads a Sequence with an Assign activity, but no erros are displayed in the designer, but the Assign and the Sequence activities should both be displaying errors, has the Assign activity has no values for the Arguments "Value" and "To".

    On the other hand, if instead of using the previous code I do:

    WorkflowDesigner.Load(fileName);

    Where the fileName points to a XAML file that has the same activities as described above (Sequence and Assign with no Arguments set), the errors are displayed correctly as soon as the file is loaded.

    I've also tried to call the following code after the WorkflowDesigner.Load(rootActivity) but without success:

    var validationService = new System.Activities.Presentation.Validation.ValidationService(WorkflowDesigner.Context);
    validationService.ValidateWorkflow();

    What can be wrong with the first approach to load an activity to the WorkflowDesigner? Why aren't the erros being displayed as soos as the activity is loaded to the designer?

    Thanks,

    Nelson Morais

    • Edited by Nelson Morais Monday, June 14, 2010 10:28 PM spelling
    • Changed type Nelson Morais Monday, June 14, 2010 10:54 PM Wrong thread type
    Monday, June 14, 2010 6:47 PM

Answers

  • can you try following code? it works on my machine

     

    new DesignerMetadata().Register();
                designer = new WorkflowDesigner();
                Sequence seq = new Sequence();
                seq.Activities.Add(new Assign());
                designer.Load(new ActivityBuilder { Implementation = seq  } );
             
                designer.Context.Services.GetService<ValidationService>().ValidateWorkflow();

                win.Content = designer.View;

    • Marked as answer by Nelson Morais Wednesday, June 16, 2010 9:05 AM
    Wednesday, June 16, 2010 5:54 AM
  • Hello Ye Yu,

    In fact, using...:

    WorkflowDesigner.Context.Services.GetService<ValidationService>().ValidateWorkflow();

    ...WORKS!

    But now I've one question, what is the difference between the previous code (that works) and this one (that doesn't work):

    var validationService = new System.Activities.Presentation.Validation.ValidationService(WorkflowDesigner.Context);
    validationService.ValidateWorkflow();
    

    Thanks,

    Nelson Morais

    • Marked as answer by Nelson Morais Wednesday, June 16, 2010 9:05 AM
    Wednesday, June 16, 2010 9:04 AM

All replies

  • For the moment the best workaround I've came up is this, but it looks "dirty":

          ActivityIdentifier = activityIdentifier;
          WorkflowDesigner.Load(ActivityIdentifier.ActivityBuilder);
    
          // HACK: WorkflowDesigner.Load(ActivityIdentifier.ActivityBuilder) - This Load overload, doesn't execute WF validation, so this hack was required to force it
          var mtmRoot = WorkflowDesigner.Context.Services.GetService<ModelTreeManager>().Root;
          using (var editingScope = mtmRoot.BeginEdit())
          {
            var rootName = mtmRoot.Root.Properties["Name"].ComputedValue;
            mtmRoot.Root.Properties["Name"].SetValue("Dummy to force a change on the ModelItemTree to force Validation to occur");
            mtmRoot.Root.Properties["Name"].SetValue(rootName);
            editingScope.Complete();
          }
    

     

    This really seems to be a failure in the implementantion of this Load(...) overload, so I've reported a Bug at Microsoft Connect. HEre's the link:

    https://connect.microsoft.com/wf/feedback/details/567382/rehosted-workflowdesigner-load-myactivitybuilderinstance-doesnt-show-errors-until-something-is-changed

     

    Monday, June 14, 2010 11:46 PM
  • Nelson,

    Rather than doing this:

     

    var validationService = new System.Activities.Presentation.Validation.ValidationService(WorkflowDesigner.Context);
    validationService.ValidateWorkflow();

     

    retrieve the ValidationService from the Services collection of hte editing context and call ValidateWorkflow on it. 

     

    The Load overload that takes in an instance let's the host determine what it needs to do with the workflow (if you are read only, you may not want to validate). 


    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    Tuesday, June 15, 2010 7:51 PM
  • Hello Matt,

    I've already done that, using this piece of code:

    var rootActivity = new System.Activities.Statements.Sequence();
    rootActivity.Activities.Add(new System.Activities.Statements.Assign());
    WorkflowDesigner.Load(rootActivity);
    var validationResults = System.Activities.Validation.ActivityValidationServices.Validate(rootActivity);
    

    After calling the Validate(rootActivity), I do receive the list of errors, but now how can the WorkflowDesigner be updated to show up this errors? Please note that my problem isn't detecting if the workflow has errors or not, this piece of code gives me that, the problem is making this errors show up in the WorkflowDesigner immediatly after the Load(rootActivity).

    I'm I being clear?

    Thanks,

    Nelson Morais

    Wednesday, June 16, 2010 12:01 AM
  • can you try following code? it works on my machine

     

    new DesignerMetadata().Register();
                designer = new WorkflowDesigner();
                Sequence seq = new Sequence();
                seq.Activities.Add(new Assign());
                designer.Load(new ActivityBuilder { Implementation = seq  } );
             
                designer.Context.Services.GetService<ValidationService>().ValidateWorkflow();

                win.Content = designer.View;

    • Marked as answer by Nelson Morais Wednesday, June 16, 2010 9:05 AM
    Wednesday, June 16, 2010 5:54 AM
  • Hello Ye Yu,

    In fact, using...:

    WorkflowDesigner.Context.Services.GetService<ValidationService>().ValidateWorkflow();

    ...WORKS!

    But now I've one question, what is the difference between the previous code (that works) and this one (that doesn't work):

    var validationService = new System.Activities.Presentation.Validation.ValidationService(WorkflowDesigner.Context);
    validationService.ValidateWorkflow();
    

    Thanks,

    Nelson Morais

    • Marked as answer by Nelson Morais Wednesday, June 16, 2010 9:05 AM
    Wednesday, June 16, 2010 9:04 AM
  • A similar issue exists if using the same load approach as outlined by the OP and using the following call:

     

    ValidationResults results = ActivityValidationServices.Validate(Activity);
    
    The call above returns a ValidationResult which I need. Anyone know of a way to get this to work? The alternatives above return void so will not work for m.
    - jeremiah adams
    Thursday, October 13, 2011 10:42 PM