定制的,复杂的,动态的思考解决方案 - C# [英] Custom, Complicated, Dynamic Reflection Solution - C#

查看:113
本文介绍了定制的,复杂的,动态的思考解决方案 - C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我使用我将解释和实例后许多自定义类。解释什么他们都做我会尽量清楚地描述下我的错误是发生的情况后。

I have many custom classes that I am using that I will explain and post examples of. After Explaining what they all do I will try to clearly describe the conditions under which my bug is happening.

首先,我使用的是PropertyGrid中显示几个不同的属性类型的对象。因为默认PropertyGrid中的结合并不像我想它是什么样的描述,我创建了我将其称为显示类的几个自定义类。这些显示类通过传递一个对象,然后创建一个返回很好地格式化字符串和描述的公共属性(在某些情况下,方法)中传递的真正对象的属性构成。

First, I am using a PropertyGrid to display the properties of several different types of objects. Because the default binding of the PropertyGrid was not what as descriptive as I wanted it to be, I created a few custom classes that I will refer to as "Display" classes. These Display classes are constructed by passing in the an object and then creating properties that return nicely formatted strings and descriptions for the public properties (and in some case methods) of the real object that was passed in.

我将用一些缩写示例代码演示了这一点:

I will demonstrate this with some abbreviated example code:

下面是一个对象,我想在我的PropertyGrid中显示的一个例子:

Here is an example of an object I want to Display in my PropertyGrid:

public class Joint
{
   public Joint(...)
   {...}

   //properties
   public string Name { get; set;}
   public CustomObject CC { get; set;}
   public List<CustomObject> Custom List { get; set;}
}



字符串名称属性PropertyGrid中的$ B显示正常$ b然而CustomObject和列表没有显示的方式,显得非常人性化给我。

The string property "Name" displays fine in the PropertyGrid However The CustomObject and List did not display in way that seemed very user friendly to me.

所以,我试图通过编写这个类来创建一个解决方案:

So I attempted to create a solution by writing this class:

public class DisplayJoint
{       

   private Joint _jnt;

   public DisplayJoint(Joint jnt)
   {
      _jnt = jnt;
   }

   //properties
   public string Name {  get { return _jnt.Name; } }

   [TypeConverterAttribute(typeof(ExpandableObjectConverter))]
   public DisplayCustomObject CC {  get { return new DisplayCustomObject(_jnt.CC); } }

   [TypeConverterAttribute(typeof(ExpandableObjectConverter))]
   public List<CustomObject> CustomList { get; set;}
}



正如你可以在上面的代码中看到的,我创建的特殊DisplayClasses为我的关节类和我CustomObject类。在项目中,我有很多很多不同种类的要求作出同样的overlaping显示类属性的对象。

As you can see in the code above, I created special DisplayClasses for both my Joint class and my CustomObject class. In my project I have many, many different kinds of objects that require the same kind of overlaping Display Class properties.

上面可以看到我的最后两个上面添加的行性能

Above you can see the Lines I added above the last two properties

[TypeConverterAttribute(typeof运算(ExpandableObjectConverter))]

[TypeConverterAttribute(typeof(ExpandableObjectConverter))]

这行解决了我的显示CustomObject的问题,我多么想在propertGrid(几乎...更多关于这个版本)。然而,它不工作对我的自定义列表属性相同的方式。在自定义列表它扩展仅显示计数和容量(列表的实际属性),这是有道理这是为什么,但它不是我想要的。我想看看在列表中实际包含的对象。

This line solves my problem of displaying the CustomObject how I want to in the propertGrid(almost... more on this later). However it does not work the same way for my Custom List property. On the Custom List it expands to show only Count and capacity(The actual properties of the List) It makes sense why this is, but it was not what I wanted. I wanted to see the actual contained object within the list.

因此,这里是我的复杂的解决方案,从的这个问题

So here is my complicated solution, Taken initially from this question:

我有两个班,我使用动态添加的属性的表单对象到PropertyGrid的绑定列表。第一个(CustomClass)可以在这里下载 。它用于动态创建的属性。我使用的是第二类(DisplayIEnumerable)从第一来源,并可以在这里找到

I have two classes that I am using to dynamically add objects to the propertyGrid bound list in the form of properties. The first(CustomClass) can be downloaded here. It is used to Dynamically create properties. The second class(DisplayIEnumerable) I am using is derived from the first and can be found here.

DisplayIEnumerable类列表循环对象,并增加了一个属性,本身包含的每个对象中的信息。一个DisplayClass传递的定义究竟如何这些对象的属性应该在网格中表示。

The DisplayIEnumerable class loops through the list objects and adds a property to itself with the information contained within the each object. A DisplayClass is passed in to define exactly how those objects properties should be represented within the Grid.

到现在为止一切都很正常!通过这张照片为证(使用提供的类没有创建图片,串在我使用的是类不同的格式,删除格式代码,以帮助你专注于相关代码:

Up to this Point everything works great! as evidenced by this picture(picture was not created using the classes provided, Strings are formatted differently in the classes I am using, removed formatting code to help you focus on the relevant code:

现在后那么长的介绍,真正的问题,利用上述技术,我想编写一个类,它可以动态处理,我没有书面独特的显示类CustomObjects。我打算离开这个代码,使用测试的应用程序的使他们能更有效地测试,而不必为我公司的CustomObjects每一个完整的显示类。(有几百个),而是通过与下面类约束力的PropertyGrid的,我希望能有一切在列表和CustomObjects的属性确实有相应的DisplayClasses在他们的地方被束缚。

Now after that long intro, the real question. Using the techniques above I would like to write a class that can dynamically handle CustomObjects that I have not written unique display classes for. I am intending to leave this code for those using the application for testing so that they can more effectively test without having to have a complete Display Class for every one of my company's CustomObjects. (there are hundreds) Instead, By binding the propertyGrid with the class below, I hope to have all the properties that are lists and CustomObjects that do have corresponding DisplayClasses to be bound in their place.

下面是我已经尝试过,并有一个错误的类。我还没有尝试过实施置换我DisplayIEnumerable班级列表中还没有,我想获得第一份工作的基本功能:

Here is the class that I have already tried and have a bug with. I have not yet tried implementing the replacement of Lists with my DisplayIEnumerable class yet, I wanted to get the basic functionality working first:

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Reflection;
using System.Collections;
using System.Windows.Forms;

   internal class DisplayObject : CustomClass<T>
   {
      #region Variables
      protected T _obj;
      #endregion

      #region Constructor
      public DisplayObject(T obj)
      {
         if (obj != null)
         {
            try
            {
               Type currentType = typeof(T);
               foreach (PropertyInfo propertyInfo in currentType.GetProperties())
               {
                  Attribute[] attributes = new Attribute[1];
                  if (propertyInfo.GetType() is IEnumerable)
                     attributes[0] = new TypeConverterAttribute(typeof(ExpandableObjectConverter));
                  else
                     attributes[0] = null;
                  this.Add(new CustomProperty(propertyInfo.Name, propertyInfo, propertyInfo.GetType(), false, true, attributes));
               }
            }
            catch
            {
               MessageBox.Show("Failure!");
            }
         }
      }
      #endregion

      #region Properties
      [Browsable(false)]
      public object Item
      {
         get { return _obj; }
         set { _obj = value; }
      }
      #endregion
   }

在运行时, PropertyGrid的出现,因为它应该:

When run, The PropertyGrid appears as it should:

然而,一旦你点击展开箭头,没有任何反应,箭头消失:

However, once you click on the Expand arrow, nothing happens, and the arrow disappears:

什么是错的上面说的类是没有错的我DisplayIEnumerable类,导致这种差异的行为?

What is wrong with the class above that is not wrong with my DisplayIEnumerable class, that causes this variance in behaviour?

我使用DisplayObject类这样的(一个DisplayClass内):

I am using the DisplayObject class like this(inside a DisplayClass):

  [TypeConverterAttribute(typeof(ExpandableObjectConverter))]
  public DisplayObject EndJoint { get { if (_member.bcEnd != null) { return new DisplayObject(_member.EndJoint); } else return null; } }



在此先感谢!我会,如果有人使得通过这个问题非常深刻的印象。

Thanks in advance! I will be very impressed if anyone makes it through this question.

推荐答案

您不必创建特殊类使用属性网格。只是装饰用正确的属性的属性。下面是一个例子:

You don't have to create special classes to use the property grid. Just decorate the properties with the proper attributes. Here is an example:

两个自定义类:

public class MyObjType1
{
    public int Id { get; set; }
    public string Name { get; set; }

    public override string ToString()
    {
        return Name;
    }
}

public class MyObjType2
{
    public string Reference { get; set; }

    public override string ToString()
    {
        return Reference;
    }
}

请注意在的ToString 被重写,那是什么属性网格默认情况下使用,如果没有类型转换器是给定类型的定义。

Note the ToString is overriden, that's what the property grid uses by default if no TypeConverter is defined for a given type.

一持有级,有一个集合自定义对象:

One "holder" class that has a collection of custom objects:

public class MyHolder
{
    public MyHolder()
    {
        Objects = new List<object>();
    }

    public string Name { get; set; }

    [TypeConverter(typeof(MyCollectionConverter))]
    public List<object> Objects { get; private set; }
}

请注意自定义的TypeConverter 直接应用到对象属性。这里是源:

Note the custom TypeConverter applied directly to the Objects property. Here is the source:

public class MyCollectionConverter : ExpandableObjectConverter
{
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        IEnumerable enumerable = value as IEnumerable;
        if (enumerable == null)
            return base.GetProperties(context, value, attributes);

        int i = 0;
        List<PropertyDescriptor> list = new List<PropertyDescriptor>();
        foreach (object obj in enumerable)
        {
            MyItemPropertyDescriptor index = new MyItemPropertyDescriptor(i.ToString(), obj);
            list.Add(index);
            i++;
        }
        return new PropertyDescriptorCollection(list.ToArray());
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType != typeof(string))
            return base.ConvertTo(context, culture, value, destinationType);

        IEnumerable enumerable = value as IEnumerable;
        if (enumerable == null)
            return base.ConvertTo(context, culture, value, destinationType);

        StringBuilder sb = new StringBuilder();
        foreach (object obj in enumerable)
        {
            if (sb.Length > 0)
            {
                sb.Append(',');
            }
            sb.AppendFormat("{0}", obj);
        }
        return sb.ToString();
    }
}

请注意,我们覆盖的ConvertTo ,并给它显示一个逗号分隔的列表中的对象列表特殊字符串。在的GetProperties 也被重写,并采用了特殊的的PropertyDescriptor ;它增加了一个 ExpandableObjectConverter 属性的子对象,使他们能够过扩展:

Note we override ConvertTo and give it a special string that displays a comma-separated list of objects in the list. The GetProperties is also overriden and uses a special PropertyDescriptor; It adds an ExpandableObjectConverter attribute to sub objects so they can be expanded too:

public class MyItemPropertyDescriptor : PropertyDescriptor
{
    private object _value;

    public MyItemPropertyDescriptor(string name, object value)
        : base(name, new[] { new TypeConverterAttribute(typeof(ExpandableObjectConverter)) })
    {
        _value = value;
    }

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

    public override object GetValue(object component)
    {
        return _value;
    }

    public override Type PropertyType
    {
        get { return _value == null ? typeof(object) : _value.GetType(); }
    }

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

    public override Type ComponentType
    {
        get { return typeof(object); }
    }

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

    public override void ResetValue(object component)
    {
    }

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

现在,这里是一些样本代码:

Now, here is some sample code:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        MyHolder holder = new MyHolder();
        for (int i = 0; i < 3; i++)
        {
            holder.Objects.Add(new MyObjType1 { Id = i, Name = i + "Name" });
        }
        for (int i = 0; i < 3; i++)
        {
            holder.Objects.Add(new MyObjType2 { Reference = "Ref" + i });
        }
        propertyGrid1.SelectedObject = holder;
    }
}

和结果:

这篇关于定制的,复杂的,动态的思考解决方案 - C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆