C# UITypeEditor Dropdown Not Working With Click Event

432 Views Asked by At

WHAT I'M TRYING TO DO

Hello everyone. I'm trying to make a dropdown inside a property grid. This dropdown for some objects will just place its text inside the property, like a StringConverter. But for other objects, it behaves like a button and will open up other forms or an OpenFileDialog. These forms and OpenFileDialog return a text, which is then put inside the property. I feel like I'm doing this very incorrectly so if there is a better way of doing this. But hopefully there is a simple solution.

WHAT I'VE TRIED

I'm very close. I can get the text to show up on a MessageBox. But I can't seem to put it in the property grid, which is in another form and is protected so I can't shove the value in. The way it works is on the other form, the property grid selected an object, which has an attribute called text.

WHAT I'M DOING NOW

When I click on the dropdown for my text attribute in my property grid. The context menu strip is created, all the click events are on, and then, it returns a value right away. Which is not what I want. I want it to wait for me to click on one of the items inside the context menu, the click events sets the string text, and then, the value returns.

public class text-editor: UITypeEditor
{
    string text = "";

    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        ContextMenuStrip cms = new ContextMenuStrip();
        cms = MakeCms(cms); // adds some ToolStripEditor, & their click events which updates value
        
        ToolStripMenuItem add = new TooStripMenuItem("Add");
        add.Click += new EventHandler(CmsClick); // updates value
        cms.Items.Add(add);

        ToolStripMenuItem remove = new TooStripMenuItem("Remove");
        remove.Click += new EventHandler(CmsClick); // updates value
        cms.Items.Add(remove);
        
        cms.Show(Control.MousePosition);

        if (text != "")
        {
            value = text;
        }

        return value;
    }
1

There are 1 best solutions below

0
Uranus On

The ContextMenuStrip.Show method does not pause the caller and cannot be used here. Create a custom ContextMenuStrip integrated with IWindowsFormsEditorService.

public class TextEditor : UITypeEditor {
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.DropDown; }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
        IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
        if(editorService != null) {
            MyContextMenuStrip cms = new MyContextMenuStrip(editorService, "Add", "Remove");
            editorService.DropDownControl(cms);
            if(cms.SelectedItem == "Add")
                return "Value When Add";
            else if(cms.SelectedItem == "Remove")
                return "Value When Remove";
        }
        return value;
    }
}
class MyContextMenuStrip : UserControl {
    readonly IWindowsFormsEditorService editorService;
    readonly ListBox listBox;
    public MyContextMenuStrip(IWindowsFormsEditorService editorService, params string[] items) {
        this.editorService = editorService;
        listBox = new ListBox();
        listBox.Items.AddRange(items);
        listBox.Dock = DockStyle.Fill;
        listBox.MouseClick += ListBox_MouseClick;
        listBox.Parent = this;
    }
    public string SelectedItem => (string)listBox.SelectedItem;
    private void ListBox_MouseClick(object sender, MouseEventArgs e) {
        ListBox listBox = (ListBox)sender;
        if(listBox.SelectedIndex >= 0) {
            Rectangle selectedItemRect = listBox.GetItemRectangle(listBox.SelectedIndex);
            if(selectedItemRect.Contains(e.Location))
                editorService.CloseDropDown();
        }
    }
}