简体   繁体   中英

How to add support of multiobject edits for PropertyGrid's custom property editor?

This is the simplest ever custom property editor that contains just a form with one more PropertyGrid:

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms.Design;

namespace PageControls
{
    public partial class PropertyGridEditor : Form
    {
        public object ObjectToEdit;

        public delegate void PropertyValueChangedEventHandler(object sender, PropertyValueChangedEventArgs e);
        public static event PropertyValueChangedEventHandler PropertyValueChangedStatic;
        public event EventHandler<PropertyValueChangedEventArgs> PropertyValueChanged;

        public PropertyGridEditor(object obj_to_edit)
        {
            InitializeComponent();
            this.ObjectToEdit = obj_to_edit;
        }

        private void PropertyGridEditor_Load(object sender, EventArgs e)
        {
            this.prop_grid.SelectedObject = ObjectToEdit;
        }

        private void PropertyGridEditor_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
        }

        private void prop_grid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            var evt = PropertyGridEditor.PropertyValueChangedStatic;

            if (evt != null)
                evt(s, e);

            var evt2 = this.PropertyValueChanged;

            if (evt2 != null)
                evt2(s, e);
        }
    }

    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public class InnerPropertyGridEditor : UITypeEditor
    {
        public InnerPropertyGridEditor()
        {

        }

        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // Indicates that this editor can display a Form-based interface. 
            return UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // Attempts to obtain an IWindowsFormsEditorService.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

            if (edSvc == null)
                return null;

            using (PropertyGridEditor form = new PropertyGridEditor(value)) //when two or more properties were selected the value is null :/
                if (edSvc.ShowDialog(form) == DialogResult.OK)
                    return form.ObjectToEdit;

            return value; // If OK was not pressed, return the original value 
        }
    }
}

So, now I have a class:

class Test
{
   public bool Prop1 { get; set; }
   public bool Prop2 { get; set; }
}

And I have main class that has this Test class as property.

class MainClass
{
    [Editor(typeof(InnerPropertyGridEditor), typeof(UITypeEditor))]
    public Test test_prop { get; set; }

    ...
}

My main PropertyEditor supports multi selected objects. So, I can select two or more MainClasses to edit their properties.

The problem is - when I do that and tries to edit test_prop InnerPropertyGridEditor appears empty, because of passed value is null.

Actually, I hoped it to be at least object[] so I can implement something.

Ok, in case if no one will ever answer this I will show the hacky solution I made:

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms.Design;
using System.Reflection;

namespace PageControls
{
    public partial class PropertyGridEditor : Form
    {
        public object Result;

        public static event EventHandler<PropertyValueChangedEventArgs> PropertyValueChangedStatic;
        public event EventHandler<PropertyValueChangedEventArgs> PropertyValueChanged;

        public PropertyGridEditor(object[] obj_to_edit)
        {
            InitializeComponent();

            this.prop_grid.SelectedObjects = obj_to_edit;

            this.Result = obj_to_edit[0];
        }

        private void PropertyGridEditor_Load(object sender, EventArgs e)
        {

        }

        private void PropertyGridEditor_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
        }

        private void prop_grid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            var evt = PropertyGridEditor.PropertyValueChangedStatic;

            if (evt != null)
                evt(s, e);

            var evt2 = this.PropertyValueChanged;

            if (evt2 != null)
                evt2(s, e);
        }
    }

    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    public class InnerPropertyGridEditor : UITypeEditor
    {
        public InnerPropertyGridEditor()
        {

        }

        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            // Indicates that this editor can display a Form-based interface. 
            return UITypeEditorEditStyle.Modal;
        }

        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            // Attempts to obtain an IWindowsFormsEditorService.
            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

            if (edSvc == null)
                return null;

            object[] values = new object[context.Instance is object[] ? ((object[])context.Instance).Length : 1];

            if (context.Instance is object[])
                for (int i = 0; i < ((object[])context.Instance).Length; i++)
                {
                    PropertyInfo pi = ((object[])context.Instance)[i].GetType().GetProperty(context.PropertyDescriptor.Name);
                    values[i] = pi != null ? pi.GetValue(((object[])context.Instance)[i], null) : null;
                }
            else
                values[0] = value;

            using (PropertyGridEditor form = new PropertyGridEditor(values))
                if (edSvc.ShowDialog(form) == DialogResult.OK)
                    return form.Result;

            return value; // If OK was not pressed, return the original value 
        }
    }
}

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