最良の方法は、Visual Studio 自体が採用する方法だと思います。各オブジェクトは、そのプロパティの型によって含めることができるものを記述します。
したがって、Visual Studio では、次のようにウィジェットを保持できる新しいオブジェクトを作成できます。
[ContentAttribute("Children")]
public class MyObject
{
...
public ICollection<Widget> Children { get ... set ... }
}
残りは Visual Studio の型システムが行います。
もちろん、いくつかの拡張機能や別の手法が必要になる可能性のある制限があります。たとえば、オブジェクトが を除いて共通の基本クラスを共有しない 2 つの異なるタイプのコンテンツを受け入れることができる場合object
、プロパティを宣言する必要がありICollection<object>
ます。追加のメカニズム。
これらの特殊なケースでは、多くのアドオン メカニズムを使用できます。たとえば、次のようになります。
- 複数の「コンテンツ」属性を許可します。たとえば、
ICollection<Widget> WidgetChildren { get ... set ...}; ICollection<Doodad> DoodadChildren { get ... set ... }
- クラスに適用できる属性を作成して、クラスに含めることができるオブジェクトタイプを指定します。たとえば
[ContentTypeAllowed(typeof(Widget))] [ContentTypeAllowed(typeof(Doodad))]
、実際のコンテンツプロパティがどこにあるかIEnumerable<object>
- たとえば、クラス名のリストだけを持つ属性を作成します。
[ContentTypesAllowed("Widget,Doodad")]
true
ターゲットオブジェクトで定義されている場合、潜在的なコンテンツクラスを評価し、それが子になることができるかどうかを返すメソッドを作成し、そうでfalse
ない場合は次のようにしますbool CanAcceptChildType(Type childType) { return type.IsSubclassOf(Widget) && !type==typeof(BadWidget); }
- たとえば、違法な子供をリストする属性を作成します。
[ContentTypesDisallowed("BadWidget")]
- このデータを表すために、項目クラスに属性またはメソッドを追加します。たとえば、
[TargetMustRespondTo(EditCommands.Cut)] public class CutTool { ... }
- アイテム クラスにデータを追加して、このデータを表します。たとえば、
new ToolBoxItem { Name="Widget", AllowedContainers=new[] { typeof(MyObject), typeof(OtherObject) }
- 上記の組み合わせ
これらはすべて実行可能なテクニックです。自分の状況を考慮して、実装するのが最も理にかなっているものを確認してください。
ツール ボックス項目の非表示を実際に実装するにIMultiValueConverter
は、ツール ボックス項目の Visibilty プロパティへのバインドを使用するだけですDataTemplate
。ツール ボックス アイテムとターゲットの 2 つのバインドをコンバーターに渡します。次に、決定したロジックを に実装しますIMultiValueConverter
。
たとえば、ContentAttribute のコレクション型のみを気にする最も単純なケースでは、次のコードが機能します。
public object Convert(object[] values, ...)
{
var toolItem = values[0] as ToolItem;
var container = values[1];
var contentPropertyAttribute =
container.GetType().GetCustomAttributes()
.OfType<ContentPropertyAttribute>()
.FirstOrDefault();
if(contentPropertyAttribute!=null)
{
var contentProperty = container.GetType().GetProperty(contentPropertyAttribute.Name);
if(contentProperty!=null &&
contentProperty.Type.IsGeneric &&
contentProperty.Type.GetGenericArguments()[0].IsAssignableFrom(toolItem.Type))
return Visibility.Visible;
}
return Visibility.Collapsed;
}
実際の状況では、もう少し複雑な場合があります。たとえば、すべての Content プロパティが ICollection であるとは限らないため、追加のチェックを行い、追加のアルゴリズムを実装する必要があります。リフレクションを頻繁に使用しないように、キャッシングを追加することもお勧めします。