9

私が使用している多くのカスタム クラスがあり、それらについて説明し、例を投稿します。それらがすべて何をするかを説明した後、バグが発生する条件を明確に説明しようとします。

まず、PropertyGrid を使用して、さまざまな種類のオブジェクトのプロパティを表示しています。PropertyGrid の既定のバインドは、私が望んでいたほど説明的ではなかったため、「表示」クラスと呼ぶカスタム クラスをいくつか作成しました。これらの Display クラスは、オブジェクトを渡し、適切にフォーマットされた文字列と、渡された実際のオブジェクトのパブリック プロパティ (場合によってはメソッド) の説明を返すプロパティを作成することによって構築されます。

いくつかの簡略化されたサンプル コードを使用してこれを示します。

これは、PropertyGrid に表示したいオブジェクトの例です。

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

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

文字列プロパティ "Name" は PropertyGrid に正常に表示されますが、CustomObject と List は非常にユーザー フレンドリーに表示されませんでした。

だから私はこのクラスを書くことによって解決策を作成しようとしました:

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;}
}

上記のコードでわかるように、Joint クラスと CustomObject クラスの両方に特別な DisplayClasses を作成しました。私のプロジェクトには、同じ種類の重複する表示クラス プロパティを必要とする非常に多くの異なる種類のオブジェクトがあります。

上に、最後の 2 つのプロパティの上に追加した行が表示されます。

[TypeConverterAttribute(typeof(ExpandableObjectConverter))]

この行は、properGrid で希望する方法で CustomObject を表示するという私の問題を解決します (ほとんど... これについては後で詳しく説明します)。ただし、カスタム リスト プロパティでは同じようには機能しません。カスタム リストでは、カウントと容量 (リストの実際のプロパティ) のみを表示するように展開されます。これは理にかなっていますが、私が望んでいたものではありませんでした。リスト内に実際に含まれているオブジェクトを見たかったのです。

ここに画像の説明を入力

だからここに私の複雑な解決策があります。最初にこの質問から取られました:

プロパティの形式でプロパティ グリッドのバインドされたリストにオブジェクトを動的に追加するために使用している 2 つのクラスがあります。最初の (CustomClass) は、ここからダウンロードできます。プロパティを動的に作成するために使用されます。私が使用している 2 番目のクラス (DisplayIEnumerable) は最初のクラスから派生したもので、ここで見つけることができます。

DisplayIEnumerable クラスはリスト オブジェクトをループ処理し、各オブジェクトに含まれる情報を使用してプロパティを自身に追加します。これらのオブジェクトのプロパティをグリッド内でどのように表現するかを正確に定義するために、DisplayClass が渡されます。

この時点まで、すべてがうまく機能しています!この写真で証明されているように (写真は提供されたクラスを使用して作成されたものではありません。使用しているクラスでは文字列の形式が異なります。関連するコードに集中できるように、書式設定コードを削除しました。

ここに画像の説明を入力

長いイントロの後、本当の質問です。上記の手法を使用して、独自の表示クラスを作成していない CustomObjects を動的に処理できるクラスを作成したいと考えています。このコードは、アプリケーションをテスト用に使用する人のために残して、会社の CustomObjects ごとに完全な表示クラスを用意しなくても、より効果的にテストできるようにするつもりです。(数百あります) 代わりに、propertyGrid を以下のクラスにバインドすることで、リストであるすべてのプロパティと、対応する DisplayClasses をその場所にバインドする CustomObjects を取得したいと考えています。

これは、私がすでに試してバグがあるクラスです。Lists を DisplayIEnumerable クラスに置き換える実装はまだ試していません。基本的な機能を最初に動作させたかったのです。

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 は次のように表示されます。 前

ただし、展開矢印をクリックすると、何も起こらず、矢印が消えます。 後

私の DisplayIEnumerable クラスでは間違っていない上記のクラスの何が問題なのですか?

私はこのようなDisplayObjectクラスを使用しています(DisplayClass内):

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

前もって感謝します!誰かがこの問題を解決できれば、私は非常に感銘を受けます。

4

2 に答える 2

6

プロパティ グリッドを使用するために特別なクラスを作成する必要はありません。プロパティを適切な属性で装飾するだけです。以下に例を示します。

2 つのカスタム クラス:

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は、特定の型に対して TypeConverter が定義されていない場合にプロパティ グリッドがデフォルトで使用するものです。

カスタム オブジェクトのコレクションを持つ 1 つの「ホルダー」クラス:

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に直接適用されたカスタムに注意してください。Objectsソースは次のとおりです。

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サブオブジェクトも展開できるようにします。

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)
    {
    }
}

さて、ここにいくつかのサンプルコードがあります:

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;
    }
}

そして結果:

ここに画像の説明を入力

于 2012-08-10T14:47:54.460 に答える
1

TypeConverters を自分で使用したことがありますが、それらが底部の大きな問題であることを確認できます。実際に何がうまくいかないかについてのnada情報を取得しますが、奇妙な出力のみです...

それが役立つかどうかはわかりますが、空の(null)配列をIEnumerableではないものに追加するのは問題かもしれませんか?add 命令を if (...) のスコープに移動してみてください。そこに害があるとは思えません。

また、(EndJoint を使用した最後の例で) getter が null ポインターを返さないことは確かですか? 空のエントリは、私の経験から渡された null ポインターのようなにおいがします。

于 2012-08-08T15:19:15.457 に答える