0

プロパティグリッドにいくつかのメンバー(それぞれが独自のクラス)を持つクラスを表示しています。私は次の状況にあります(簡略化すると、これは実際の設計やクラスではありません):

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、読み取りが成功した場合は各メンバーが展開可能であり、そうでない場合はエラーコード(文字列のみ)が表示されます。

何か案は?

4

2 に答える 2

2

ExpandableObjectConverterに基づいて独自のTypeConverterを実装すれば、おそらくこのケースを処理できると思います。たとえば。Data2のデータを取得できないため、Data2はNullになると想定しています。独自のコンバーターを使用してグリッドにプロパティを表示できますが、その前に「エラー」というテキストをどのように表示するのでしょうか。基本的に、Expandableオブジェクトの場合、クラスのToString()を使用して、グループ内のオブジェクトに対してテキストを表示します。

私はあなたが使用できるハックを持っています、最もエレガントな解決策ではないかもしれませんが、それがうまくいくことを願っています...あなたができることはあなたのクラスに表示されますあなたのクラスがこのようなものになるように別のプロパティを追加します...

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
}

(上記のクラスにはセッターがありませんが、どのようにそれらを設定するのか疑問に思っていましたが、それは部分的なコードである可能性があります)

ここで、このクラスのオブジェクトにデータを入力し、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に表示されます。これを行うには、リフレクションを使用して属性「Browsable」を取得し、そのプロパティを設定します。

于 2012-07-26T08:15:25.203 に答える
2

Arifが提案したように、ExpandableObjectConverterに基づいて独自のTypeConverterを作成することになりました。私の解決策はやや単純でした(私は思います)。

私は変更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;
    }
}

このように、コンバーター自体が読み取られたデータオブジェクトを照会し、エラーコードがあったかどうかに基づいてそれを表示する方法を決定します。

もちろん、より多くのコードが関係しています(必要に応じて関連するエラーコードを設定するなど)が、それが主なアイデアです。

于 2012-07-26T15:07:20.467 に答える