Would like to create a combobox property editor for a custom ativity

Answered Would like to create a combobox property editor for a custom ativity

  • Friday, December 17, 2010 2:46 PM
     
      Has Code

    I have tried searching all over for this solution and came across this thread which is close.

    http://social.msdn.microsoft.com/Forums/en/wfprerelease/thread/a5b6982f-c7f2-49b3-a183-ddb0eb3075cc

    However I do not want to put all of my properties on the custom activity since I will have about 8-10 of them that the person designing the workflow will be able to set and that will take up to much space on the workflow canvas.  The solution above provided a good solution that allows the combo box to be used to set a value directly in the activity.  Also I am rehosting the workflow designer so that our customers can build their workflows.  I have followed the pattern of using WPF that is shown in many posts out there where the property editor grid is on the right hand side. 

    I would like to modify the property editors behavior to not use the expression editor and instead use a custom combobox to allow the user to pick from a list.   I have the followoing code in my activity with a seperate class that holds the custom property editor.   This is giving me the combo box in the property grid editor however I have no idea on how to populate the drop down with values.  

    Here is the class for the custom editor:

      class DropDownEditor : PropertyValueEditor
      {
        public DropDownEditor()
        {
          this.InlineEditorTemplate = new DataTemplate();
          FrameworkElementFactory stack = new FrameworkElementFactory(typeof(StackPanel));
          FrameworkElementFactory dropDown = new FrameworkElementFactory(typeof(ComboBox));
          Binding dropDownBinding = new Binding("Value");
          dropDownBinding.Mode = BindingMode.TwoWay;
    
          stack.AppendChild(dropDown);
    
          this.InlineEditorTemplate.VisualTree = stack;
        }
    
      }

    And here is the code for my custom activity:

      public sealed class WorkflowQueue : NativeActivity
      {
        // Define an activity input argument of type string
        public string SelectedForm { get; set; }
        public string SelectedQueue { get; set; }
    
        static WorkflowQueue()
        {
          //this section registers each field that needs to have a specific type of property editor. Like a drop down.
          AttributeTableBuilder builder = new AttributeTableBuilder();
          builder.AddCustomAttributes(typeof(WorkflowQueue), "SelectedForm", new EditorAttribute(typeof(DropDownEditor), typeof(PropertyValueEditor)));
          builder.AddCustomAttributes(typeof(WorkflowQueue), "SelectedQueue", new EditorAttribute(typeof(DropDownEditor), typeof(PropertyValueEditor)));
          MetadataStore.AddAttributeTable(builder.CreateTable());
        }
    
        // If your activity returns a value, derive from CodeActivity<TResult>
        // and return the value from the Execute method.
        protected override void Execute(NativeActivityContext context)
        {
          // Obtain the runtime value of the Text input argument
        }
      }

    You can see that there is a SelectedFormProperty and a SelectedQueue property.  When I run my hosted designer and drop this custom activity onto the form I see the 2 input properties in the property editing grid as drop downs, just with no values.   So I am trying to figure out how to populate each of those with a list of options I will retrieve from the database.  Also I am hoping to be able to reuse the custom editor for all properties that need a combobox as the editing choice.

    Any direction would be greatly appreciated.


    Thank you, Wade

All Replies

  • Monday, December 20, 2010 3:10 AM
     
     Answered Has Code

    Hi Wade,

    One way is to define the template in XAML like below:

    <DataTemplate x:Key="dropDownEditorTemplate">
      <ComboBox SelectedItem="{Binding Path=Value, Mode=TwoWay}">
        <ComboBox.Items>
        <s:String>Item1</s:String>
        <s:String>Item2</s:String>
        </ComboBox.Items>
      </ComboBox>
    </DataTemplate>
    

    and then assign this.InlineEditorTemplate to this DataTemplate in your DropDownEditor.

    Thanks,
    Tony 

    • Proposed As Answer by Tony Tang Tuesday, December 21, 2010 1:53 AM
    • Marked As Answer by Andrew_ZhuModerator Monday, December 27, 2010 2:51 AM
    •  
  • Thursday, August 23, 2012 3:39 PM
     
     
    How would you bind a custom datasource (DataTable) to this combo?

    PaulM

  • Friday, August 24, 2012 10:03 AM
     
      Has Code
    How would you bind a custom datasource (DataTable) to this combo?

    PaulM

    Found a solution, if anyone is interested.

    public DropDownEditor() { try { this.InlineEditorTemplate = new DataTemplate(); FrameworkElementFactory combo = new FrameworkElementFactory(typeof(ComboBox)); Binding b = new Binding("Value"); b.Mode = BindingMode.TwoWay; b.Converter = new StateConverter(); combo.SetValue(ComboBox.SelectedValueProperty, b); Binding items = new Binding("options"); items.Source = this; combo.SetValue(ComboBox.ItemsSourceProperty, items); combo.SetValue(ComboBox.SelectedValuePathProperty, "ID"); DataTemplate itemTemplate = new DataTemplate(); FrameworkElementFactory textBlock = new FrameworkElementFactory(typeof(TextBlock)); Binding text = new Binding(); text.Converter = new DataTableConverter(); textBlock.SetValue(TextBlock.TextProperty, text); itemTemplate.VisualTree = textBlock; combo.SetValue(ComboBox.ItemTemplateProperty, itemTemplate); this.InlineEditorTemplate.VisualTree = combo; } public DataTable options { get { DataTable lst = new DataTable(); lst.Columns.Add("ID", typeof(string)); lst.Columns.Add("TEXT", typeof(string)); lst.Rows.Add(...) ... } }

    public class StateConverter : IValueConverter
        {
            public StateConverter()
            {
                ;
            }
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
    
                if (value != null)
                {
                    Activity<string> expression = (value as InArgument<string>).Expression;
                    VisualBasicValue<string> vbexpression = expression as VisualBasicValue<string>;
                    Literal<string> literal = expression as Literal<string>;
                    if (literal != null) { return literal.Value.ToString(); }
                    else if (vbexpression != null) { return vbexpression.ExpressionText; }
                }
                return null;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value == null) return null;
                InArgument<string> inArgument = value.ToString();
                // Convert combo box value to InArgument<string>
                return inArgument;
            }
        }
    
       public class DataTableConverter : IValueConverter
        {
            #region IValueConverter Members
    
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value != null && (value as System.Data.DataRowView) != null)
                {
                    return (value as System.Data.DataRowView).Row["TEXT"].ToString();
                }
                return null;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
    
            #endregion
        }



    PaulM


    • Edited by MPaul Friday, August 24, 2012 10:05 AM
    •