C#WinForms Model-View-Presenter(パッシブビュー)
-
29-09-2019 - |
質問
C#でWinFormsアプリケーションを開発しています。私はGUIプログラミングの経験が限られており、その場で多くのことを学ばなければなりません。そうは言っても、ここに私が構築しているものがあります。
一般的なGUIを参照してください。次のリンクをご覧ください。
GUI http://img227.imageshack.us/img227/1084/program0.jpg
今、私はすでに多くの仕事をしていますが、非常に悪い自律設計パターンで。プロジェクトが特定のサイズに達することを知りませんでした。そのため、いくつかの主要なリファクタリングを行う時が来ました。
私はGUIのデザインパターンについて多くのことを研究してきましたが、実装したいパターンはパッシブビューです(参照 http://martinfowler.com/eaadev/passivescreen.html)。これをすべてまとめる方法についての助けを探しています。
バックグラウンド:
1)「ツリービュー」でユーザーがクリックするものに応じて、左下隅の「リスト」には「エディター」領域を入力できるオブジェクトのリストが表示されます。これらのオブジェクトは、テキストボックスまたはdatagridViewである場合があります。ユーザーはリストを切り替えて、「エディター」で見たいものを選択します
2)モデルは、基本的にデータと構成ファイルを備えたフォルダーです。特定のディレクトリで実行され、出力ファイル/フォルダーなどを作成する外部プログラムがあります。私が開発しているこのプログラムは、これらのオブジェクトをユーザーフレンドリーな方法で効果的に管理/構成するように設計されています
3)私が物事をしてきた方法の問題は、テストすることは次に不可能であり、したがってMVP風のパッシブビューのデザインパターンへの移行であるということです
私は、プログラムが見解から独立して機能するようにそれを作ろうとしています。パッシブビューパターンで、より複雑でインタラクティブなビューが使用される例を見つけることができませんでした。
質問:
1)プログラムの「外観」全体に1つの大きなインターフェイス/ビューを実装し、各ツリービュー、編集者、ロガーなどにサブインターフェイス/サブビューを実装する必要がありますか?それとも、これを行うにはより良い「構造」がありますか?
2)ビューからプレゼンター/コントローラーへの「引き渡し」イベント(Passive View Design Patternを使用する用語が何であれ)になると、これを行うべき方法は何ですか?時々、更新する必要がある単純なプロパティがあり、時には展開するための一連のステップが必要な場合があります。
このトピックに関する提案とアドバイスが大好きです。私はインターネットを精査しましたが、このプロジェクトを継続するのに役立つ適切な例を見つけていません。
前もって感謝します!
ダニエル
解決
MVP設計パターンを使用して受動的ビューの概念を示す簡単な例を以下に示します。パッシブビューを使用しているため、ビューには発表者の知識がありません。プレゼンターは、ビューによって公開されたイベントを単に購読し、それに応じて行動します。
開始するには、見解の契約を定義する必要があります。これは通常、インターフェイスを使用して達成されます。本質的に、私たちの見解と非常にゆるい結合が必要です。さまざまなビューまたはイベントに切り替える機能が必要です。ユニットテストのために模擬ビューを作成します。
これは、顧客情報を表示するために使用される簡単なビューを説明する契約です
public interface ICustomerManagementView
{
void InitializeCustomers(ICustomer[] customers);
void DisplayCustomer(ICustomer customer);
event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
単一のメソッドを公開します InitialIzestomers これは、モデルのオブジェクトでビューを初期化するために使用されます。
イベントもあります SelectedCustomerChanged これは、プレゼンターがビューでアクションが発生したという通知を受け取るために使用されます。
契約を結んだら、プレゼンターでこれらのやり取りの処理を開始できます。
public class CustomerManagementPresenter
{
private ICustomer _selectedCustomer;
private readonly ICustomerManagementView _managementView;
private readonly ICustomerRepository _customerRepository;
public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository)
{
_managementView = managementView;
_managementView.SelectedCustomerChanged += this.SelectedCustomerChanged;
_customerRepository = customerRepository;
_managementView.InitializeCustomers(_customerRepository.FetchCustomers());
}
private void SelectedCustomerChanged(object sender, EventArgs<ICustomer> args)
{
// Perform some logic here to update the view
if(_selectedCustomer != args.Value)
{
_selectedCustomer = args.Value;
_managementView.DisplayCustomer(_selectedCustomer);
}
}
}
プレゼンターでは、呼ばれる別のデザインパターンを使用できます 依存関係インジェクション 私たちのビューへのアクセスと、必要なモデルクラスを提供するため。この例では、顧客の詳細の取得を担当するCustomerRePositoryがあります。
コンストラクターには、2つの重要なコード行があります。まず、私たちの見解では、選択されたカストメーチャンジのイベントを購読しました。ここで、関連するアクションを実行できます。第二に、リポジトリからのデータを使用したInitialaizecustomersを呼び出しました。
この時点で、私たちは実際に私たちの見解のために具体的な実装を定義していません。 icustomermanagementView. 。たとえば、Windowsフォームアプリケーションでは、次のことを行うことができます
public partial class CustomerManagementView : Form, ICustomerManagementView
{
public CustomerManagementView()
{
this.InitializeComponents();
}
public void InitializeCustomers(ICustomer[] customers)
{
// Populate the tree view with customer details
}
public void DisplayCustomer(ICustomer customer)
{
// Display the customer...
}
// Event handler that responds to node selection
private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e)
{
var customer = e.Node.Tag as ICustomer;
if(customer != null)
{
this.OnSelectedCustomerChanged(new EventArgs<ICustomer>(customer));
}
}
// Protected method so that we can raise our event
protected virtual void OnSelectedCustomerChanged(EventArgs<ICustomer> args)
{
var eventHandler = this.SelectedCustomerChanged;
if(eventHandler != null)
{
eventHandler.Invoke(this, args);
}
}
// Our view will raise an event each time the selected customer changes
public event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
プレゼンテーションロジックをテストしたい場合は、見解をock笑し、いくつかの主張を実行できます。
編集:カスタムイベントArgsを含めました
public class EventArgs<T> : EventArgs
{
private readonly T _value;
public EventArgs(T value)
{
_value = value;
}
public T Value
{
get { return _value; }
}
}
他のヒント
私はそれらを独自のプレゼントで別々のビューに分解し、「コントロール」プレゼンター /ビューを使用して、それらすべての間のメッセージ委任を管理します。これはテスト可能性を支援するだけでなく、コントロールもSRPを満たし続けるでしょう。
したがって、あなたの場合、メインウィンドウが実装するIformManagerがあり、Ifilemanager、iloggerwindowなどがあります。
使用するのは少し過剰かもしれませんが、スマートクライアントソフトウェア工場(Microsoft Patterns and Practicesチームから)を見ることをお勧めします。この種のビュー構成には非常によくできているので、いくつかの良いアイデアを与えるかもしれません。