2009-06-26 2 views
4

This question (вместе с его ответом) объясняет, почему вы не можете легко привязать DataGridView к типу интерфейса и получить столбцы для свойств, унаследованных от базового интерфейса.Привязка к интерфейсу и отображение свойств в базовом интерфейсе

Предлагаемое решение заключается в реализации пользовательского TypeConverter. Моя попытка ниже. Однако создание DataSource и DataGridView, привязанных к ICamel, по-прежнему приводит только к одному столбцу (Humps). Я не думаю, что мой конвертер используется .NET для определения свойств, которые он может видеть для ICamel. Что я делаю не так?

[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; 
    } 
} 
+0

Два других сообщения, которые могут вам понравиться: http://stackoverflow.com/questions/749542#750481 и http://stackoverflow.com/questions/882214#882246 –

ответ

2

DataGridView не использует TypeConverter; PropertyGrid использует TypeConverter.

Если это относится к элементам управления списком, например DataGridView, тогда другой ответ неверен.

Для обеспечения пользовательских свойств в списке, вам нужно один из:

  • ITypedList на источнике данных
  • TypeDescriptionProvider от типа

Оба нетривиальные.

+0

Спасибо. Невозможно применить 'TypeDescriptionProvider' к интерфейсу, но реализация' ITypedList' в моем источнике данных отлично работает во время выполнения. Видеть мои пользовательские свойства во время разработки было бы неплохо, но я думаю, что я смогу найти обходной путь, которого будет достаточно. – spatulon

0

Мое предложение было бы создать интерфейс, который «переопределяет» в propertys вы хотите:

Допустим, у вас есть два интерфейса:

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 
} 

Теперь, thx для выяснения этого вне, если у вас есть список с объектами конкретного типа HasTwoNames и вы привязываете этот список к dgv, он отображает только элемент (Name2) o f IHasName2.

«обходной путь» А создать новый интерфейс «IHasEverything», который наследует от IHasName2 и, следовательно, от IHasName1 и заново реализует Propertys вам нужно в связывании (вы можете сделать это с новым заявлением

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 не нужно новое ключевое слово.

1

Мой Обход происходит в связывании DGV. мне нужно, что основание интерфейсы и наследующие интерфейсы остаются в одной и той же структуре, просто потому, что я делаю другие вещи шириной конечного класса concerete, а не только отображают данные в DataGridView.Так, например:

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

и класса Gateway:

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(); 

Я получаю DataGridView с единственный столбец IsAdmin bool из интерфейса IOperator, а не идентификатор, ни свойства 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; 

Все работает в правильном направлении.

Таким образом, мне не нужно изменять структуру цепочки intarfaces, полезную для других целей, и только при отображении данных я просто вставляю фрагмент выше.