由于Control.Name属性被标记为[Browsable(false)],导致Name属性无法显示,请问怎么解决呢?我要让所有的控件(比如TextBox,Button,ComboBox)都能显示Name出来,所以不能用派生子控件的方式去做

解决方案 »

  1.   

    什么控件名?是form里面的所有控件名?
      

  2.   

    参考,不知道有么有帮助http://blog.csdn.net/luyifeiniu/article/details/5426960
    http://space.itpub.net/12639172/viewspace-488958
      

  3.   

    Button btn=new Button();
    btn.Name="MyName";
    btn.Text="OK";propertyGrid1.SelectedObject=btn;在propertyGrid1控件上,会显示btn的Text属性会OK,但是不会显示Name属性,我希望把Name属性也要显示出来因为我的SelectedObject在运行时可能是不同的控件,所以不能通过从Button派生出自己的自定义Button来实现
      

  4.   

    Tag属性可以不哦。把值绑定到Tag属性
      

  5.   


    。。
    只能在PropertyGrid,TypeConverter等上面考虑,你不能修改SelectedObject对象啊,那不就影响这些控件的正常使用了吗?。
      

  6.   

    这样可以显示所有的属性,如果觉得太多,可以添加new ReadOnlyAttribute(false)的控制,只读的不显示。
                TextBox tx = new TextBox();
                propertyGrid1.BrowsableAttributes = new AttributeCollection(new BrowsableAttribute(false));
                propertyGrid1.SelectedObject = tx;
    反正要精确控制属性的显示,只能派生一个类才行。
      

  7.   

    貌似能出来,但不知道是不是LZ想要的东西!!!我也是抄楼上的Button btn = new Button();
                btn.Name = "MyName";
                btn.Text = "OK";            propertyGrid1.BrowsableAttributes = new AttributeCollection(new BrowsableAttribute(false));
                propertyGrid1.BrowsableAttributes = new AttributeCollection(new ReadOnlyAttribute(false));
                propertyGrid1.SelectedObject = btn;
      

  8.   

    楼上的方法我知道,直接:
    propertyGrid1.BrowsableAttributes = new AttributeCollection();
    就可以显示出来,但是有一个问题,如果有子对象的话,子对象的Name显示不了比如放一个Panel,在Panel放一个Button
    propertyGrid1.SelectedObject=panel1;
    然后你在PropertyGrid面板中选中Controls这个属性,并打开,会弹出新的一个对话框,里面没有Name属性
      

  9.   

    我只知道研究方向,我们一起来研究可以,看谁先找出来:去这里http://www.icsharpcode.net/OpenSource/SD/Download/下载开源的.NET编译器,该编译器非常强大,本身是用C#写的,我看过它的属性显示,可以显示Name属性,而且效果了Visual Studio一样,都是用括号包围的,但是整个开源项目非常庞大,具体是什么位置设置了这个Name显示,目前还没有找到。如果你看这个项目有难度,可以等等,我看能不能花点时间找出来。
      

  10.   

    大概思路我了解,需要创建一个属性:
    PropertyDescriptor pd= TypeDescriptor.CreateProperty(typeof(Control),"Name",typeof(string));
    然后把这个属性描述添加进去,但是我不知道添加到哪里
      

  11.   

    经研究发现,Visual Studio和其他编译器之所以可以实现Name属性的显示,是因为在设计模式下单独加载的这个属性,换句话说,微软单独在设计模式下开放了这个接口,没有任何多余代码即可显示。因此除非你的控件是工作在设计模式下,否则是无法显示Name属性的,即便显示了第一层的Name属性,打开子属性面板后,还是无法显示Name属性。
      

  12.   

    你这是凭空想想,根本没这样的技术,就算有这样的说法,也只是自定义个支持添加属性的类,且添加了不可反射的属性,这里必须是可反射才行。你要求是系统自带的类进行动态添加,且不说动态添加,静态添加都不可能,所以劝你趁早放弃。退一步有一种技术,虽然可以实现,但是十分复杂,不推荐。就是动态创建新的类型,继承基础类。
    但是动态创建的类型虽然可以给PropertyGrid使用,但是诸如你点击Controls属性,在那个弹出窗口里添加的子控件又是不可控制的,最多只能控制第一层的PropertyGrid的SelectObject,之后属性里弹出的PropertyGrid控制不到,除非更改类本身的属性类型,那样还不如继承一个类定制更好。
      

  13.   

    这个我以前也遇到过,最后没办法,只好加一个属性[name],来表示name
      

  14.   

    我相信微软提供一个TypeDescriptor.CreateProperty函数不是当摆设吧,如果不能实现这个功能,那CreateProperty函数的意义何在呢?在其它场合还有它存在的价值吗
      

  15.   

    这是核心代码:    class ControlDescriptionProvider : TypeDescriptionProvider
        {
            private static TypeDescriptionProvider defaultTypeProvider =
                           TypeDescriptor.GetProvider(typeof(Control));        public ControlDescriptionProvider() : base(defaultTypeProvider) { }        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
                return new TitleCustomTypeDescriptor(defaultDescriptor);
            }
        }
        class TitleCustomTypeDescriptor : CustomTypeDescriptor
        {
            public TitleCustomTypeDescriptor(ICustomTypeDescriptor parent)
                : base(parent)
            {
                customFields.Add(new NamePropertyDescriptor());
            }        private List<PropertyDescriptor> customFields = new List<PropertyDescriptor>();        public override PropertyDescriptorCollection GetProperties()
            {
                return new PropertyDescriptorCollection(base.GetProperties()
                    .Cast<PropertyDescriptor>().Union(customFields).ToArray());
            }        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                return new PropertyDescriptorCollection(base.GetProperties(attributes)
                    .Cast<PropertyDescriptor>().Union(customFields).ToArray());
            }
        }    class NamePropertyDescriptor : PropertyDescriptor
        {
            public NamePropertyDescriptor() : base("(Name)", null) { }        public override bool CanResetValue(object component)
            {
                return false;
            }        public override Type ComponentType
            {
                get
                {
                    return typeof(Control);
                }
            }        public override object GetValue(object component)
            {
                Control control = (Control)component;
                return control.Name;
            }        public override bool IsReadOnly
            {
                get
                {
                    return false;
                }
            }        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)
            {
                Control control = (Control)component;
                control.Name = value.ToString();
            }        public override bool ShouldSerializeValue(object component)
            {
                return false;
            }
        }下面是测试代码:ControlDescriptionProvider provider = new ControlDescriptionProvider();
    TypeDescriptor.AddProvider(provider, typeof(Control));
    //下面测试下Label,任何控件都可以。
    Label label = new Label();
    label.Name = "123";
    propertyGrid1.SelectedObject = label;
      

  16.   

    好像可以,除了子菜单的情况,因为ToolStripItem不是Control的派生类,再写一个ToolStripItem的类应该就可以了
      

  17.   

    不用那么麻烦,稍微改下即可,把Control替换为Object,再改动下一些细节,就支持所有带有Name属性的类型了。核心类:    class ObjectDescriptionProvider : TypeDescriptionProvider
        {
            private static TypeDescriptionProvider defaultTypeProvider =
                           TypeDescriptor.GetProvider(typeof(Object));        public ObjectDescriptionProvider() : base(defaultTypeProvider) { }        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
                return objectType.GetProperty("Name") == null ? defaultDescriptor : new NameCustomTypeDescriptor(defaultDescriptor);
            }
        }
        class NameCustomTypeDescriptor : CustomTypeDescriptor
        {
            public NameCustomTypeDescriptor(ICustomTypeDescriptor parent)
                : base(parent)
            {
                customFields.Add(new NamePropertyDescriptor());
            }        private List<PropertyDescriptor> customFields = new List<PropertyDescriptor>();        public override PropertyDescriptorCollection GetProperties()
            {
                return new PropertyDescriptorCollection(base.GetProperties()
                    .Cast<PropertyDescriptor>().Union(customFields).ToArray());
            }        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                return new PropertyDescriptorCollection(base.GetProperties(attributes)
                    .Cast<PropertyDescriptor>().Union(customFields).ToArray());
            }
        }    class NamePropertyDescriptor : PropertyDescriptor
        {
            public NamePropertyDescriptor() : base("(Name)", null) { }        public override bool CanResetValue(object component)
            {
                return false;
            }        public override Type ComponentType
            {
                get
                {
                    return typeof(Object);
                }
            }        public override object GetValue(object component)
            {
                Object control = (Object)component;
                return control.GetType().GetProperty("Name").GetValue(control, null);
            }        public override bool IsReadOnly
            {
                get
                {
                    return false;
                }
            }        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)
            {
                Object control = (Object)component;
                control.GetType().GetProperty("Name").SetValue(control, value, null);
            }        public override bool ShouldSerializeValue(object component)
            {
                return false;
            }
        }示例:ObjectDescriptionProvider provider = new ObjectDescriptionProvider();
    TypeDescriptor.AddProvider(provider, typeof(Object));
    //下面测试下ToolStripMenuItem,任何控件都可以。
    ToolStripItem toolItem = new ToolStripMenuItem();
    toolItem.Name = "123";
    propertyGrid1.SelectedObject = toolItem;
      

  18.   

    我有个疑问,为什么一定要写成(Name),写成Name就不行
      

  19.   

       class NamePropertyDescriptor : PropertyDescriptor
        {
            public NamePropertyDescriptor() : base("(Name)", null) { }
      

  20.   

    参考Visual Studio里面的属性显示方式,因为这是额外增加的属性,如果用原来的名字,就不是增加属性,而只是使用原来的属性,但是原来的属性不可见,最后就是没任何效果。
      

  21.   

    我知道了,应该正是因为Name属性被标记为[Browsable(false)]所以不能显示,改成其它任何名字都行,比如改成MyName也行
      

  22.   

    其实如果做得完善点,还应该判断下原来的那个Name属性是否带有[Browsable(false)],如果带有,才需要额外增加属性。
      

  23.   

    恩,我修改了两处,一处是判断是否存在[Browsable(false)],另一处是判断对象的Name属性是否为string类型(否则进行属性修改时可能会报错),现在应该比较完善了,非常感谢!
        class ObjectDescriptionProvider : TypeDescriptionProvider
        {
            public ObjectDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(Object))) { }        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
                PropertyInfo pi = objectType.GetProperty("Name");
                if (pi != null && pi.PropertyType==typeof(string))
                {
                    BrowsableAttribute[] bas = (BrowsableAttribute[])pi.GetCustomAttributes(typeof(BrowsableAttribute), false);
                    if (bas.Length > 0 && !bas[0].Browsable)
                        return new NameCustomTypeDescriptor(defaultDescriptor);
                }
                return defaultDescriptor;
            }
        }    class NameCustomTypeDescriptor : CustomTypeDescriptor
        {
            public NameCustomTypeDescriptor(ICustomTypeDescriptor parent)
                : base(parent)
            {
            }        public override PropertyDescriptorCollection GetProperties()
            {
                PropertyDescriptorCollection pdc = base.GetProperties();
                PropertyDescriptor[] pds = new PropertyDescriptor[pdc.Count + 1];
                pds[0] = new NamePropertyDescriptor();
                pdc.CopyTo(pds, 1);
                return new PropertyDescriptorCollection(pds);
            }        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                PropertyDescriptorCollection pdc = base.GetProperties(attributes);
                PropertyDescriptor[] pds = new PropertyDescriptor[pdc.Count + 1];
                pds[0] = new NamePropertyDescriptor();
                pdc.CopyTo(pds, 1);
                return new PropertyDescriptorCollection(pds);
            }
        }    class NamePropertyDescriptor : PropertyDescriptor
        {
            public NamePropertyDescriptor() : base("(Name)", null) { }        public override bool CanResetValue(object component)
            {
                return false;
            }        public override Type ComponentType
            {
                get
                {
                    return typeof(object);
                }
            }        public override object GetValue(object component)
            {
                return component.GetType().GetProperty("Name").GetValue(component, null);
            }        public override bool IsReadOnly
            {
                get
                {
                    return false;
                }
            }        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)
            {
                component.GetType().GetProperty("Name").SetValue(component, value, null);
            }        public override bool ShouldSerializeValue(object component)
            {
                return false;
            }
        }
      

  24.   

    又研究了一下,去掉了从PropertyDescriptor派生子类的部分,并且可以直接显示Name,而不是(Name),更加完善了    class ObjectDescriptionProvider : TypeDescriptionProvider
        {
            public ObjectDescriptionProvider() : base(TypeDescriptor.GetProvider(typeof(object))) { }        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
            {
                ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
                PropertyInfo pi = objectType.GetProperty("Name");
                if (pi != null&&pi.PropertyType==typeof(string) )
                {
                    BrowsableAttribute[] bas = (BrowsableAttribute[])pi.GetCustomAttributes(typeof(BrowsableAttribute), false);
                    if (bas.Length > 0 && !bas[0].Browsable)
                        return new NameCustomTypeDescriptor(defaultDescriptor);
                }
                return defaultDescriptor;
            }
        }    class NameCustomTypeDescriptor : CustomTypeDescriptor
        {
            public NameCustomTypeDescriptor(ICustomTypeDescriptor parent)
                : base(parent)
            {
                pd = TypeDescriptor.CreateProperty(parent.GetType().GetField("_objectType", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(parent) as Type, "Name", typeof(string), BrowsableAttribute.Yes);
            }
            private PropertyDescriptor pd;
            public override PropertyDescriptorCollection GetProperties()
            {
                PropertyDescriptorCollection pdc = base.GetProperties();
                PropertyDescriptor[] pds = new PropertyDescriptor[pdc.Count + 1];
                pds[0] = pd;
                pdc.CopyTo(pds, 1);
                return new PropertyDescriptorCollection(pds);
            }        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                PropertyDescriptorCollection pdc = base.GetProperties(attributes);
                PropertyDescriptor[] pds = new PropertyDescriptor[pdc.Count + 1];
                pds[0] = pd;
                pdc.CopyTo(pds, 1);
                return new PropertyDescriptorCollection(pds);
            }
        }
      

  25.   

    想法不错,不过代码总是有点冗余,比如这里完全可以优化成这样:
        class NameCustomTypeDescriptor : CustomTypeDescriptor
        {
            public NameCustomTypeDescriptor(ICustomTypeDescriptor parent,Type objectType)
                : base(parent)
            {
                pd = TypeDescriptor.CreateProperty(objectType, "Name", typeof(string), BrowsableAttribute.Yes);
            }
        //.................
    你再看下调用方,有个objectType参数可以直接传递给它的。另外这种方法虽然可以,但是你没有去掉原来的那个Name,实际连隐藏属性一起显示的话,就会看到两个Name(完全同名),太别扭了。
      

  26.   

    1.我最早就是你这么写的,后来分析.Net的源码,发现CustomTypeDescriptor中本来就已经保存了这个Type,所以我才只传了一个参数,我反而觉得我现在的写法更好一点
    2.显示的时候没有,我觉得就没什么问题了
    3.我又发现了一种新方法,可以不自定义类型(ObjectDescriptionProvider,NameCustomTypeDescriptor 都可以不要)
            private void propertyGrid1_SelectedObjectsChanged(object sender, EventArgs e)
            {
                PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(propertyGrid1.SelectedObject.GetType());
                PropertyDescriptor pd = pdc.Find("Name", false);
                if (pd != null && !pd.IsBrowsable)
                {
                    pdc.GetType().GetField("readOnly", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(pdc, false);
                    pdc.Add(TypeDescriptor.CreateProperty(propertyGrid1.SelectedObject.GetType(), "Name", typeof(string), BrowsableAttribute.Yes));
                }
            }但是必须为每一种类型执行一次操作,直接在object或Control类上操作不行,所以我把代码放在SelectedObjectsChanged事件中,每次使用propertyGrid1.SelectedObject.GetType(),但问题是,如果有子项就不好弄了,比如MenuStrip.Items,修改它的子项并不会触发propertyGrid1的SelectedObjectsChanged事件,我分析后发现子项其实是一个VsPropertyGrid类型,但是没法取得Instance,所以没法注册其SelectedObjectsChanged事件
      

  27.   

    在没有想出更好的办法之前,看来只有使用绝招了(^_^)
    static void Main()
            {
                foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
                    AddNameProperty(ass);
                AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);//code        static void AddNameProperty(Assembly ass)
            {
                foreach (Type t in ass.GetTypes())
                {
                    try
                    {
                        PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(t);
                        PropertyDescriptor pd = pdc.Find("Name", false);
                        if (pd != null && !pd.IsBrowsable)
                        {
                            pdc.GetType().GetField("readOnly", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(pdc, false);
                            pdc.Add(TypeDescriptor.CreateProperty(t, "Name", typeof(string), BrowsableAttribute.Yes));
                        }
                    }
                    catch
                    {
                    }
                }
            }
            static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
            {
                AddNameProperty(args.LoadedAssembly);
            }
    把所有满足条件的都添加上,这样不需要处理SelectedObjectsChanged事件了
      

  28.   

    本来我打算睁只眼闭只眼的,但是你还在错误的方向越陷越深,实在看不下去了。最佳方法是我前面给的那个自定义类的方法,而且可扩展性高。你的方法看似代码量少,但是执行效率却降低了。而且最可怕的是,你反射了微软保护的字段,所有受保护的字段不保证在.NET的所有版本中都适用,这不是WINDOWS API,私有成员切记直接反射,否则程序兼容性大大下降。
      

  29.   

    我之前还有更疯狂的想法:监视Application.OpenForm,从其中去找到子项的ProperyGrid控件的instance,从而通过其SelectedObject来获取需要的Type
      

  30.   

    动态属性有这个啊。怎么是凭空想的呢。
    我前段时间搞这个东西。下载了动态属性的列子。列子好象msdn上也有。
      

  31.   

    楼主可以搜一下。tooltip这个就有动态添加属性的。
      

  32.   

    直接继承
    new Name
    {
    get{retrun base.Name}
    set{base.Name=value;}
    }上面的搞了那么多复杂的方法干啥
      

  33.   


    这个兄弟说的很对。
    [Browsable(True)]
    public new Name
    {
    get{retrun base.Name}
    set{base.Name=value;}
    }
      

  34.   

    200分给我吧,以上都没有好答案! PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(TextBox));
                AttributeCollection attrs= props["Name"].Attributes;BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic |BindingFlags.CreateInstance;
                
    FieldInfo type = typeof(BrowsableAttribute).GetField("browsable", flags);
    filedInfo.SetValue(attrs[typeof(ReadOnlyAttribute)], false/true);以上方法适应于所有的字段属性标签