0

現在、Visual Studio ツールボックスと同様の外観と機能を持つツールボックスを備えた Wpf アプリを構築しています。ツールボックスで表される一連のクラスと、ツールボックス項目のすべてではなく一部をそれぞれに含むことができるさまざまな種類のオブジェクトがあります。

アプリを稼働させるための応急処置として、ツールボックスの機能を UserControls にハードコーディングしました。ここで、ハードコーディングされていない、より優れた設計に進む必要があります。

Type、Label、および Icon のプロパティを持つ単純な ToolBoxItem クラスがあります。ツールボックスに入れる必要がある各クラスは、ToolBoxItems のコレクションに追加され、正しく表示されます。

しかし、私は次の 2 つの問題に対するエレガントな解決策を思いつくのに苦労しています。

  • 編集中のオブジェクトで ToolBoxItem Type によって表されるクラスのインスタンスを作成する方法。
  • 編集中のアイテムと互換性のないツールボックス アイテムを非表示にする方法。編集された各クラスがインターフェイスを介して実装する必要があるハードコードされたプロパティ (つまり、CanSupportClassX、CanSupportBaseClassY) を使用して、手動でこれを行うようになりました。

私の感覚では、デリゲートとおそらくジェネリックが解決策になる可能性がありますが、私は過去にこれらの機能を使用しただけで、どのように進めればよいかわかりません.

4

2 に答える 2

1

最良の方法は、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 であるとは限らないため、追加のチェックを行い、追加のアルゴリズムを実装する必要があります。リフレクションを頻繁に使用しないように、キャッシングを追加することもお勧めします。

于 2009-11-09T17:10:55.537 に答える
1

あなたが達成しようとしていることの良い例は、完全にオープンソースであるAvalonDockにあります。MVVM で AvalonDock を使用する方法 (つまり、ウィンドウにツールを配置する方法など) を確認したい場合は、SoapBox Core Frameworkを調べてください。

于 2009-11-10T03:38:29.513 に答える