locked
Detecting changes to 'Cases' property of FlowSwitch RRS feed

  • Question

  • Hi,

    I have the same question as this previous user.  I thought I understood the answer, but I'm not getting my event handler called when I add more connections from the FlowSwitch.  Here's my code, in model changed, where I hook up my event handlers:

    else if (mi.ItemType == typeof(FlowSwitch<int>))
                        {
                            mi.PropertyChanged += new PropertyChangedEventHandler(FlowSwitch_PropertyChanged);
                            (mi.Properties["Cases"].Value as ModelItemDictionary).CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(FlowSwitchCase_CollectionChanged);
                        }

    and here are my handlers:

           void FlowSwitchCase_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
               
            }

            void FlowSwitch_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (e.PropertyName == "Default")
                {
                }
            }

    What am I doing wrong?

    Thanks,

    Notre

    Tuesday, May 18, 2010 11:08 PM

Answers

  • this should work for you

     

    the problem is in flowchartDesigner, it has some added logic.

    it's not added to ModelItemDictionary directly, instead it operates on the ItemsCollection.

    so you need to monitor that property.

     void Program_ModelChanged(object sender, ModelChangedEventArgs e)
            {
                if (e.ItemsAdded != null)
                {
                    foreach (ModelItem mi in e.ItemsAdded)
                    {

                        if (mi.ItemType == typeof(FlowSwitch<int>))
                        {
                            mi.Properties["Cases"].Value.Properties["ItemsCollection"].Collection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Dictionary_CollectionChanged);
                        }
                    }
                }
            } 

    • Proposed as answer by Ye Yu - MSFT Thursday, May 20, 2010 9:59 PM
    • Marked as answer by Notre Thursday, May 20, 2010 11:18 PM
    Thursday, May 20, 2010 9:59 PM

All replies

  • can you paste me your whole sample code about how you launch the rehost designer and how you bind the event?
    Wednesday, May 19, 2010 6:59 AM
  • My whole code is a lot longer.  What I'm pasting below is the relevant pieces, based on the .xaml.cs file.  My main code is based on the WF sample rehosting project, where a WPF app rehosts the WF designer.  In my full app, the Toolbox is mostly defined in the .xaml portion.   In the code section below, ToolboxControl is the name of the toolbox control defined in my XAML.  Please let me know if you need anything else.

     

     WorkflowDesigner _wd;

            private void Window_Loaded(object sender, RoutedEventArgs e)       
            {
                (new DesignerMetadata()).Register();           
                _wd = new WorkflowDesigner();

                ActivityBuilder ab = new ActivityBuilder();
                ab.Name = "Workflow";
                ab.Implementation = new Flowchart();
                _wd.Load(ab);


                ModelService modelService = _wd.Context.Services.GetRequiredService<ModelService>();
                modelService.ModelChanged += new EventHandler<ModelChangedEventArgs>(modelService_ModelChanged);


                DesignerBorder.Child = _wd.View;
                PropertyBorder.Child = _wd.PropertyInspectorView;

                ToolboxControl.Categories[0].Add(new ToolboxItemWrapper(typeof(FlowSwitch<int>)));
            }


            private void modelService_ModelChanged(object sender, ModelChangedEventArgs e)
            {

                if (e.ItemsAdded != null)
                {
                    foreach (ModelItem mi in e.ItemsAdded)
                    {
                        if (mi.ItemType == typeof(FlowSwitch<int>))
                        {
                            mi.PropertyChanged += new PropertyChangedEventHandler(FlowSwitch_PropertyChanged);
                            (mi.Properties["Cases"].Value as ModelItemDictionary).CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(FlowSwitchCase_CollectionChanged);
                            (mi.Properties["Cases"].Value as ModelItemDictionary).PropertyChanged += new PropertyChangedEventHandler(FlowSwitchCase_PropertyChanged);
                        }
                    }
                }

            }

            void FlowSwitchCase_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
              //This is never called  
            }

            void FlowSwitchCase_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
       //This is never called
            }

            void FlowSwitch_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (e.PropertyName == "Default")
                {
      //This is called
                    object value = (sender as ModelItem).Properties["Default"].ComputedValue;
                }
            }

    Wednesday, May 19, 2010 4:37 PM
  • can you have a try on following code? the collection change handler should be get called.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Activities.Statements;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation;
    using System.Activities.Presentation.Services;
    using System.ComponentModel;

    namespace ConsoleApplication8
    {
        public class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                WorkflowDesigner designer = new WorkflowDesigner();
                Flowchart flowchart = new Flowchart();
               
                designer.Load(flowchart);
                designer.Context.Services.GetService<ModelService>().ModelChanged += new EventHandler<ModelChangedEventArgs>(Program_ModelChanged);
                FlowSwitch<int> flowswitch = new FlowSwitch<int>();
                designer.Context.Services.GetService<ModelService>().Root.Properties["Nodes"].Collection.Add(flowswitch);
                ModelItem flowSwitch = designer.Context.Services.GetService<ModelService>().Root.Properties["Nodes"].Collection[0];
                FlowStep step = new FlowStep();
                step.Action = new Assign();
                flowSwitch.Properties["Cases"].Dictionary.Add(1, step);
            }

            static void Program_ModelChanged(object sender, ModelChangedEventArgs e)
            {
                if (e.ItemsAdded != null)
                {
                    foreach (ModelItem mi in e.ItemsAdded)
                    {
                        if (mi.ItemType == typeof(FlowSwitch<int>))
                        {
                            (mi.Properties["Cases"].Value as ModelItemDictionary).CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Dictionary_CollectionChanged);
                        }
                    }
                }
            }

            static void Dictionary_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                //throw new NotImplementedException();
            }
        
        }
    }

    Thursday, May 20, 2010 5:58 PM
  • Hi Ye,

    Your sample works.  Your code is basically the same as my own, except mine visually rehosts the workflow designer and doesn't explicitly call 'flowSwitch.Properties["Cases"].Dictionary.Add(1, step);' instead, I try to trigger that from the UI.
    '

    Maybe that is my problem - what user action should cause the Cases property to be updated?  I was under the assumption that when I added new links from my Switch to other activities (flow steps) in the UI or else when the user changes the Case property on one of the FlowSwitch links, then Cases property would be updated, and the collection changed event would fire.  Is this not the case?

    Thanks,

    Notre

    Thursday, May 20, 2010 6:33 PM
  • To add to the above question, I took the code sample you provided and threw it into a sample where the workflow designer is visually rehosted.  I also added this statement:

    designer.Context.Services.GetService<ModelService>().Root.Properties["Nodes"].Collection.Add(step);

    just before

    flowSwitch.Properties["Cases"].Dictionary.Add(1, step);

    or an exception would result when the designer was loaded.  The result was that the explicit call to Add a step to the Cases dictionary did trigger a breakpoint on the collection changed handler, as the window was getting ready to display.  And when the window displayed I had two items - a FlowSwitch that had a link (with a case of 1) to an Assign wrapped in a FlowStep. 

    However, if in the designer, I add a new activity to the design surface and try to link up a connection from the FlowSwitch to the new activity or change the Case property of a FlowSwith link in the designer, then the breakpoint on the collection changed handler is not hit.

    Thursday, May 20, 2010 7:02 PM
  • let me take a look at how the connector works of flowdecision.

    I try to give you the answer today.

    Thursday, May 20, 2010 8:19 PM
  • Thanks, that all I can ask :)
    Thursday, May 20, 2010 8:29 PM
  • this should work for you

     

    the problem is in flowchartDesigner, it has some added logic.

    it's not added to ModelItemDictionary directly, instead it operates on the ItemsCollection.

    so you need to monitor that property.

     void Program_ModelChanged(object sender, ModelChangedEventArgs e)
            {
                if (e.ItemsAdded != null)
                {
                    foreach (ModelItem mi in e.ItemsAdded)
                    {

                        if (mi.ItemType == typeof(FlowSwitch<int>))
                        {
                            mi.Properties["Cases"].Value.Properties["ItemsCollection"].Collection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Dictionary_CollectionChanged);
                        }
                    }
                }
            } 

    • Proposed as answer by Ye Yu - MSFT Thursday, May 20, 2010 9:59 PM
    • Marked as answer by Notre Thursday, May 20, 2010 11:18 PM
    Thursday, May 20, 2010 9:59 PM
  • Great! Thanks for the help.

    Notre

    Thursday, May 20, 2010 11:19 PM