DataGridView在运行时更改显示器

问题描述:

我在属性网格中显示一个有几个成员(每个都是它自己的类)的类。 我有以下的情况(简化的,这是不实际的设计和/或类):DataGridView在运行时更改显示器

public class DataType1 
{ 
    public int Value1 { get; } 
    public int Value2 { get; } 
} 

public class DataType2 
{ 
    public int ValueA { get; } 
    public int ValueB { get; } 
} 

public class DisplayedData 
{ 
    [TypeConverter(typeof(ExpandableObjectConverter))] 
    [ReadOnly(true)] 
    public DataType1 Data1 { get; } 

    [TypeConverter(typeof(ExpandableObjectConverter))] 
    [ReadOnly(true)] 
    public DataType2 Data2 { get; } 
} 

每个成员(数据1,数据2),你可以看到,被显示为可扩张的对象,所以我可以看到所有的成员。

现在,问题是这样的: 这些数据类中的每一个都是从远端源单独读取的,每个读取可能会失败(带有特定错误)。

我希望能够在属性网格中显示组合对象(DisplayedData),其中每个成员在读取成功时可以展开,否则显示错误代码(只是一个字符串)。

任何想法?

我最终创建了自己的TypeConverter,基于Arif建议的ExpandableObjectConverter。 我的解决方案比较简单(我认为)。

我改变了DataType1DataType2从相同的基类(我们称之为BaseDataType),它保存错误代码(以及是否有错误)。

然后在我的类型转换器,我做这样的事情(再次,简化):

public class MyDynamicTypeConverter : ExpandableObjectConverter 
{ 
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
    { 
     if (destinationType.Equals(typeof(string))) 
     { 
      BaseDataType baseDisplay = GetBaseDisplay(context); 
      if (baseDisplay.ReadFailed) 
      { 
       // Display the error message 
       return baseDisplay.ErrorMessageReadFailed; 
      } 
     } 
     return base.ConvertTo(context, culture, value, destinationType); 
    } 

    public override bool GetPropertiesSupported(ITypeDescriptorContext context) 
    { 
     BaseDataType baseDisplay = GetBaseDisplay(context); 
     if (baseDisplay.ReadFailed) 
     { 
      // If read failed, do not expand the display for this object 
      return false; 
     } 
     return base.GetPropertiesSupported(context); 
    } 

    private BaseDataType GetBaseDisplay(ITypeDescriptorContext context) 
    { 
     // Extract base data type using reflections 
     object obj = context.Instance.GetType().GetProperty(context.PropertyDescriptor.Name).GetValue(context.Instance, null); 
     return (BaseDataType)obj; 
    } 
} 

这样,变频器本身查询读取的数据对象,并决定如何根据是否有一个来显示它错误代码。

当然还有更多的代码(比如在需要时设置相关的错误代码等),但这是主要思想。

我想如果你基于ExpandableObjectConverter实现你自己的TypeConverter,你可能可以处理这种情况。例如。说你无法获取Data2的数据,所以我假设Data2将是空值。你可以使用你自己的转换器在网格中显示属性,但是我想知道你将如何显示文本在它前面显示“Error”。基本上对于Expandable对象,该类的ToString()用于在组中显示文本。

我有一个黑客,你可以使用,可能不是最优雅的解决方案,但我希望它可以工作... 你可以做什么是在你的类DisplayedData添加另一个属性,使你的类变得像这样...

public class DisplayedData 
{ 
    [TypeConverter(typeof(ExpandableObjectConverter))] 
    [ReadOnly(true)] 
    public DataType1 Data1 { get; } 

    [TypeConverter(typeof(ExpandableObjectConverter))] 
    [ReadOnly(true)] 
    [DisplayName("Data2")] 
    [Browsable(true)] 
    public DataType2 Data2 { get; } //We have Browsable set to true for this 

    [DisplayName("Data2")] 
    [Browsable(false)] 
    public string Data2Error { get; } //An additional property with Browsable set to false 
} 

(上面的类有没有setter方法我想知道你将如何对其进行填充,但随后可能是部分代码)

现在,当你在这个类的对象来填充数据并且您看到您无法读取Data2的值,因此Data2为空。然后,你写这个...

if (data.Data2 == null)//data is an object of DisplayedData class that we are showing in PropertyGrid 
     { 
      PropertyDescriptor descriptor = TypeDescriptor.GetProperties(data.GetType())["Data2"]; 
      BrowsableAttribute attribute = (BrowsableAttribute)descriptor.Attributes[typeof(BrowsableAttribute)]; 
      FieldInfo fieldToChange = attribute.GetType().GetField("Browsable", 
            BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Public | 
            BindingFlags.Instance); 
      fieldToChange.SetValue(attribute, false); 

      data.Data2Error = "Error"; 
      descriptor = TypeDescriptor.GetProperties(data.GetType())["Data2Error"]; 
      attribute = (BrowsableAttribute)descriptor.Attributes[typeof(BrowsableAttribute)]; 
      fieldToChange = attribute.GetType().GetField("Browsable", 
            BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Public | 
            BindingFlags.Instance); 
      fieldToChange.SetValue(attribute, true); 
     } 

     propertyGrid1.SelectedObject = data; //Reassign object to PropertyGrid 

基本上在运行时,我们正试图隐藏属性数据2和显示属性Data2Error,这两个属性具有相同的显示名称,以便为同名PropertyGrid中所示。要做到这一点,我们使用反射并获得“Browsable”属性并设置其属性。

+0

适用于想法和代码示例。我最终做了一些与众不同的事情。很快就会发布答案。 – Asaf 2012-07-26 14:57:26