Search code examples
c#winformspropertygriduitypeeditor

IWindowsFormsEditorService delay after closing


I need to have a custom property value editor integrated into PropertyGrid control. Code is listed below

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

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        IWindowsFormsEditorService service = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;

        Type type = context.GetType();
        PropertyInfo property = type.GetProperty("OwnerGrid");

        IPlugIn plug = context.Instance as IPlugIn;

        if (service != null && property != null
                            && plug != null)
        {
            PropertyGrid owner = property.GetValue(context) as PropertyGrid;

            if (owner != null)
            {
                Collection<VariableWrapper> variables = owner.Tag as Collection<VariableWrapper>;

                if (variables != null)
                {
                    VariableEditorForm editor = new VariableEditorForm();
                    editor.Value = plug.VariableName;
                    editor.Variables = variables.Select(o => o.Variable).Where(o => o.ValueType == plug.VariableType).ToArray();
                    editor.TopLevel = false;
                    editor.FormClosed += new FormClosedEventHandler((sender, args) =>
                    {
                        service.CloseDropDown();
                    });

                    service.DropDownControl(editor);
                    value = editor.Value;
                }
            }
        }

        return value;
    }
}

I want it to work this way:

  • to change value of the property user opens up the DropDown with VariableEditorForm (using PropertyGrid)
  • user selects one of the values listed in the VariableEditorForm and after that VariableEditorForm would close automatically

It works now. But for some reason it takes 2-3 seconds before EditValue method would return its value.

Why service.DropDownControl(editor) does not return immediately after its closing?


Solution

  • I managed to find a solution. I don't like but it works. Code is listed below.

                public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
                {
                    IWindowsFormsEditorService service = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
    
                    Type type = context.GetType();
                    PropertyInfo property = type.GetProperty("OwnerGrid");
    
                    IPlugIn plug = context.Instance as IPlugIn;
    
                    if (service != null && property != null
                                        && plug != null)
                    {
                        PropertyGrid owner = property.GetValue(context) as PropertyGrid;
    
                        if (owner != null)
                        {
                            Collection<VariableWrapper> variables = owner.Tag as Collection<VariableWrapper>;
    
                            if (variables != null)
                            {
                                VariableEditorForm editor = new VariableEditorForm();
                                editor.Value = plug.VariableName;
                                editor.Variables = variables.Select(o => o.Variable).Where(o => o.ValueType == plug.VariableType).ToArray();
                                editor.TopLevel = false;
                                editor.FormClosed += new FormClosedEventHandler((sender, args) =>
                                {
                                    // disable main form rendering
                                    User32.PostMessage(Process.GetCurrentProcess().MainWindowHandle, Messages.WM_DISABLE_RENDER, IntPtr.Zero, IntPtr.Zero);
                                    service.CloseDropDown();
                                });
    
                                service.DropDownControl(editor);
    
                                // enable main form rendering
                                User32.PostMessage(Process.GetCurrentProcess().MainWindowHandle, Messages.WM_ENABLE_RENDER, IntPtr.Zero, IntPtr.Zero);
                                value = editor.Value;
                                editor.Dispose();
                            }
                        }
                    }
    
                    return value;
                }
    

    Thing is that I have a panel on my main form that uses timer to constantly render itself. I noticed that my problem goes away each time I disable that timer. So not having any better solition I decided to post message to my main form to enable/disable mentioned timer.

    I would appreciate if someone would provide a proper solution to my problem.