PropertyGrid—添加EventTab

零.引言

  前面一篇文章介绍了如何在PropertyGrid中添加属性Tab,本文主要介绍如何添加事件选项卡。事件在许多对象中都有,尤其是在控件中,如何让对象的事件在PropertyGrid中显示出来呢,本文将进行简单的说明。

一.回顾添加属性Tab

  在上篇文章中详细的讲解了如何添加属性Tab,这里简单回顾一下:

  1.新建一个Tab类并继承于PropertyTab。

  2.重写TabName和Bitmap属性以及GetProperties方法。

  3.给特定类添加PropertyTab特性或将自定义Tab类添加到PropertyGrid的PropertyTabs集合中。

  三步就可以完成了,添加EventTab与此类似,现在问题的关键在于我们要显示的是事件,而GetProperties方法只能返回属性集合(PropertyDescriptorCollection)。怎么办呢,很简单,我们把事件封装成PropertyDescriptor,再返回就行了。

二. 添加EventTab

  GetProperties方法只能返回属性集合。那我们就把事件封装成PropertyDescriptor。首先定义一个封装事件的类,该类继承于PropertyDescriptor:

class EventWrapper : PropertyDescriptor
    {
        string name; //名字
        public EventWrapper(string name)
            : base(name, null)
        {
            this.name = name;
        }

        public override bool CanResetValue(object component)
        {
            return true;
        }

        public override string DisplayName
        {
            get
            {
                return name;
            }
        }

        public override string Description
        {
            get
            {
                return string.Format("{0} description", name);
            }
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override string Name
        {
            get
            {
                return "fs2_" + name;
            }
        }

        public override Type ComponentType
        {
            get { throw new NotImplementedException(); }
        }

        public override object GetValue(object component)
        {
            //do something
            return "";
        }

        public override Type PropertyType
        {
            get { return typeof(string); }
        }

        public override void ResetValue(object component)
        {
            throw new NotImplementedException();
        }

        public override void SetValue(object component, object value)
        {
            //do something
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }
View Code

  继承PropertyDescriptor时,需要重写一些属性和方法。封装类中,我们定义了一个name,用来保存事件的名称。好了,现在EventWrapper是从PropertyDescriptor继承而来,可以作为GetProperties方法的返回类型了。

  接下来像前一篇文章一样定义一个EventsTab选型卡类:

public class EventsTab : System.Windows.Forms.Design.PropertyTab
    {
        [BrowsableAttribute(true)]
        // This string contains a Base-64 encoded and serialized example property tab image.
        private string img = "AAEAAAD/////AQAAAAAAAAAMAgAAAFRTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj0xLjAuMzMwMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5CaXRtYXABAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA9gAAAAJCTfYAAAAAAAAANgAAACgAAAAIAAAACAAAAAEAGAAAAAAAAAAAAMQOAADEDgAAAAAAAAAAAAD///////////////////////////////////9ZgABZgADzPz/zPz/zPz9AgP//////////gAD/gAD/AAD/AAD/AACKyub///////+AAACAAAAAAP8AAP8AAP9AgP////////9ZgABZgABz13hz13hz13hAgP//////////gAD/gACA/wCA/wCA/wAA//////////+AAACAAAAAAP8AAP8AAP9AgP////////////////////////////////////8L";

        public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes)
        {
            //Return list of known events
            EventDescriptorCollection events_info;
            if (attributes == null)
                events_info = TypeDescriptor.GetEvents(component);
            else
                events_info = TypeDescriptor.GetEvents(component, attributes);
            //封装事件
            var events = new PropertyDescriptor[events_info.Count];
            for (int i = 0; i < events_info.Count; i++)
                events[i] = new EventWrapper(events_info[i].Name);

            return new PropertyDescriptorCollection(events);
        }

        public override string TabName
        {
            get { return "Events"; }
        }

        public override System.Drawing.Bitmap Bitmap
        {
            get
            {
                Bitmap bmp = new Bitmap(DeserializeFromBase64Text(img));

                return bmp;
            }
        }

        private Image DeserializeFromBase64Text(string text)
        {
            Image img = null;
            byte[] memBytes = Convert.FromBase64String(text);
            IFormatter formatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream(memBytes);
            img = (Image)formatter.Deserialize(stream);
            stream.Close();
            return img;
        }
}

  唯一的不同是在Getproperties方法中,我们先获取对象的事件信息,再将其封装为我们定义的事件封装类,并返回。

  现在要做的就是将我们定义的EventsTab类型添加到PropertyGrid控件的PropertyTabs集合中,将MyControl对象赋值给PropertyGrid控件的SelectedObject属性,运行程序,就可以看到MyControl对象的事件列表,效果如下:

  

  可见,事件都列出来了。

三.完整代码

  下面是完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace TestAddTab
{
    //控件类
    //[PropertyTabAttribute(typeof(MyPropertyTab), PropertyTabScope.Component)]
    public class MyControl : System.Windows.Forms.UserControl
    {
        private double _angle = 90;

        public MyControl()
        {
        }

        [BrowsableAttribute(true)]
        [Category("角度")]
        public double Angle
        {
            get
            { return _angle; }
            set
            { _angle = value; }
        }


        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            e.Graphics.DrawString("The Angle is " + _angle, this.Font, Brushes.Red, 0, 0);
        }
    }

    public class EventsTab : System.Windows.Forms.Design.PropertyTab
    {
        [BrowsableAttribute(true)]
        // This string contains a Base-64 encoded and serialized example property tab image.
        private string img = "AAEAAAD/////AQAAAAAAAAAMAgAAAFRTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj0xLjAuMzMwMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5CaXRtYXABAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA9gAAAAJCTfYAAAAAAAAANgAAACgAAAAIAAAACAAAAAEAGAAAAAAAAAAAAMQOAADEDgAAAAAAAAAAAAD///////////////////////////////////9ZgABZgADzPz/zPz/zPz9AgP//////////gAD/gAD/AAD/AAD/AACKyub///////+AAACAAAAAAP8AAP8AAP9AgP////////9ZgABZgABz13hz13hz13hAgP//////////gAD/gACA/wCA/wCA/wAA//////////+AAACAAAAAAP8AAP8AAP9AgP////////////////////////////////////8L";


        public override System.ComponentModel.PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes)
        {
            //Return list of known events
            EventDescriptorCollection events_info;
            if (attributes == null)
                events_info = TypeDescriptor.GetEvents(component);
            else
                events_info = TypeDescriptor.GetEvents(component, attributes);

            var events = new PropertyDescriptor[events_info.Count];
            for (int i = 0; i < events_info.Count; i++)
                events[i] = new EventWrapper(events_info[i].Name);

            return new PropertyDescriptorCollection(events);
        }

        public override string TabName
        {
            get { return "Events"; }
        }

        public override System.Drawing.Bitmap Bitmap
        {
            get
            {
                Bitmap bmp = new Bitmap(DeserializeFromBase64Text(img));
                return bmp;
            }
        }

        private Image DeserializeFromBase64Text(string text)
        {
            Image img = null;
            byte[] memBytes = Convert.FromBase64String(text);
            IFormatter formatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream(memBytes);
            img = (Image)formatter.Deserialize(stream);
            stream.Close();
            return img;
        }
    }

    class EventWrapper : PropertyDescriptor
    {
        string name;
        public EventWrapper(string name)
            : base(name, null)
        {
            this.name = name;
        }

        public override bool CanResetValue(object component)
        {
            return true;
        }

        public override string DisplayName
        {
            get
            {
                return name;
            }
        }

        public override string Description
        {
            get
            {
                return string.Format("{0} description", name);
            }
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override string Name
        {
            get
            {
                return "fs2_" + name;
            }
        }

        public override Type ComponentType
        {
            get { throw new NotImplementedException(); }
        }

        public override object GetValue(object component)
        {
            //do something
            return "";
        }

        public override Type PropertyType
        {
            get { return typeof(string); }
        }

        public override void ResetValue(object component)
        {
            throw new NotImplementedException();
        }

        public override void SetValue(object component, object value)
        {
            //do something
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }
}
View Code

  新建Windows工程,添加该文件,在Form中拖入一个PropertyGrid控件和MyControl控件,在Form的构造函数中添加如下代码:

  this.propertyGrid1.PropertyTabs.AddTabType(typeof(EventsTab));

  this.propertyGrid1.SelectedObject = this.myControl1;

  运行程序,查看效果。

  这里只是实现了非常简单的功能,仅仅显示了控件的事件,而不能编辑,如果要达到VS那种效果,需要完善EventWrapper类。

  还是那句话,个人浅见,错漏不正之处,敬请指出,万分感谢!

 

 

(原文)

 

posted @ 2018-12-29 17:22  quanzhan  阅读(538)  评论(0编辑  收藏  举报