5

この質問(およびその回答) は、DataGridView をインターフェイス タイプに簡単にバインドして、基本インターフェイスから継承されたプロパティの列を取得できない理由を説明しています。

推奨される解決策は、カスタム TypeConverter を実装することです。私の試みは以下です。ただし、ICamel にバインドされた DataSource と DataGridView を作成しても、結果は 1 つの列 (ハンプ) になります。ICamel のどのプロパティを表示できるかを決定するために、私のコンバーターが .NET によって使用されているとは思いません。私は何を間違っていますか?

[TypeConverter(typeof(MyConverter))]
public interface IAnimal
{
    string Name { get; set; }
    int Legs { get; set; }
}

[TypeConverter(typeof(MyConverter))]
public interface ICamel : IAnimal
{
    int Humps { get; set; }
}

public class MyConverter : TypeConverter
{
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        if(value is Type && (Type)value == typeof(ICamel))
        {
            List<PropertyDescriptor> propertyDescriptors = new List<PropertyDescriptor>();
            foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(typeof(ICamel)))
            {
                propertyDescriptors.Add(pd);
            }
            foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(typeof(IAnimal)))
            {
                propertyDescriptors.Add(pd);
            }
            return new PropertyDescriptorCollection(propertyDescriptors.ToArray());
        }
        return base.GetProperties(context, value, attributes);
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
        return true;
    }
}
4

3 に答える 3

3

DataGridView使用しませんTypeConverterPropertyGridを使用しTypeConverterます。

のようなリストコントロールに関連する場合DataGridView、他の答えは間違っています。

リストにカスタム プロパティを提供するには、次のいずれかが必要です。

  • ITypedListデータソース上
  • TypeDescriptionProviderタイプについて

どちらも自明ではありません。

于 2009-06-26T11:24:08.473 に答える
1

私の回避策は、dgv のバインディングで発生します。DataGridViewにデータを表示するだけでなく、最終的なconcereteクラスで他のことを行うという理由だけで、基本インターフェイスと継承インターフェイスが同じ構造のままである必要があります。たとえば、次のようになります。

interface IGenericPerson
{
    int ID { get; set; }
    string Name { get; set; }
}

interface IOperator : IGenericPerson
{
    bool IsAdmin { get; set; }
}

具体的なクラス:

class Operator : IOperator
{
    public Operator(){}

    public Operator(int id, string name, bool isAdmin)
    {
        this.ID = id;
        this.Name = name;
        thsi.IsAdmin = isAdmin;
    }

    public int ID { get; set; }
    public string name { get; set; }
    public bool IsAdmin { get; set; }
}

およびゲートウェイクラスで:

public IList<IOperator> GetOperators()
{
    IList<IOperator> list = new List<IOperator>();

    list.add(new Operator(112, "Mark Twain", false);
    list.add(new Operator(112, "Charles Manson", false);
    list.add(new Operator(112, "Richard Nixon", true);

    return list;
}

今、次のように datagridView をバインドしようとすると:

Gateway gt = new Gateway();
dgv.DataSource = gt.GetOperators();

IOperator インターフェイスから唯一の bool IsAdmin 列を持つ DataGridView を取得します。ID ではなく、基本インターフェイスから Name プロパティも取得しません。

しかし、私がこれを行うと:

Gateway gt = new Gateway();

IList<IOperator> list = gt.GetOperators();

IList<Operator> ds = new List<Operator>();

foreach(IOperator op in list)
    ds.add((Operator)op);

dgv.DataSource = ds;

すべてが正しい方法で機能します。

このように、インターフェイスチェーンの構造を変更する必要はなく、他の目的に役立ちます。データを表示する場合にのみ、上記のスニペットを挿入するだけです。

于 2011-07-02T11:07:49.370 に答える
0

私の提案は、必要なプロパティを「再実装」するインターフェイスを作成することです。

2 つのインターフェースがあるとします。

public interface IHasName1
{
    String Name1 { get; set; }
}

public interface IHasName2 : IHasName1
{
    String Name2 { get; set; }
}

IHasName2 を実装するクラス:

public class HasTwoNames : IHasName2
{
    #region IHasName1 Member
    public string Name1 { get; set; }
    #endregion

    #region IHasName2 Member
    public string Name2 {get; set; }
    #endregion
}

さて、具体的なタイプ HasTwoNames のオブジェクトを含む List があり、そのリストを dgv にバインドすると、IHasName2 のメンバー (Name2) のみが表示されます。

「回避策」は、IHasName2、したがって IHasName1 から継承し、バインディングで必要なプロパティを再実装する新しいインターフェイス「IHasEverything」を作成することです (新しいステートメントでそれを行うことができます)。

public interface IHasEverything : IHasName2
{
    new String Name1 { get; set; }
    new String Name2 { get; set; }
}

具象クラス「HasTwoNames」も IHasEverything を実装する必要があります。

public class HasTwoNames : IHasName2, IHasEverything
{
    ...
}

このリストを datagridview にバインドできます。

    public List<IHasEverything> elements = new List<IHasEverything> {
        new HasTwoNames { Name1 = "Name1", Name2 = "Name2"},
        new HasTwoNames { Name1 = "Name3", Name2 = "Name4"},
    };

これは単なる回避策であり、実装クラスを変更できる場合にのみ可能であることはわかっています。しかし、それは機能します。(IHasName2 からプロパティを削除しても、コードはコンパイルされますが、IHasEverything には新しいキーワードが必要ないという警告が表示されます。

于 2009-06-26T13:13:28.347 に答える