20

私はC#でWinFormsアプリケーションを開発しています。GUIプログラミングの経験は限られており、その場で多くのことを学ぶ必要があります。そうは言っても、これが私が構築しているものです。

次のリンクを参照して、一般的なGUIを参照してください。

GUI http://img227.imageshack.us/img227/1084/program0.jpg

今、私はすでに多くの作業を行っていますが、非常に悪い自律設計パターンです。プロジェクトが特定のサイズに達するとは思っていなかったので、大規模なリファクタリングを行うときが来ました。

私はGUIデザインパターンについて多くのことを研究してきましたが、実装したいパターンはパッシブビューです(http://martinfowler.com/eaaDev/PassiveScreen.htmlを参照)。私はこれをすべてまとめる方法についていくつかの助けを探しています。

バックグラウンド:

1)ユーザーが「TreeView」でクリックした内容に応じて、左下隅の「リスト」には、「エディター」領域に入力できるオブジェクトのリストが表示されます。これらのオブジェクトは、TextBoxまたはDataGridViewである可能性があります。ユーザーはリストを切り替えて、「エディター」に表示したいものを選択します

2)モデルは基本的に、データと構成ファイルを含むフォルダーです。特定のディレクトリで実行され、出力ファイル/フォルダなどを作成する外部プログラムがあります。私が開発しているこのプログラムは、これらのオブジェクトをユーザーフレンドリーな方法で効果的に管理/構成するように設計されています。

3)私が行ってきた方法の問題は、テストがほぼ不可能であるため、MVP風のパッシブビューデザインパターンに移行することです。

プログラムがビューとは独立して動作するようにしようとしています。パッシブビューパターンでより複雑でインタラクティブなビューが使用されている例は見つかりませんでした。

質問:

1)プログラムの「外観」全体に対して1つの大きなインターフェイス/ビューを実装してから、TreeView、エディター、ロガーなどのそれぞれに対してサブインターフェイス/サブビューを実装する必要がありますか?それとも、これを行うためのより良い「構造」がありますか?

2)ビューからプレゼンター/コントローラーへのイベントの「受け渡し」(WRTパッシブビューデザインパターンを使用する用語が何であれ)に関しては、これをどのように行う必要がありますか?更新が必要な単純なプロパティがある場合もあれば、展開するための一連の手順全体が必要な場合もあります。

このトピックに関する提案やアドバイスが欲しいです。私はインターネットを調べましたが、このプロジェクトを継続するのに役立つ適切な例が見つかりませんでした。

前もって感謝します!

ダニエル

4

2 に答える 2

18

これは、MVPデザインパターンを使用したパッシブビューの概念を示す簡単な例です。パッシブビューを使用しているため、ビューにはプレゼンターの知識がありません。プレゼンターは、ビューによって公開されたイベントをサブスクライブし、それに応じて行動します。

まず、ビューのコントラクトを定義する必要があります。これは通常、インターフェースを使用して実現されます。基本的に、ビューとの結合を非常に緩くしたいと考えています。ユニットテスト用に、別のビューに切り替えたり、イベント作成のモックビューを作成したりできるようにする必要があります。

これは、顧客情報を表示するために使用される単純なビューを説明する契約です。

public interface ICustomerManagementView
{
    void InitializeCustomers(ICustomer[] customers);
    void DisplayCustomer(ICustomer customer);
    event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}

モデルのオブジェクトでビューを初期化するために使用される単一のメソッドInitializeCustomersを公開します。

ビューでアクションが発生したという通知を受け取るためにプレゼンターが使用するイベント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つの重要なコード行があります。最初に、ビューのSelectedCustomerChangedイベントをサブスクライブしました。ここで、関連するアクションを実行できます。次に、リポジトリからのデータを使用してInitilaizeCustomersを呼び出しました。

この時点では、ビューの具体的な実装を実際に定義していません。必要なのは、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;
}

プレゼンテーションロジックをテストしたい場合は、ビューをモックしていくつかのアサーションを実行できます。

編集:含まれているカスタムイベント引数

public class EventArgs<T> : EventArgs
{
    private readonly T _value;

    public EventArgs(T value)
    {
        _value = value;
    }

    public T Value
    {
        get { return _value; }
    }
}
于 2010-11-30T20:11:20.763 に答える
0

私はそれらを独自のプレゼントで別々のビューに分割し、「制御」プレゼンター/ビューを使用してそれらすべての間のメッセージ委任を管理します。これはテスト容易性を支援するだけでなく、コントロールがSRPを満たし続けるようにします。

したがって、あなたの場合、メインウィンドウが実装するIFormManagerがあり、次にIFileManager、ILoggerWindowなどがあります。

使用するのは少しやり過ぎかもしれませんが、Smart Client Software Factory(Microsoft Patterns and Practicesチームから)をご覧になることをお勧めします-これはもう積極的に開発されていませんが、MVPとこの種のビュー構成は非常にうまく機能するので、いくつかの良いアイデアが得られるかもしれません。

于 2010-12-02T02:03:57.480 に答える