我的一个wpf程序需要把portable lib中的某一个类的属性用propertygrid展示出来
对于复杂的成员类型比如class或者struct,我上网搜索了下,需要用TypeConverter标记该属性是一个展开属性,如下
class B
{
    A myA;
    [TypeConverter(typeof(ExpandableObjectConverter))]
    public A MyA
    {
        get{..}
        set{..}
     }
}但现在的问题是,我所引用的库是个portable lib,它能引用的references很有限,好像不包括这个TypeConverter.我是个新手,也仔细搜索了一通,但还是没找到什么好的办法。
求教,谢谢。

解决方案 »

  1.   

    那你可否继承一个,为派生类编写 TypeConverter,然后你用派生类去展示
      

  2.   

    我很奇怪,对于class或者struct,默认是支持展开的,你为啥一定要加一个所谓的展开属性?
      

  3.   

    默认是展开的吗?我这里默认是不展开的。
    我看也有其他人问过关于展开的问题:http://topic.csdn.net/u/20100603/14/393795e6-1536-401f-91b6-9cc0c562311f.html
      

  4.   

    不好意思,我再次测试了下自定义类型,发现是以前都是用的系统自带类型,所以默认展开的,如果是自定义类型就不展开了,所以就一直有个误认识。另外,我总算明天你要做什么了,你是要编写通用化的类,跨平台使用,但是又要让那个类型在WPF下面的可以被特殊对待,这种两全其美的东西似乎没有。不过既然是WPF,它也不自带那个Porpertygrid,你肯定是用的WinForm下面的控件,如果你自己制作一个类似的Porpertygrid,那么就可以识别任意类型的默认展开,WPF下自定义Porpertygrid应该不难,这里有相关介绍:
    http://www.cnblogs.com/zhuqil/archive/2010/09/02/Wpf-PropertyGrid-Demo.html
      

  5.   

    还有一个方法,等晚上或明天给你,可以不需要自定义PorpertyGrid了,刚想到,不过因为时间晚了,我得先回去吃饭了。
      

  6.   

    当你在WPF中引用那个portable中定义的类时,运行下述代码即可在自带的那个PorpertyGrid中实现任意类型的展开了(未展开显示的名字由类的ToString重写决定):    public 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.IsPrimitive ? defaultDescriptor : new ObjectCustomTypeDescriptor(defaultDescriptor);
            }
        }
        public class ObjectCustomTypeDescriptor : CustomTypeDescriptor
        {
            public ObjectCustomTypeDescriptor(ICustomTypeDescriptor parent)
                : base(parent) { }        public override AttributeCollection GetAttributes()
            {            
                var attributes = base.GetAttributes().Cast<Attribute>().ToList();
                if (!attributes.Exists(t => t is TypeConverterAttribute))
                {
                    attributes.Add(new TypeConverterAttribute(typeof(ExpandableObjectConverter)));
                }
                return new AttributeCollection(attributes.ToArray());
            }
        }
    请在程序的一开始运行一次如下代码(只需要一次)
    ObjectDescriptionProvider provider = new ObjectDescriptionProvider();
    TypeDescriptor.AddProvider(provider, typeof(Object));
    如果你的类继承某个接口,那么这里的typeof(Object)可以改为你的接口类型。
      

  7.   

    感谢前辈这么晚帮忙看这个问题。
    我照着写了下,发现有变化,原来无法展开的属性出现了个展开箭头,但我点下去之后,还是无法展开,而且值无法修改。我详细说下我的情况:
    我有两个portable lib,假设他们叫A和B。
    A中有个processor类,他里面的属性类型是定义在B中的Level。
    B中的Level只是简单的属性:
            public byte byte1;
           public double double1;
    我在WPF中引用A的processor类,并希望把这个类的实例显示在propertygrid里面。我现在的问题是,我看前辈说,无法展开的属性取决于类型的toString重写,但我如果重写了Level类的ToString,是不是用户也无法通过property grid修改其值?我看前辈的代码,是不是类似于动态提供给Level类一个属性ExpandableObjectConverter?我需不需要继承ExpandableObjectConverter,自己写一个converter,实现ConvertTO, ConvertFrom一类的方法来解决这个问题?非常感谢
      

  8.   

    我这边的测试结果非常正常,那个ToString的重写是不必须的,只是用来改变那个未展开的属性所显示的名字,因为不重写的话,默认显示类的完全限定名,这实在太难看了点,如果不介意就不去管它。
    如果你还有疑问,我可以把我的测试代码放上:    public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }        public override string ToString()
            {
                return this.Id + "," + this.Name;
            }
        }    public class Post
        {
            public int Id { get; set; }
            public User Owner { get { return new User(); } }
            public string Content { get; set; }
            public Comment Comment { get { return new Comment(); } }
        }
        public class Comment
        {
            public int Id { get; set; }
            public string CommentData { get; set; }
        }
            public Window1()
            {
                InitializeComponent();            ObjectDescriptionProvider provider = new ObjectDescriptionProvider();
                TypeDescriptor.AddProvider(provider, typeof(Object));
                PropertyGrid1.SelectedObject = new Post();
            }
      

  9.   

    关于你所说的那个修改问题,我刚才试了下,发现string类型被搞成无法修改了,故稍作调整如下:    public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();            ObjectDescriptionProvider provider = new ObjectDescriptionProvider();
                TypeDescriptor.AddProvider(provider, typeof(Object));
                PropertyGrid1.SelectedObject = new Post();
            }
        }    public 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.IsPrimitive || objectType == typeof(string)) ? defaultDescriptor : new ObjectCustomTypeDescriptor(defaultDescriptor);
            }
        }
        public class ObjectCustomTypeDescriptor : CustomTypeDescriptor
        {
            public ObjectCustomTypeDescriptor(ICustomTypeDescriptor parent)
                : base(parent) { }        public override AttributeCollection GetAttributes()
            {
                var attributes = base.GetAttributes().Cast<Attribute>().ToList();
                if (!attributes.Exists(t => t is TypeConverterAttribute))
                {
                    attributes.Add(new TypeConverterAttribute(typeof(ExpandableObjectConverter)));
                }
                return new AttributeCollection(attributes.ToArray());
            }
        }    public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }        public override string ToString()
            {
                return this.Id + "," + this.Name;
            }
        }    public class Post
        {
            User owner = new User();
            Comment comment = new Comment();
            public int Id { get; set; }
            public User Owner { get { return owner; } }
            public string Content { get; set; }
            public Comment Comment { get { return comment; } }
        }
        public class Comment
        {
            public int Id { get; set; }
            public string CommentData { get; set; }
        }
    至于原理的确是动态给一个Object类型提供ExpandableObjectConverter,因为这个ExpandableObjectConverter功能有限,如果至少它没有实现ConvertFrom,因此不能在未展开的情况下编辑,除非自己继承并提供支持。
      

  10.   


     public Window1()
            {
                InitializeComponent();            ObjectDescriptionProvider provider = new ObjectDescriptionProvider();
                TypeDescriptor.AddProvider(provider, typeof(Object));
                PropertyGrid1.SelectedObject = new Post();
            }这里typeof 不需要指明是user或者comment类吗?
    TypeDescriptor.AddProvider(provider, typeof(Object));
      

  11.   

    指明基类即可,不需要对每个类型进行指明。
    另外给你一个小技巧,CSDN的论坛最近频繁抽风,不但经常404,还出现楼层掉落现象,比如我这里12楼就掉落了。
    当你看到楼层不连续的时候,就需要在管理菜单里面反复“生成帖子”,否则看不全帖子的内容。给CSDN管理员的建议:如果CSDN一直这样下去,以后将不来这里了,去cnblog看看吧,人家的博问显示非常及时,从未有丢失内容或404的现象,功能强大带邮件提醒,做得非常人性化,相比之下,这里的论坛程序太垃圾了,而人气应该都是刷出来的。
      

  12.   

    嗯,我也发现了,以前我记得很少出现404.
    不过我这里还是无法展开,只能出现一个展开的箭头,点完之后没反应。我打算试着自己写一个converter实现convertto, convertfrom什么的,试一下。
    非常感谢,你提供的这种动态增加attr的办法很有用。
      

  13.   

    关于展开后显示不出内容,需要留意的是TypeConverter.GetProperties方法,所显示的属性通过这个方法的三个重载形式来提供,如果自己继承一个TypeConverter类,也必须实现这个方法才能得到展开的属性。
    一般情况下,属性都是共有的,类的实例不为null的话,都是可以展开并显示的。
      

  14.   

    我通过你教的动态增加attr,加上我自己重载了一个converter。可以实现在string的形式下编辑数值了,大概是这个形式:
    InLow:25, InHigh: 232, OutLow: 0, OutHigh: 10, Gamma: 1.18
    虽然不如展开菜单方便,但也可以用了。我再按照你说的试下重载getproperties。
    非常感谢你的帮助。