条件付き「閲覧可能」属性
-
11-10-2019 - |
質問
「閲覧可能な」属性を条件とする方法はありますか?それを適用するプロパティは、プロパティページに表示されることがありますか?
ありがとう :)
解決
簡単な方法はありません。
iCustomtypedescriptorを実装することで、これを解決できます。これが良い記事です icustomtypedescriptorの実装.
または、あなた自身を関連付けることができます componloldesigner あなたのクラスで、そしてオーバーライドします PrefilterProperties プロパティグリッドに表示されているプロパティを追加または削除する方法。
他のヒント
これがあなたの状況に当てはまるかどうかはわかりませんが、以下の関数に電話して、実行時に「眉間」装飾を調整できます。
/// <summary>
/// Set the Browsable property.
/// NOTE: Be sure to decorate the property with [Browsable(true)]
/// </summary>
/// <param name="PropertyName">Name of the variable</param>
/// <param name="bIsBrowsable">Browsable Value</param>
private void setBrowsableProperty(string strPropertyName, bool bIsBrowsable)
{
// Get the Descriptor's Properties
PropertyDescriptor theDescriptor = TypeDescriptor.GetProperties(this.GetType())[strPropertyName];
// Get the Descriptor's "Browsable" Attribute
BrowsableAttribute theDescriptorBrowsableAttribute = (BrowsableAttribute)theDescriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo isBrowsable = theDescriptorBrowsableAttribute.GetType().GetField("Browsable", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
// Set the Descriptor's "Browsable" Attribute
isBrowsable.SetValue(theDescriptorBrowsableAttribute, bIsBrowsable);
}
これは、カスタムタイプモデルを提供することで行うことができます。で 最も簡単です レベルでは、カスタムを提供できます TypeDescriptor
派生したタイプのために ExpandableObjectConverter
, 、そして単に与えられたプロパティを気まぐれに含める/除外しますが、これはでのみ機能します PropertyGrid
- プロパティページで使用。より複雑なアプローチは使用することです ICustomTypeDescriptor
/ TypeDescriptionProvider
- これは、ような内部で動作する可能性があります DataGridView
上記の @Neoikonの回答の改善とコメントで言及されている例外を回避するために、ここにジェネリックを使用してタイプを取得するバージョンがあります。
/// <summary>
/// Set the Browsable property.
/// NOTE: Be sure to decorate the property with [Browsable(true)]
/// </summary>
/// <param name="PropertyName">Name of the variable</param>
/// <param name="bIsBrowsable">Browsable Value</param>
private void SetBrowsableProperty<T>(string strPropertyName, bool bIsBrowsable)
{
// Get the Descriptor's Properties
PropertyDescriptor theDescriptor = TypeDescriptor.GetProperties(typeof(T))[strPropertyName];
// Get the Descriptor's "Browsable" Attribute
BrowsableAttribute theDescriptorBrowsableAttribute = (BrowsableAttribute)theDescriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo isBrowsable = theDescriptorBrowsableAttribute.GetType().GetField("Browsable", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
// Set the Descriptor's "Browsable" Attribute
isBrowsable.SetValue(theDescriptorBrowsableAttribute, bIsBrowsable);
}
その後、インスタンスを取得するバージョンを追加することもできます。
/// <summary>
/// Set the Browsable property.
/// NOTE: Be sure to decorate the property with [Browsable(true)]
/// </summary>
/// <param name="obj">An instance of the object whose property should be modified.</param>
/// <param name="PropertyName">Name of the variable</param>
/// <param name="bIsBrowsable">Browsable Value</param>
private void SetBrowsableProperty<T>(T obj, string strPropertyName, bool bIsBrowsable)
{
SetBrowsableProperty<T>(strPropertyName, bIsBrowsable);
}
使用法:
class Foo
{
[Browsable(false)]
public string Bar { get; set; }
}
void Example()
{
SetBrowsableProperty<Foo>("Bar", true);
Foo foo = new Foo();
SetBrowsableProperty(foo, "Bar", false);
}
特定のメンバーをIntellisenseに見えるまたは隠していることを宣言し、コンパイル時に隠されるために必要なすべてのために一度変更できる方法を求めてこれに出会いました。それがあなたが探していたものかどうかはわかりませんが、私の質問に対する答えを見つけました...共有することは害がないと思いました。
条件付きコンパイルシンボル(プロジェクトプロパティのビルドタブにある)is_vis(特定のメンバーに表示する場合は真の値である値、falseを非表示にしたい場合はfalse)を設定します。
#if IS_VIS
public const System.ComponentModel.EditorBrowsableState isVis =
ComponentModel.EditorBrowsableState.Always;
#else
public const System.ComponentModel.EditorBrowsableState isVis =
ComponentModel.EditorBrowsableState.Never;
#endif
次に、属性のISVIS変数を参照してください。
[EditorBrowsable(isVis)]
public string myMethod...
私はこれをVBで行いましたが、これは急いでC#に変換されました。何かが正しく機能しない場合は、私に知らせてください。
ジョン・カミングスのソリューションは基本的に私のために働いたが、ジェネリックの導入により次の2つの問題がある(しかし、これは非常に賢い):
1-バージョン SetBrowsableProperty<T>(T obj, string strPropertyName, bool bIsBrowsable)
Tが実際に意図されたコレクションのタイプではなく、TがIenumerable(リスト、配列など)の実装になるため、コレクションがパラメーターOBJとして渡されると失敗します。
2-プリミティブタイプを通過させることもできます。これは、この場合は無意味であり、ほとんど常に失敗します。
完全に改訂されたソリューション:
したがって、これらの問題に取り組み、私のために働いた改訂されたソリューションは次のとおりです。
Browsable属性値を変更する主なジョブを実行する実際の方法の最初:
/// <summary>
/// Sets the Browsable attribute value of a property of a non premitive type.
/// NOTE: The class property must be decorated with [Browsable(...)] attribute.
/// </summary>
/// <param name="type">The type that contains the property, of which the Browsable attribute value needs to be changed</param>
/// <param name="propertyName">Name of the type property, of which the Browsable attribute value needs to be changed</param>
/// <param name="isBrowsable">The new Browsable value</param>
public static void SetBrowsableAttributeOfAProperty(Type type, string propertyName, bool isBrowsable)
{
//Validate type - disallow primitive types (this will eliminate problem-2 as mentioned above)
if (type.IsEnum || BuiltInTypes.Contains(type))
throw new Exception($"The type '{type.Name}' is not supported");
var objPropertyInfo = TypeDescriptor.GetProperties(type);
// Get the Descriptor's Properties
PropertyDescriptor theDescriptor = objPropertyInfo[propertyName];
if (theDescriptor == null)
throw new Exception($"The property '{propertyName}' is not found in the Type '{type}'");
// Get the Descriptor's "Browsable" Attribute
BrowsableAttribute theDescriptorBrowsableAttribute = (BrowsableAttribute)theDescriptor.Attributes[typeof(BrowsableAttribute)];
FieldInfo browsablility = theDescriptorBrowsableAttribute.GetType().GetField("Browsable", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
// Set the Descriptor's "Browsable" Attribute
browsablility.SetValue(theDescriptorBrowsableAttribute, isBrowsable);
}
今、ジョン・カミングスの解決策で提案されているバリアント <T>
:
public static void SetBrowsableAttributeOfAProperty<T>(string propertyName, bool isBrowsable)
{
SetBrowsableAttributeOfAProperty(typeof(T), propertyName, isBrowsable);
}
今、問題があった過負荷。 1、しかし、次の変更は今それを処理します:
/// <summary>
/// Sets the Browsable attribute value of a property of a non premitive type.
/// NOTE: The class property must be decorated with [Browsable(...)] attribute.
/// </summary>
/// <param name="obj">An instance of the type that contains the property, of which the Browsable attribute value needs to be changed.</param>
/// <param name="propertyName">Name of the type property, of which the Browsable attribute value needs to be changed</param>
/// <param name="isBrowsable">Browsable Value</param>
public static void SetBrowsableAttributeOfAProperty<T>(T obj, string propertyName, bool isBrowsable)
{
if (typeof(T).GetInterface("IEnumerable") != null && typeof(T) != typeof(string)) //String type needs to be filtered out as String also implements IEnumerable<char> but its not a normal collection rather a primitive type
{
//Get the element type of the IEnumerable collection
Type objType = obj.GetType().GetGenericArguments()?.FirstOrDefault(); //when T is a collection that implements IEnumerable except Array
if (objType == null) objType = obj.GetType().GetElementType(); //when T is an Array
SetBrowsableAttributeOfAProperty(objType, propertyName, isBrowsable);
}
else
SetBrowsableAttributeOfAProperty(typeof(T), propertyName, isBrowsable);
そして、ここにすべてのC#システムが組み込まれた(プリミティブ)タイプを取得するためのユーティリティ関数があります。
public static List<Type> BuiltInTypes
{
get
{
if (builtInTypes == null)
builtInTypes = Enum.GetValues(typeof(TypeCode)).Cast<TypeCode>().Select(t => Type.GetType("System." + Enum.GetName(typeof(TypeCode), t)))
.ToList();
return builtInTypes;
}
}
使用法:
class Foo
{
[Browsable(false)]
public string Bar { get; set; }
}
void Example()
{
SetBrowsableAttributeOfAProperty<Foo>("Bar", true); //works
Foo foo = new Foo();
SetBrowsableAttributeOfAProperty(foo, "Bar", false); //works
List<Foo> foos = new List<Foo> { foo, new Foo { Bar = "item2" } };
SetBrowsableAttributeOfAProperty(foos, "Bar", true); //works now, whereas it would crash with an exception in John Cummings's solution
}