none
WF Activity Designer OnModelItemChanged only fires once?

    Pertanyaan

  • I have a workflow activity and designer that is going to be run in a rehosted application.

    In the ActivityDesigner, I'm trying to bind a textblock (a static resource) to a string that is dependent on children of the ModelItem.  The goal will be to use a RichTextBox to provide color hints and the like, but for the purpose of this question I've simplified it to just a string and a textblock.

    The problem I'm having is that OnModelItemChanged only fires when the designer changes root or something that forces the entire ActivityDesigner to reload.  It does not fire when the underlying ModelItem gets new Rows for example.  as a result the TextBlock does not appear to update except in these 'rare' situations.

    Is there another event i can hook into for this? or a better standard for implementing this type of behavior?

    I tried publishing a service and subscribing to it in OnModelItemChanged as well but it had the same effect where it was subscribed and processed only that 1 time.

    Activity Code:

    namespace DefaultActivities
    {
        public enum LogicalExpressionOP
        {
            AND,
            OR,
            NOT,
            XOR,
            AND_NOT
        }
        public class LogicalExpressionRow
        {
            #region Enums
     
            #endregion
     
            #region properties
     
            public LogicalExpressionRow()
            {
                LeftParen = false;
                RightParen = false;
            }
     
            public LogicalExpressionOP? Op
            {
                get;
                set;
            }
            public bool LeftParen { getset; }
     
            
            public BoolActivity Activity {get;set;}
     
            public bool RightParen { getset; }
            #endregion
        }
     
        public class LogicalExpression : BoolActivity
        {      
            public List<LogicalExpressionRow> Rows { getset; }
     
            public LogicalExpression()
            {
                Rows = new List<LogicalExpressionRow>();
            }
            protected override void Execute(System.Activities.NativeActivityContext context)
            {
                //TODO: Implement this.
            }
                   
            protected override void CacheMetadata(System.Activities.NativeActivityMetadata metadata)
            {
                
                Collection<Activity> activities = new Collection<Activity>();
                foreach (var row in Rows)
                    activities.Add(row.Activity);
                    
                metadata.SetImplementationChildrenCollection(activities);
                ValidateLogicalExpression(metadata);
                base.CacheMetadata(metadata);
     
            }
     
            private void ValidateLogicalExpression(System.Activities.NativeActivityMetadata metadata)
            {
                if (Rows == null || Rows.Count == 0)
                    metadata.AddValidationError("Must Set LogicalExpression rows.");
            }
        }
    }

    Designer Code:

    namespace DefaultActivities.Designer
    {
            
        public partial class LogicalExpressionDesigner
        {
            private int InsertIndex = -1;
            
            public LogicalExpressionDesigner()
            {
                InitializeComponent();
     
            }
           
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                DataGrid grid = (DataGrid)this.Resources["datagrid"];
                ModelItemCollection collection = ((ModelItemCollection)grid.ItemsSource);
                int SelectedIndex = grid.SelectedIndex;
                collection.Insert(InsertIndex, new LogicalExpressionRow());           
            }
     
            protected override void OnModelItemChanged(object newItem)
            {
                ((TextBlock)this.Resources["Expression"]).Text = GetDescription((List<LogicalExpressionRow>)this.ModelItem.Properties["Rows"].ComputedValue);            
            }
     
            private string GetDescription(List<LogicalExpressionRow> Rows)
            {
                //TODO: Add markup logic
                if (Rows == null)
                    return "no rows set";
                int i = 0;
                StringBuilder sb = new StringBuilder();
                foreach (var Row in Rows)
                {
                    if (Row.Op != null)
                    {
                        switch (Row.Op)
                        {
                            case LogicalExpressionOP.AND:
                                sb.Append(" AND ");
                                break;
                            case LogicalExpressionOP.AND_NOT:
                                sb.Append(" AND NOT ");
                                break;
                            case LogicalExpressionOP.NOT:
                                sb.Append(" NOT ");
                                break;
                            case LogicalExpressionOP.OR:
                                sb.Append(" OR ");
                                break;
                            case LogicalExpressionOP.XOR:
                                sb.Append(" XOR ");
                                break;
                        }
                    }
                    if (Row.LeftParen)
                        sb.Append("(");
                    if (Row.Activity != null)
                    {
                        sb.Append(string.Format("{0}", Row.Activity.DisplayName));
                        i++;
                    }
                    if (Row.RightParen)
                        sb.Append(")");
                }
                return sb.ToString();
            }
         
            private void datagrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
            {
                DataGrid grid = (DataGrid)sender;
                if (e.AddedCells.Count > 0)
                {
                    DataGridCellInfo cell = (DataGridCellInfo)e.AddedCells[0];
                    int i = 1;
                    foreach (var Row in grid.Items)
                    {
                        
                        if (Row == cell.Item)
                        {
                            this.InsertIndex = i;
                            break;
                        }
                        i++;
                    }
                }
                else
                {
                    this.InsertIndex = -1;
                }
            }
     
            public static void RegisterMetadata(AttributeTableBuilder builder)
            {
                builder.AddCustomAttributes(
                    typeof(LogicalExpression),
                    new DesignerAttribute(typeof(LogicalExpressionDesigner)),
                    new DescriptionAttribute("My sample activity"),
                    new ToolboxBitmapAttribute(typeof(LogicalExpression), "QuestionMark.png"));
     
            }
        }
    }


    kent

    02 Mei 2012 14:22

Jawaban

  • Hi,

    ->the problem I'm having is that OnModelItemChanged only fires when the designer changes root or something that forces the entire ActivityDesigner to reload.  It does not fire when the underlying ModelItem gets new Rows for example.  as a result the TextBlock does not appear to update except in these 'rare' situations.

    It is an expected issue. Is there any event on the specified ModelItem(gets new rows) you can subscribe to?

    • Ditandai sebagai Jawaban oleh Kent Simon 03 Mei 2012 15:29
    03 Mei 2012 2:45

Semua Balasan

  • Hi,

    ->the problem I'm having is that OnModelItemChanged only fires when the designer changes root or something that forces the entire ActivityDesigner to reload.  It does not fire when the underlying ModelItem gets new Rows for example.  as a result the TextBlock does not appear to update except in these 'rare' situations.

    It is an expected issue. Is there any event on the specified ModelItem(gets new rows) you can subscribe to?

    • Ditandai sebagai Jawaban oleh Kent Simon 03 Mei 2012 15:29
    03 Mei 2012 2:45
  • that seemed to do it;

            protected override void OnModelItemChanged(object newItem)
            {
     
                ModelService serv = this.Context.Services.GetService<ModelService>();
                serv.ModelChanged += new EventHandler<ModelChangedEventArgs>(serv_ModelChanged);
                this.Expression = GetDescription((List<LogicalExpressionRow>)this.ModelItem.Properties["Rows"].ComputedValue);
            }

    I had to put quite a bit of logic into my method to handle the event args in an efficient way ( you need to check that the properties changed / items added / removed are in fact children of the service you subscribe to, for example.

    It feels a little dirty, but this did the trick.


    kent

    03 Mei 2012 15:31