DataGridView在运行时更改显示

时间:2012-07-25 19:24:25

标签: c# winforms .net-4.0 datagridview propertygrid

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

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>

有什么想法吗?

2 个答案:

答案 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建议的那样。 我的解决方案有点简单(我认为)。

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

这样,转换器本身会查询读取的数据对象,并根据是否存在错误代码来决定如何显示它。

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