none
PropertyGridのコレクションエディタを非表示にしたい RRS feed

  • 質問

  • いつもお世話になっております
    VS2008 でC++/CLIを使ってフォームアプリを作成しています

    GUIでPropertyGridコントロールを使っているのですが、入力方法にコレクションエディタというものがあります

    このコレクションエディタでは配列に追加、削除などが出来てしまい、

    追加、削除はされたくないので、どうにかして非表示にしたいと思っています。(入力欄右下に現れる...ボタンを表示しない)

    PropertyGridのプロパティを見ると、コレクションエディタをDisableにするプロパティ等は無いようですが、どなたか実現方法を教えて頂けないでしょうか?

    2012年10月24日 10:48

回答

  • 特定のプロパティでのみ編集できないようにしたいのであれば、そのプロパティに偽のSystem.ComponentModel.EditorAttributeを追加してやればできます。

    通常ならコレクションエディタが表示されるプロパティすべてで非表示にしたいのであれば、以下のような方法で可能です。
    C#で書いてあるのでC++/CLIへ変換するか、C#でDLLを作るかしてください。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    using System.Windows.Forms.PropertyGridInternal;
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            PropertyGrid propertyGrid = new PropertyGrid();
            propertyGrid.Dock = DockStyle.Fill;
            this.Controls.Add(propertyGrid);
    
            DisableCollectionEditorPropertyGridTab.SetAttributeReloadPropertyGridTab(propertyGrid);
    
            propertyGrid.SelectedObject = new TestData();
        }
    }
    
    //テスト用のデータ
    public class TestData
    {
        public TestData()
        {
            List1 = new List<int>();
            List1.Add(1);
    
            List2 = new List<int>();
            List2.Add(2);
        }
    
        //常に編集できないようにできる
        [Editor(typeof(DummyEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public List<int> List1 { get; private set; }
    
        //DisableCollectionEditorPropertyGridTabを使うと編集できないようにできる。
        public List<int> List2 { get; private set; }
    }
    
    /// <summary>
    /// CollectionEditorを表示させないための偽エディタ
    /// </summary>
    public class DummyEditor : System.Drawing.Design.UITypeEditor
    {
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return System.Drawing.Design.UITypeEditorEditStyle.None;
        }
    }
    
    /// <summary>コレクションエディタを表示させないPropertyTab</summary> 
    public class DisableCollectionEditorPropertyGridTab : PropertyTab
    {
        /// <summary></summary><remarks>Bitmapが定義されていないとPropertyGridに表示されないらしい</remarks> 
        public override System.Drawing.Bitmap Bitmap
        {
            get { return new System.Drawing.Bitmap(16, 16); }
        }
    
        private PropertiesTab defatultTab = new PropertiesTab();
    
        public override PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes)
        {
            PropertyDescriptorCollection descriptors = new PropertyDescriptorCollection(null, false);
            PropertyDescriptorCollection defaultDescriptors = defatultTab.GetProperties(component);
    
            foreach (PropertyDescriptor descriptor in defaultDescriptors)
            {
                dynamic d = descriptor;
    
                // 属性を更新したPropertyDescriptorを作る 
                if (descriptor.Converter is System.ComponentModel.CollectionConverter)
                {
                    descriptors.Add(new AttributeReloadPropertyDescripter(descriptor));
                }
                else
                {
                    descriptors.Add(descriptor);
                }
            }
    
            return descriptors;
        }
    
        /// <summary>あとで入れ替えるので適当な名前</summary> 
        public override string TabName
        {
            get { return DefaultTabName; }
        }
        private static string DefaultTabName
        {
            get { return "#DumyTabName"; }
        }
    
        /// <summary>属性を更新するためにPropertyDescriptorをラップ</summary> 
        private class AttributeReloadPropertyDescripter : PropertyDescriptor
        {
            public AttributeReloadPropertyDescripter(PropertyDescriptor pd)
                : base(pd)
            {
                innerDescriptor = pd;
                this.AttributeArray = base.AttributeArray;
            }
    
            protected override Attribute[] AttributeArray
            {
                get
                {
                    return _AttributeArray;
                }
                set
                {
                    base.AttributeArray = value;
    
                    _AttributeArray = new Attribute[base.AttributeArray.Length + 1];
                    Array.Copy(base.AttributeArray, _AttributeArray, base.AttributeArray.Length);
    
                    System.ComponentModel.EditorAttribute atr = new EditorAttribute(typeof(DummyEditor), typeof(System.Drawing.Design.UITypeEditor));
    
                    _AttributeArray[_AttributeArray.Length - 1] = atr;
                }
            }
            private Attribute[] _AttributeArray;
    
            #region "PropertyDescriptorのabstract"
    
            private PropertyDescriptor innerDescriptor;
    
            public override bool CanResetValue(object component)
            {
                return innerDescriptor.CanResetValue(component);
            }
    
            public override Type ComponentType
            {
                get { return innerDescriptor.ComponentType; }
            }
    
            public override object GetValue(object component)
            {
                return innerDescriptor.GetValue(component);
            }
    
            public override bool IsReadOnly
            {
                get { return innerDescriptor.IsReadOnly; }
            }
    
            public override Type PropertyType
            {
                get { return innerDescriptor.PropertyType; }
            }
    
            public override void ResetValue(object component)
            {
                innerDescriptor.ResetValue(component);
            }
    
            public override void SetValue(object component, object value)
            {
                innerDescriptor.SetValue(component, value);
            }
    
            public override bool ShouldSerializeValue(object component)
            {
                return innerDescriptor.ShouldSerializeValue(component);
            }
            #endregion
        }
    
        /// <summary>PropertyTabをPropertyGridに追加してデフォルトのPropertyTabを消します</summary> 
        public static void SetAttributeReloadPropertyGridTab(PropertyGrid grid)
        {
            if (!grid.IsHandleCreated)
            {
                grid.HandleCreated += (s, e) => { SetAttributeReloadPropertyGridTab((PropertyGrid)s); };
                return;
            }
    
            foreach (PropertiesTab tab in grid.PropertyTabs)
            {
                if (tab.GetType() == typeof(DisableCollectionEditorPropertyGridTab))
                {
                    return;
                }
            }
    
            grid.PropertyTabs.AddTabType(typeof(DisableCollectionEditorPropertyGridTab), PropertyTabScope.Global);
    
            string propTabName = grid.PropertyTabs[0].TabName;
            string custumTabName = DisableCollectionEditorPropertyGridTab.DefaultTabName;
            ToolStripItem propButton = null;
            ToolStripItem custumButton = null;
    
            ToolStrip strip = GetToolStrip(grid);
            if (strip != null)
            {
                foreach (ToolStripItem item in strip.Items)
                {
                    if (item.Text == propTabName)
                    {
                        propButton = item;
                    }
                    else if (item.Text == custumTabName)
                    {
                        custumButton = item;
                    }
                }
            }
    
            if (propButton != null && custumButton != null)
            {
                strip.Items.Remove(propButton);
                custumButton.Image = propButton.Image;
                custumButton.Text = propButton.Text;
                custumButton.ToolTipText = propButton.ToolTipText;
                custumButton.PerformClick();
            }
            else
            {
                throw new ApplicationException("PropertyGridの構成が変更されているようです");
            }
        }
    
        /// <summary>Control内のToolStripを探します</summary> 
        private static ToolStrip GetToolStrip(Control ctl)
        {
            ToolStrip strip = ctl as ToolStrip;
            if (strip == null)
            {
                foreach (Control child in ctl.Controls)
                {
                    strip = GetToolStrip(child);
                    if (strip != null)
                    {
                        break;
                    }
                }
            }
    
            return strip;
        }
    }
    #「PropertyGridコントロールで、カテゴリ文字列を自由に変更したい。」の亜種です。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク BB-X LARISSA 2012年10月25日 9:42
    2012年10月24日 14:17

すべての返信

  • 特定のプロパティでのみ編集できないようにしたいのであれば、そのプロパティに偽のSystem.ComponentModel.EditorAttributeを追加してやればできます。

    通常ならコレクションエディタが表示されるプロパティすべてで非表示にしたいのであれば、以下のような方法で可能です。
    C#で書いてあるのでC++/CLIへ変換するか、C#でDLLを作るかしてください。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    using System.Windows.Forms.PropertyGridInternal;
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            PropertyGrid propertyGrid = new PropertyGrid();
            propertyGrid.Dock = DockStyle.Fill;
            this.Controls.Add(propertyGrid);
    
            DisableCollectionEditorPropertyGridTab.SetAttributeReloadPropertyGridTab(propertyGrid);
    
            propertyGrid.SelectedObject = new TestData();
        }
    }
    
    //テスト用のデータ
    public class TestData
    {
        public TestData()
        {
            List1 = new List<int>();
            List1.Add(1);
    
            List2 = new List<int>();
            List2.Add(2);
        }
    
        //常に編集できないようにできる
        [Editor(typeof(DummyEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public List<int> List1 { get; private set; }
    
        //DisableCollectionEditorPropertyGridTabを使うと編集できないようにできる。
        public List<int> List2 { get; private set; }
    }
    
    /// <summary>
    /// CollectionEditorを表示させないための偽エディタ
    /// </summary>
    public class DummyEditor : System.Drawing.Design.UITypeEditor
    {
        public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return System.Drawing.Design.UITypeEditorEditStyle.None;
        }
    }
    
    /// <summary>コレクションエディタを表示させないPropertyTab</summary> 
    public class DisableCollectionEditorPropertyGridTab : PropertyTab
    {
        /// <summary></summary><remarks>Bitmapが定義されていないとPropertyGridに表示されないらしい</remarks> 
        public override System.Drawing.Bitmap Bitmap
        {
            get { return new System.Drawing.Bitmap(16, 16); }
        }
    
        private PropertiesTab defatultTab = new PropertiesTab();
    
        public override PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes)
        {
            PropertyDescriptorCollection descriptors = new PropertyDescriptorCollection(null, false);
            PropertyDescriptorCollection defaultDescriptors = defatultTab.GetProperties(component);
    
            foreach (PropertyDescriptor descriptor in defaultDescriptors)
            {
                dynamic d = descriptor;
    
                // 属性を更新したPropertyDescriptorを作る 
                if (descriptor.Converter is System.ComponentModel.CollectionConverter)
                {
                    descriptors.Add(new AttributeReloadPropertyDescripter(descriptor));
                }
                else
                {
                    descriptors.Add(descriptor);
                }
            }
    
            return descriptors;
        }
    
        /// <summary>あとで入れ替えるので適当な名前</summary> 
        public override string TabName
        {
            get { return DefaultTabName; }
        }
        private static string DefaultTabName
        {
            get { return "#DumyTabName"; }
        }
    
        /// <summary>属性を更新するためにPropertyDescriptorをラップ</summary> 
        private class AttributeReloadPropertyDescripter : PropertyDescriptor
        {
            public AttributeReloadPropertyDescripter(PropertyDescriptor pd)
                : base(pd)
            {
                innerDescriptor = pd;
                this.AttributeArray = base.AttributeArray;
            }
    
            protected override Attribute[] AttributeArray
            {
                get
                {
                    return _AttributeArray;
                }
                set
                {
                    base.AttributeArray = value;
    
                    _AttributeArray = new Attribute[base.AttributeArray.Length + 1];
                    Array.Copy(base.AttributeArray, _AttributeArray, base.AttributeArray.Length);
    
                    System.ComponentModel.EditorAttribute atr = new EditorAttribute(typeof(DummyEditor), typeof(System.Drawing.Design.UITypeEditor));
    
                    _AttributeArray[_AttributeArray.Length - 1] = atr;
                }
            }
            private Attribute[] _AttributeArray;
    
            #region "PropertyDescriptorのabstract"
    
            private PropertyDescriptor innerDescriptor;
    
            public override bool CanResetValue(object component)
            {
                return innerDescriptor.CanResetValue(component);
            }
    
            public override Type ComponentType
            {
                get { return innerDescriptor.ComponentType; }
            }
    
            public override object GetValue(object component)
            {
                return innerDescriptor.GetValue(component);
            }
    
            public override bool IsReadOnly
            {
                get { return innerDescriptor.IsReadOnly; }
            }
    
            public override Type PropertyType
            {
                get { return innerDescriptor.PropertyType; }
            }
    
            public override void ResetValue(object component)
            {
                innerDescriptor.ResetValue(component);
            }
    
            public override void SetValue(object component, object value)
            {
                innerDescriptor.SetValue(component, value);
            }
    
            public override bool ShouldSerializeValue(object component)
            {
                return innerDescriptor.ShouldSerializeValue(component);
            }
            #endregion
        }
    
        /// <summary>PropertyTabをPropertyGridに追加してデフォルトのPropertyTabを消します</summary> 
        public static void SetAttributeReloadPropertyGridTab(PropertyGrid grid)
        {
            if (!grid.IsHandleCreated)
            {
                grid.HandleCreated += (s, e) => { SetAttributeReloadPropertyGridTab((PropertyGrid)s); };
                return;
            }
    
            foreach (PropertiesTab tab in grid.PropertyTabs)
            {
                if (tab.GetType() == typeof(DisableCollectionEditorPropertyGridTab))
                {
                    return;
                }
            }
    
            grid.PropertyTabs.AddTabType(typeof(DisableCollectionEditorPropertyGridTab), PropertyTabScope.Global);
    
            string propTabName = grid.PropertyTabs[0].TabName;
            string custumTabName = DisableCollectionEditorPropertyGridTab.DefaultTabName;
            ToolStripItem propButton = null;
            ToolStripItem custumButton = null;
    
            ToolStrip strip = GetToolStrip(grid);
            if (strip != null)
            {
                foreach (ToolStripItem item in strip.Items)
                {
                    if (item.Text == propTabName)
                    {
                        propButton = item;
                    }
                    else if (item.Text == custumTabName)
                    {
                        custumButton = item;
                    }
                }
            }
    
            if (propButton != null && custumButton != null)
            {
                strip.Items.Remove(propButton);
                custumButton.Image = propButton.Image;
                custumButton.Text = propButton.Text;
                custumButton.ToolTipText = propButton.ToolTipText;
                custumButton.PerformClick();
            }
            else
            {
                throw new ApplicationException("PropertyGridの構成が変更されているようです");
            }
        }
    
        /// <summary>Control内のToolStripを探します</summary> 
        private static ToolStrip GetToolStrip(Control ctl)
        {
            ToolStrip strip = ctl as ToolStrip;
            if (strip == null)
            {
                foreach (Control child in ctl.Controls)
                {
                    strip = GetToolStrip(child);
                    if (strip != null)
                    {
                        break;
                    }
                }
            }
    
            return strip;
        }
    }
    #「PropertyGridコントロールで、カテゴリ文字列を自由に変更したい。」の亜種です。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク BB-X LARISSA 2012年10月25日 9:42
    2012年10月24日 14:17
  • 素晴らしいコードをありがとうございます。

    2012年10月25日 9:42