2015-09-21 30 views
1

我试图使用DataGridView来显示对象列表。 在我想呈现属性的类中,我有一些C#属性,并且我也想动态地创建属性,原因有些。试图将DataGridView与ICustomTypeDescriptor一起使用

这里我有一个例子,它适用于C#属性(FeatureId),但动态创建的属性(Name)返回所有实例的第一个实例的值。 为什么?

首先实现了ICustomPropertyDescriptor接口的类

public abstract class PropertyPresentationSubBase : ICustomTypeDescriptor 
{ 
public String GetClassName() 
{ 
    return TypeDescriptor.GetClassName(this, true); 
} 

public AttributeCollection GetAttributes() 
{ 
    return TypeDescriptor.GetAttributes(this, true); 
} 

public String GetComponentName() 
{ 
    return TypeDescriptor.GetComponentName(this, true); 
} 

public TypeConverter GetConverter() 
{ 
    return TypeDescriptor.GetConverter(this, true); 
} 

public EventDescriptor GetDefaultEvent() 
{ 
    return TypeDescriptor.GetDefaultEvent(this, true); 
} 

public PropertyDescriptor GetDefaultProperty() 
{ 
    return TypeDescriptor.GetDefaultProperty(this, true); 
} 

public object GetEditor(Type editorBaseType) 
{ 
    return TypeDescriptor.GetEditor(this, editorBaseType, true); 
} 

public EventDescriptorCollection GetEvents(Attribute[] attributes) 
{ 
    return TypeDescriptor.GetEvents(this, attributes, true); 
} 

public EventDescriptorCollection GetEvents() 
{ 
    return TypeDescriptor.GetEvents(this, true); 
} 


public virtual PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
{ 
    PropertyDescriptorCollection rtn = TypeDescriptor.GetProperties(this); 

    //rtn = FilterReadonly(rtn, attributes); 

    return new PropertyDescriptorCollection(rtn.Cast<PropertyDescriptor>().ToArray()); 


} 

public virtual PropertyDescriptorCollection GetProperties() 
{ 

    return TypeDescriptor.GetProperties(this, true); 

} 


public object GetPropertyOwner(PropertyDescriptor pd) 
{ 
    return this; 
} 

[Browsable(false)] 
public PropertyPresentationSubBase Parent 
{ 
    get 
    { 
    return m_Parent; 
    } 
    set 
    { 
    m_Parent = value; 
    } 
} 

PropertyPresentationSubBase m_Parent = null; 

[Browsable(false)] 
public Type ValueType 
{ 
    get 
    { 
    return valueType; 
    } 
    set 
    { 
    valueType = value; 
    } 
} 

private Type valueType = null; 

[Browsable(false)] 
public string Name 
{ 
    get 
    { 
    return sName; 
    } 
    set 
    { 
    sName = value; 
    } 
} 



public abstract object GetValue(); 

private string sName = string.Empty; 

public abstract void Change(object value); 


    } 
} 

我还具有从的PropertyDescriptor

public class MyCustomPropertyDescriptor : PropertyDescriptor 
{ 
PropertyPresentationSubBase m_Property; 

public MyCustomPropertyDescriptor(PropertyPresentationSubBase myProperty, Attribute[] attrs, int propertyNo) 
    : base(myProperty.Name + propertyNo, attrs) 
{ 
    m_Property = myProperty; 
} 

#region PropertyDescriptor specific 

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

public override string Name 
{ 
    get 
    { 
    return "MyName"; 
    } 
} 

public override Type ComponentType 
{ 
    get 
    { 
    return null; 
    } 
} 

public override object GetValue(object component) 
{ 
    return m_Property.GetValue(); 
} 


public override string Description 
{ 
    get 
    { 
    return "Description"; 
    } 
} 



public object Value 
{ 
    get 
    { 
    return m_Property; 
    } 
} 


public override string Category 
{ 
    get 
    { 
    return "Category"; 
    } 
} 

public override string DisplayName 
{ 
    get 
    { 
    return m_Property.Name; 
    } 

} 


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


public override void ResetValue(object component) 
{ 
    //Have to implement 
} 

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




public override void SetValue(object component, object value) 
{ 
    m_Property.Change(value); 
} 

public override Type PropertyType 
{ 

    get 
    { 
    if ((m_Property != null) && (m_Property.ValueType != null)) 
    { 
     return m_Property.ValueType; 
    } 
    else 
    { 
     return System.Type.Missing.GetType(); 

    } 
    } 
} 

#endregion 

}

保存数据的小型类继承的类:

public class QuadriFeatureItem 
{ 
public QuadriFeatureItem(int featureId, string name) 
{ 
    m_featureId = featureId; 
    m_name = name; 

} 
public int m_featureId; 

public string m_name; 
} 

我的类被发送到网格(同时含有FEATUREID属性和动态创建的属性)

class FeaturePropertyPresentation : PropertyPresentationSubBase 
{ 

public int FeatureId 
{ 
    get 
    { 
    return m_feature.m_featureId; 

    } 
    set { m_feature.m_featureId = value; } 
} 

public FeaturePropertyPresentation(QuadriFeatureItem item) 
{ 
    m_feature = item; 
} 

private QuadriFeatureItem m_feature; 

public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
{ 
    PropertyDescriptorCollection rtn = base.GetProperties(attributes); 

    CreateNameAttribute(ref rtn, attributes); 

    return rtn; 

} 

private void CreateNameAttribute(ref PropertyDescriptorCollection pdc, Attribute[] attributes) 
{ 

    NameProperty namePres = null; 
    namePres = new NameProperty(m_feature, this); 

    pdc.Add(new MyCustomPropertyDescriptor(namePres, attributes, pdc.Count)); 

} 

public override void Change(object value) 
{ 
    throw new NotImplementedException(); 
} 

public override object GetValue() 
{ 
    return this; 
} 

}

实现该nameproperty一类:

class NameProperty : PropertyPresentationSubBase 
{ 

public NameProperty(QuadriFeatureItem feature, FeaturePropertyPresentation parent) 
    : base() 
{ 
    m_quadriFeatureItem = feature; 
    Parent = parent; 
    ValueType = typeof(string); 

} 

private QuadriFeatureItem m_quadriFeatureItem; 

public override void Change(object value) 
{ 
    m_quadriFeatureItem.m_name = (string)value; 
} 

public override object GetValue() 
{ 

    return m_quadriFeatureItem.m_name; 

} 

} 

而我的表单代码:

public Form1() 
{ 
    InitializeComponent(); 

    ShowGrid(); 
} 

private void ShowGrid() 
{ 

    QuadriFeatureItem no1 = new QuadriFeatureItem(1, "Nummer1"); 
    QuadriFeatureItem no2 = new QuadriFeatureItem(2, "Nummer2"); 
    QuadriFeatureItem no3 = new QuadriFeatureItem(3, "Nummer3"); 

    BindingSource source = new BindingSource(); 

    FeaturePropertyPresentation no1Pres = new FeaturePropertyPresentation(no1); 
    FeaturePropertyPresentation no2Pres = new FeaturePropertyPresentation(no2); 
    FeaturePropertyPresentation no3Pres = new FeaturePropertyPresentation(no3); 

    source.Add(no1Pres); 
    source.Add(no2Pres); 
    source.Add(no3Pres); 

    dataGridView1.DataSource = source; 

    Show();  
} 

但网格对所有行显示“Nummer1”。为什么?我在PropertyGrid中使用这个表示类,它工作正常。我也在PropertyGrid中使用这个MyCustomPropertyDescriptor。

我希望现在能够在datagridview中重用这个presentationclasses和MyCustomPropertyDescriptor。是否可以在MyCustomPropertyDescriptor或PropertyPresentationSubBase中进行任何修改?

+0

也许它与'ICustomTypeDescriptor'的实现有关,所以最好发布你的实现。 –

+0

这绝对是可能的,但你需要展示你的实现。 –

+0

如何显示“MyCustomPropertyDescriptor”的代码?看,如果你需要帮助,你需要向我们提供足够的信息。我只能说目前的问题在于你的代码。 –

回答

0

问题是您的自定义属性描述符绑定到具体实例。当您使用单个项目数据绑定(如TextBox到您的对象属性或在PropertyGrid控件中选择您的对象)时,这起作用。但是,当您使用控件需要列表数据绑定(如DataGridView,ListView,ListBox,ComboBox列表等)此技术不起作用。为了自动填充列,DataGridView需要一组属性通用到所有项目。为了做到这一点,它尝试了几种方法来获取这些信息(可以在这里找到一个很好的解释DataGridView not showing properites of objects which implement ICustomTypeDescriptor),其中一个方法是获取列表中的第一项并询问属性(因此可以调试您的调试体验)。无论如何,为了使这个工作在列表绑定方案中,你的属性描述符需要以不同的方式实现。

请注意PropertyDescriptor s GetValue/SetValue方法的签名。他们都有一个参数object component。这是您需要返回或设置值的对象实例。你可以将属性描述符想象成与我们通常在编程语言中使用的反例。因此,而不是

var val = obj.Property; 
obj.Property = val; 

我们

var val = propertyDescriptor.GetValue(obj); 
propertyDescriptor.SetValue(obj, val); 

换句话说,你不应该“嵌入”的属性描述符中的对象实例,但使用传递的参数。

下面是一个简单通用的实现属性描述的正是这样做的:用你的东西

public class SimplePropertyDescriptor<TComponent, TValue> : PropertyDescriptor 
    where TComponent : class 
{ 
    private readonly Func<TComponent, TValue> getValue; 
    private readonly Action<TComponent, TValue> setValue; 
    private readonly string displayName; 
    public SimplePropertyDescriptor(string name, Attribute[] attrs, Func<TComponent, TValue> getValue, Action<TComponent, TValue> setValue = null, string displayName = null) 
     : base(name, attrs) 
    { 
     Debug.Assert(getValue != null); 
     this.getValue = getValue; 
     this.setValue = setValue; 
     this.displayName = displayName; 
    } 
    public override string DisplayName { get { return displayName ?? base.DisplayName; } } 
    public override Type ComponentType { get { return typeof(TComponent); } } 
    public override bool IsReadOnly { get { return setValue == null; } } 
    public override Type PropertyType { get { return typeof(TValue); } } 
    public override bool CanResetValue(object component) { return false; } 
    public override bool ShouldSerializeValue(object component) { return false; } 
    public override void ResetValue(object component) { } 
    public override object GetValue(object component) { return getValue((TComponent)component); } 
    public override void SetValue(object component, object value) { setValue((TComponent)component, (TValue)value); } 
} 

示例用法:

public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
{ 
    var properties = base.GetProperties(attributes); 
    // Custom name property 
    properties.Add(new SimplePropertyDescriptor<FeaturePropertyPresentation, string>("FeatureName", attributes, 
     getValue: component => component.m_feature.m_name, 
     setValue: (component, value) => component.m_feature.m_name = value, // remove this line to make it readonly 
     displayName: "Feature Name" 
    )); 
    return properties; 
} 

,并把他们放在一起,一个相当于小例子你的:

using System; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.Linq; 
using System.Windows.Forms; 

namespace Samples 
{ 
    // Generic implemenation of a property descriptor 
    public class SimplePropertyDescriptor<TComponent, TValue> : PropertyDescriptor 
     where TComponent : class 
    { 
     private readonly Func<TComponent, TValue> getValue; 
     private readonly Action<TComponent, TValue> setValue; 
     private readonly string displayName; 
     public SimplePropertyDescriptor(string name, Attribute[] attrs, Func<TComponent, TValue> getValue, Action<TComponent, TValue> setValue = null, string displayName = null) 
      : base(name, attrs) 
     { 
      Debug.Assert(getValue != null); 
      this.getValue = getValue; 
      this.setValue = setValue; 
      this.displayName = displayName; 
     } 
     public override string DisplayName { get { return displayName ?? base.DisplayName; } } 
     public override Type ComponentType { get { return typeof(TComponent); } } 
     public override bool IsReadOnly { get { return setValue == null; } } 
     public override Type PropertyType { get { return typeof(TValue); } } 
     public override bool CanResetValue(object component) { return false; } 
     public override bool ShouldSerializeValue(object component) { return false; } 
     public override void ResetValue(object component) { } 
     public override object GetValue(object component) { return getValue((TComponent)component); } 
     public override void SetValue(object component, object value) { setValue((TComponent)component, (TValue)value); } 
    } 
    // Your stuff 
    public abstract class PropertyPresentationSubBase : ICustomTypeDescriptor 
    { 
     public string GetClassName() 
     { 
      return TypeDescriptor.GetClassName(this, true); 
     } 

     public AttributeCollection GetAttributes() 
     { 
      return TypeDescriptor.GetAttributes(this, true); 
     } 

     public String GetComponentName() 
     { 
      return TypeDescriptor.GetComponentName(this, true); 
     } 

     public TypeConverter GetConverter() 
     { 
      return TypeDescriptor.GetConverter(this, true); 
     } 

     public EventDescriptor GetDefaultEvent() 
     { 
      return TypeDescriptor.GetDefaultEvent(this, true); 
     } 

     public PropertyDescriptor GetDefaultProperty() 
     { 
      return TypeDescriptor.GetDefaultProperty(this, true); 
     } 

     public object GetEditor(Type editorBaseType) 
     { 
      return TypeDescriptor.GetEditor(this, editorBaseType, true); 
     } 

     public EventDescriptorCollection GetEvents(Attribute[] attributes) 
     { 
      return TypeDescriptor.GetEvents(this, attributes, true); 
     } 

     public EventDescriptorCollection GetEvents() 
     { 
      return TypeDescriptor.GetEvents(this, true); 
     } 

     public virtual PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
     { 
      PropertyDescriptorCollection rtn = TypeDescriptor.GetProperties(this); 

      //rtn = FilterReadonly(rtn, attributes); 

      return new PropertyDescriptorCollection(rtn.Cast<PropertyDescriptor>().ToArray()); 
     } 

     public virtual PropertyDescriptorCollection GetProperties() 
     { 

      return TypeDescriptor.GetProperties(this, true); 

     } 


     public object GetPropertyOwner(PropertyDescriptor pd) 
     { 
      return this; 
     } 

     [Browsable(false)] 
     public PropertyPresentationSubBase Parent 
     { 
      get 
      { 
       return m_Parent; 
      } 
      set 
      { 
       m_Parent = value; 
      } 
     } 

     PropertyPresentationSubBase m_Parent = null; 

     [Browsable(false)] 
     public Type ValueType 
     { 
      get 
      { 
       return valueType; 
      } 
      set 
      { 
       valueType = value; 
      } 
     } 

     private Type valueType = null; 

     [Browsable(false)] 
     public string Name 
     { 
      get 
      { 
       return sName; 
      } 
      set 
      { 
       sName = value; 
      } 
     } 



     public abstract object GetValue(); 

     private string sName = string.Empty; 

     public abstract void Change(object value); 
    } 
    public class QuadriFeatureItem 
    { 
     public QuadriFeatureItem(int featureId, string name) 
     { 
      m_featureId = featureId; 
      m_name = name; 

     } 
     public int m_featureId; 

     public string m_name; 
    } 
    class FeaturePropertyPresentation : PropertyPresentationSubBase 
    { 

     public int FeatureId 
     { 
      get 
      { 
       return m_feature.m_featureId; 

      } 
      set { m_feature.m_featureId = value; } 
     } 

     public FeaturePropertyPresentation(QuadriFeatureItem item) 
     { 
      m_feature = item; 
     } 

     private QuadriFeatureItem m_feature; 

     public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
     { 
      var properties = base.GetProperties(attributes); 
      // Custom name property 
      properties.Add(new SimplePropertyDescriptor<FeaturePropertyPresentation, string>("FeatureName", attributes, 
       getValue: component => component.m_feature.m_name, 
       setValue: (component, value) => component.m_feature.m_name = value, // remove this line to make it readonly 
       displayName: "Feature Name" 
      )); 
      return properties; 
     } 
     public override void Change(object value) 
     { 
      throw new NotImplementedException(); 
     } 

     public override object GetValue() 
     { 
      return this; 
     } 

    } 
    // Test 
    static class Test 
    { 
     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      var dataSet = Enumerable.Range(1, 10).Select(n => new FeaturePropertyPresentation(new QuadriFeatureItem(n, "Nummer" + n))).ToList(); 
      var form = new Form(); 
      var dg = new DataGridView { Dock = DockStyle.Fill, Parent = form }; 
      dg.DataSource = dataSet; 
      Application.Run(form); 
     } 
    } 
} 

结果:

enter image description here

相关问题