简体   繁体   中英

UITypeEditor in Windows Workflow Designer 4.5 (Browse for folder)

I'm trying to implement a Browse for folder in a WF 4.5 Workflow Activity but the ellipses button does not get displayed and pretty much nothing happens.

This is my UITypeEditor class:

public class BrowseForFolderEditor : UITypeEditor
{
    public override object EditValue(ITypeDescriptorContext context, 
         IServiceProvider provider, object value)
    {
        string folderName = string.Empty;
        BrowseForFolderAttribute browseForFolderAttribute = null;

        if (value is string)
        {
            if (context?.PropertyDescriptor != null)
            {
                browseForFolderAttribute =
                    (BrowseForFolderAttribute)
                context.PropertyDescriptor.Attributes[typeof(BrowseForFolderAttribute)];
            }

            var browse = new FolderBrowserDialogEx
            {
                Description = browseForFolderAttribute?.Description,
                ShowNewFolderButton = true,
                ShowEditBox = true,
                SelectedPath = folderName,
                ShowFullPathInEditBox = false,
                RootFolder = Environment.SpecialFolder.MyComputer
            };

            var result = browse.ShowDialog();

            if (result == DialogResult.OK)
                folderName = browse.SelectedPath;

            return folderName;
        }

        // Return whatever value if it wasn't a string - Should never occur!
        return value;
    }

    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.Modal; //base.GetEditStyle(context);
    }

    public class BrowseForFolderAttribute : Attribute
    {
        public BrowseForFolderAttribute(string description)
        {
            this.Description = description;
        }

        public string Description { get; set; }
    }
}

And this is how I declare the code in my Activity :

    [Description("Select the folder where the files will be 
     copied/moved to.")]
    [Category("Folders")]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [BrowseForFolderEditor.BrowseForFolder("Select the folder where the files will be 
     copied/moved to.")]
    [Editor(typeof(BrowseForFolderEditor), typeof(UITypeEditor))]
    public string TargetPath { get; set; }

I don't know if it makes any difference but my workflow Activity is of type NativeActivity .

The property shows up in the property grid, but it just shows up as a textbox with no ellipses button.

Any help would be appreciated.

UPDATE-1:

The problem doesn't have anything to do with the fact that it is a NativeCodeActivity as I've just changed my code to CodeActivity and it made no difference.

I figured it out by looking at some samples provided by Microsoft ie Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4

Anyway, based on this info, I managed to display the ellipses button ('...'), a Textbox and a tooltip in the event where the textbox is too short to display the path. It's not perfect just yet as I'm looking how I can add additional attributes to set other properties of the 'BrowseForFolder' dialog, but I thought I'd share my findings.

My Editor is defined as follows:

public class BrowseForFolderEditor : DialogPropertyValueEditor
{
    public BrowseForFolderEditor()
    {
        // Create a textbox, a '...' button and a tooltip.
        string template = @"
            <DataTemplate
                xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                xmlns:pe='clr-namespace:System.Activities.Presentation.PropertyEditing;assembly=System.Activities.Presentation'>
                <DockPanel LastChildFill='True'>
                    <pe:EditModeSwitchButton TargetEditMode='Dialog' Name='EditButton' DockPanel.Dock='Right'>...</pe:EditModeSwitchButton>
                    <TextBlock Text='{Binding Value}' Margin='2,0,0,0' VerticalAlignment='Center'>
                        <TextBox.ToolTip>
                            <ToolTip>
                                <TextBlock Text='{Binding Value}' Margin='2' VerticalAlignment='Center' HorizontalAlignment='Left'/>
                            </ToolTip>
                        </TextBox.ToolTip>
                    </TextBlock>
                </DockPanel>
            </DataTemplate>";

        using (var sr = new MemoryStream(Encoding.UTF8.GetBytes(template)))
        {
            this.InlineEditorTemplate = XamlReader.Load(sr) as DataTemplate;
        }
    }

    public override void ShowDialog(PropertyValue propertyValue, 
      IInputElement commandSource)
    {
        var browse = new FolderBrowserDialog
        {
            ShowNewFolderButton = true,
            SelectedPath = propertyValue.StringValue,
            Description = "Select Target Folder:",
            RootFolder = Environment.SpecialFolder.MyComputer
        };

        if (browse.ShowDialog() == DialogResult.OK)
        {
            propertyValue.Value = browse.SelectedPath;
        }

        browse.Dispose();
    }
}

I won't get into too much details about the XAML , but a few things to notice:

  1. How the InlineEditorTemplate is set ie by setting it to XAML that's predefined in the string.
  2. Binding of the TextBox ie Value
  3. Binding of the Tooltip ie Value

The 'important' code that's contained in Activity constructor is:

AttributeTableBuilder builder = new AttributeTableBuilder();

builder.AddCustomAttributes(typeof(CopyMoveFiles), "TargetPath",
            new EditorAttribute(
            typeof(BrowseForFolderEditor), 
            typeof(DialogPropertyValueEditor)));

MetadataStore.AddAttributeTable(builder.CreateTable());

Where the TargetPath represents a string property that will be displayed in the PropertyGrid .

There's definitely room for improvement, but that's a start and it seems to work pretty well. One thing worth mentioning is that adding the various references was a pain. I can't afford to waste anymore time on this, but even after adding all the references as per the Microsoft project, it still wouldn't work and eventually it did, so I'm still not sure why this occurred which is a shame but if anyone tries it out and can pinpoint which reference gave them trouble, I'd be interested to know.

Hope this helps.

Update:

If you don't want to define the attributes programmatically in the constructor, you can simply use the attributes:

[Editor(typeof(BrowseForFolderEditor), typeof(DialogPropertyValueEditor))]
public string TargetPath { get; set; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM