我在属性网格中显示一个包含几个成员的类(每个类都是它自己的类)。 我有以下情况(简化,这不是实际的设计和/或类):
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; }
}
您可以看到的每个成员(Data1,Data2)都显示为可扩展对象,因此我可以看到其所有成员。
现在,问题是: 这些数据类中的每一个都与远程源分开读取,每次读取都可能失败(具有特定错误)。
我希望能够在属性网格中显示组合对象(DisplayedData
),其中如果读取成功,每个成员都可以展开,否则显示错误代码(只是一个字符串)。 / p>
有什么想法吗?
答案 0 :(得分:2)
我认为如果您基于ExpandableObjectConverter实现自己的TypeConverter,您可以处理这种情况。例如。假设您无法获取Data2的数据,因此我假设Data2将为Null。您可以使用自己的转换器在网格中显示属性,但我想知道如何在它前面显示文本说“错误”。基本上对于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
}
(上面的类没有setters我想知道如何填充它们,但那可能是部分代码)
现在,当您在此类的对象中填充数据时,您会发现无法读取Data2的值,因此Data2为Null。然后你写这个......
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
基本上在运行时我们试图隐藏属性Data2并显示属性Data2Error,这两个属性都具有相同的显示名称,因此在propertygrid中显示相同的名称。要做到这一点,我们使用反射并获取属性“可浏览”并设置其属性。
答案 1 :(得分:2)
我最终基于ExpandableObjectConverter创建了自己的TypeConverter,正如Arif建议的那样。 我的解决方案有点简单(我认为)。
我将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;
}
}
这样,转换器本身会查询读取的数据对象,并根据是否存在错误代码来决定如何显示它。
当然还有更多的代码(例如在需要时设置相关的错误代码等),但这是主要的想法。