13

NotifyIconとその動的に入力された のみで構成される UI を使用して、WinForms アプリケーションを構築していContextMenuStripます。MainFormアプリケーションをまとめるための がありますが、それは決して目に見えません。

私はこれを可能な限りしっかりと構築することに着手し (Autofac を使用してオブジェクト グラフを処理します)、私の成功に非常に満足しています。現在実装している拡張機能では、設計に欠陥があり、少し改造する必要があるようです。必要な方法はわかっていると思いますが、依存関係を正確に定義する方法については少し不明です。

前述のように、アプリケーションの起動後に、メニューの一部が動的に読み込まれます。この目的のために、私はIToolStripPopulatorインターフェースを定義しました:

public interface IToolStripPopulator
{
    System.Windows.Forms.ToolStrip PopulateToolStrip(System.Windows.Forms.ToolStrip toolstrip, EventHandler itemclick);
}

this の実装は に注入され、フォームで定義された および ハンドラを使用しMainFormLoad()メソッドが呼び出されます。ポピュレータの依存関係は、メニュー項目に使用するデータの取得にのみ関連しています。PopulateToolStrip()ContextMenuStrip

この抽象化は、いくつかの進化的なステップを経てうまく機能しましたが、複数のイベント ハンドラーが必要な場合には、もはや十分ではありません。たとえば、メニュー項目のいくつかの異なるグループを作成している場合などですIToolStripPopulator。それにはまったく関心がありません。

私が言ったように、私は一般的な構造がどのようなものであるべきかを知っていると思います-IToolStripPopulatorインターフェースをより具体的なものに名前変更し*、メソッドがパラメーターをPopulateToolStrip()取らない新しいものを作成しました。EventHandler実装に必要なハンドラーの数に関する柔軟性の向上など)。このようにして、私の「最前線」IToolStripPopulatorは、任意の数の特定のもののアダプターになることが非常に簡単になります。

今、私がはっきりしていないのは、EventHandler の依存関係を解決する方法です。MainFormメニューイベントに適切に反応するために必要な他のすべての依存関係があり、メニューも「所有」しているため、ハンドラはすべて で定義する必要があると思います。IToolStripPopulatorこれは、最終的に MainForm に注入されるオブジェクトの依存関係が、MainFormを使用してオブジェクト自体に依存する必要があることを意味しLazy<T>ます。

私が最初に考えたのは、IClickHandlerSourceインターフェースを定義することでした:

public interface IClickHandlerSource
{
    EventHandler GetClickHandler();
}

これは my によって実装され、MainForm私の特定のIToolStripPopulator実装は に依存していましたLazy<IClickHandlerSource>。これは機能しますが、柔軟性に欠けます。ハンドラーの数が増える可能性があるため (MainFormクラスで OCP に重大な違反)、個別のインターフェイスを定義するか、継続的に拡張するIClickHandlerSource(主に ISP に違反する) 必要があります。イベント ハンドラーへの依存関係を直接取得することは、コンシューマー側にとっては良いアイデアのように見えますが、遅延インスタンス (など) のプロパティを介してコンストラクターを個別に接続するのは非常に面倒です (可能であれば)。

私の最善の策は現在これのようです:

public interface IEventHandlerSource
{
    EventHandler Get(EventHandlerType type);
}

インターフェイスは引き続きMainForm遅延シングルトンによって実装および注入され、EventHandlerType必要なさまざまなタイプのカスタム列挙型になります。これはまだOCPに完全には準拠していませんが、適度に柔軟です。新しいイベント ハンドラー自体と (おそらく) 新しく作成された の追加実装に加えて、EventHandlerTypeの解決ロジックと同様に、新しいタイプのイベント ハンドラーごとに変更があることは明らかです。MainFormIToolStripPopulator

または....それを(唯一のオブジェクトとして)個別に実装するとIEventHandlerSource、依存関係が発生し、オプションが?で定義された特定のハンドラーにLazy<MainForm>解決されます。EventHandlerTypeMainForm

私は実際にMainForm実行可能な方法でイベント ハンドラーを取得する方法を考えようとしていますが、今のところうまくいくようには見えません。

ここで、さまざまなイベント ハンドラーの結合が最も緩く、最もエレガントな解決策を提供する最善の選択肢は何ですか?

[*はい、OCP に完全に準拠するために名前をそのままにしておくべきだったかもしれませんが、その方が見栄えがよくなりました。]

4

4 に答える 4

0

フォーム内で子コンポーネントをホストしている場合、それらはメイン アプリケーションの「シェル」に入力できます。

ShellComponentSystem.Windows.Forms.ContainerControl から継承する基本クラスを持つことができます。これにより、デザイン面も提供されます。IToolStripPopulator に依存する代わりに、そのような ITool を使用できます。

public inteface ITool<T>
{
   int ToolIndex { get; }
   string Category { get; }
   Action OnClick(T eventArgs);
}

ビューが読み込まれるたびに MainForm からShellComponent呼び出すことができます。public List<ITool> OnAddTools(ToolStrip toolStrip)このようにして、コンポーネントはツールストリップへの入力を担当します。

次に、「ShellComponent」は、IoC コンテナーに を実装するハンドラーを要求しますITool<T>。このようにITool<T>して、イベントを ( MainForm、または でContainerControl) 分離し、これを任意のクラスにプッシュする方法を提供します。また、(MouseClickEventArgs ect とは対照的に) 引数として渡すものを正確に定義することもできます。

于 2012-06-28T16:09:56.523 に答える