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。 我的解决方案比较简单(我认为)。
我改变了DataType1
和DataType2
从相同的基类(我们称之为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”属性并设置其属性。
适用于想法和代码示例。我最终做了一些与众不同的事情。很快就会发布答案。 – Asaf 2012-07-26 14:57:26