5

1 行の要約: Silverlight2 の UserControl のコンストラクターで作成されたイベント ハンドラーをアンフックするためのベスト プラクティスは何ですか?

背景: 現在、Silverlight2 で基幹業務アプリケーションを構築しています。Silverlight はブラウザー プラグインであるため、ウィンドウの概念はありません。すべては UserControls 内で行われます。アプリケーションでさまざまな「フォーム」を処理する方法は、Viewbox を含む最上位のユーザー コントロールを使用することです。別のフォームを表示するには、Viewbox の Child プロパティを別の UserControls に設定します。私のアプリには、フォームを開閉するために呼び出されるシングルトン PageManager クラスがあります。フォーム (UserControls) はスタックに格納されます。フォームを開くとスタックの一番上に置かれ、フォームを閉じるとスタックから削除され、その下のフォームが表示されます。

Model-View-ViewModel パターンに従おうとしています。各フォーム (UserControl から派生) には、View のすべてのデータを管理する ViewModel があります。ViewModel はイベントを公開するため、読み込みや保存などの操作が完了したときに UI に通知できます。

私のフォームでは、ViewModel を取得した後、コンストラクターでイベントをサブスクライブします。

public partial class MyPage : UserControl
{

    public MyViewModel ViewModel{get; set;}

    // other constructors, which create the viewmodel and call the constructor below.

    public MyPage(MyViewModel viewModel)
    {
        InitializeComponent();
        ViewModel = viewModel;
        this.LayoutRoot.DataContext = this.ViewModel;

        // subscribe to event so we can do stuff
        this.ViewModel.LoadCompleted += new MyViewModel.LoadCompletedEventHandler(ViewModel_LoadCompleted);
    }

私の質問は次のとおりです。このイベントをサブスクライブしたので、いつハンドラーを削除しますか? デストラクタを作成してそこで実行しますか?それとも、ガベージ コレクタがすべての参照 (つまり、イベント ハンドラ) がなくなるまでオブジェクトを破棄しない鶏と卵の状況を作り出しますか? PageManager によってフォームが閉じられたときに呼び出される UnhookEvents 関数を指定する、フォームが実装する必要があるインターフェイスを作成する必要がありますか?

編集:返信ありがとうございます。ViewModel がフォーム (UserControl) よりも長く続く状況はどうですか? 私のアプリの一部では、ユーザーは非常に複雑な構造を作成できますが、95% のケースでは、はるかに単純です。私がやったことは、同じViewModelを使用する2つのフォームを作成することでした. ユーザーは単純なフォームへの入力を開始してから、ViewModel を渡して新しいフォームを作成する詳細モードに切り替えることができます。

簡単なセットアップ フォームの場合:

    private void AdvancedSessionSetupButton_Click(object sender, RoutedEventArgs e)
    {
        PageManager.GetPageManager().Close(this);
        PageManager.GetPageManager().Open(new CreateSessionPage(this.ViewModel), "Create Session");
    }

詳細設定フォームで:

    private void BasicSessionSetupButton_Click(object sender, RoutedEventArgs e)
    {
        PageManager.GetPageManager().Close(this);
        PageManager.GetPageManager().Open(new CreateBasicSessionPage(this.ViewModel), "Create Session");
    }

PageManager.Close の後、フォームを参照しているのは ViewModel 内のイベントだけです。私はそれが私がそれらを外す必要がある場所だと思います。

4

2 に答える 2

2

この場合、C# プログラマーにはファイナライザーとして知られているデストラクタは必要ありません。ViewModel_LoadCompleted がメンバー関数であると仮定すると、「this」に完全に含まれる ViewModel オブジェクトに与える「this」へのポインターが含まれます。ガベージ コレクターは、これをインテリジェントに無視する必要があります。

この場合、正しいことは、バインドを解除する時間を無駄にしないことです。

一般に、"this" を (明示的または暗黙的に) "this" の意図された有効期間よりも長くその参照を保持するオブジェクトに渡す場合、イベント ハンドラーのバインドを解除する必要があります。たとえば、親コントロールのイベントにハンドラーを設定するとします。これで、親は、ハンドラーとその Children コントロール コレクションを介してあなたへの参照を持ちます。この場合、親から削除されたときにバインドを解除する必要があります。

不確かな場合は、IDisposable を実装し、Dispose() の呼び出しでバインドを解除してください。

于 2009-02-17T09:56:35.560 に答える
1

ガベージ コレクターがオブジェクトを通過すると、イベントは自動的にアンバインドされます。

ただし、いつでも「-=」構文を使用して明示的にバインドを解除できます。

this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;

デストラクタを実装できます。

~MyPage
{
    this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;
}
于 2009-02-17T09:22:23.427 に答える