1

私は現在、コンテンツを交換してさまざまなユーザー コントロールを表示できるパネルを含むメイン ウィンドウを持つ WPF アプリケーションに取り組んでいます。基本的に、これは、サイドバーが常に表示されるメニューがあることを意味します。

私の質問は、クラス間の結合を減らすことです。メイン ウィンドウに、メッセージがポップアップする通知セクション (ListBox の形式) があります。通知は、一部のユーザー コントロール (UC) で発生するアクションから「トリガー」できます。もちろん、これらのユーザー コントロールはメイン ウィンドウ クラスのメンバーです。

メイン ウィンドウ クラスの ListBox コントロールに影響を与える必要があるため、どのようなベスト プラクティスが必要かを考えていました。明らかに、最も簡単な解決策は、コンストラクターを介して各 UC にメイン ウィンドウへの参照を渡すことですが、それは多くのレベルであまり効率的ではないようです。もちろん、ListBox 要素のみを渡すこともできますが、ListBox に追加されるデータに対して操作を実行する必要があるため、実際には機能しません。そのため、すべての UC でこれらの命令をプログラムで繰り返す必要があります。

ListBox への参照を持ち、通知メソッドを実装するシングルトンを使用することもできますが、自分のプロジェクトで快適に使用できるシングルトンが既にあります (誰もがこれらのメソッドにアクセスできるようにしたくありません。特定の UC)。

もう 1 つの方法は、関連する UC のコンストラクターを介して (同じジョブを実行する) 通知マネージャー インスタンスを渡すことです。そのマネージャーは、UC をメイン ウィンドウにリンクするために必要なすべての方法を備えています。

私が思いもよらなかった追加のより効率的なソリューションがあるかもしれません。特にそれが生成するクラス結合を考慮して、そのような場合のベストプラクティスについて意見を求めます. これはこの特定の問題に関連している可能性がありますが、内部の集約クラスが外部のリソースの一部にアクセスする必要がある、より一般的な方法で考えてみてください。ありがとう。

4

2 に答える 2

2

UserControlイベントを発生させるという Jesse のアイデアが気に入っています。これは非常に WPF 風であり、ログを記録する必要がある とログを提供するウィンドウとの間の疎結合を可能にします。さらに、ロギングを行う UserControls は、実際に使用可能なロギング サービスに依存しないため、ソリューションがさらに柔軟になります。

これがどのように機能するか

ログが必要なはUserControl、関連情報 (ログに記録されるテキスト メッセージ) を含むバブリング イベントを発生させるだけです。UC は、そのメッセージがどのように処理されるか、または処理されるかどうかさえわかりません。単にそれを発生させます。それは軽量操作であり、カップリングは最小限です。

Window発生したメッセージは、最上位の要素 ( 、 )まで階層チェーンを上っていきますPage。途中のどこでも、要素がこのイベント タイプのハンドラーを提供し、それを介してログ リクエストについて通知を受けることができます。繰り返しますが、結合は非常に緩いです。実装が行われる場所は、誰がメッセージを送信したかを気にしません。UserControl またはその他のものである可能性があります。

問題

UIElementロギング メッセージ イベントの発信元として を使用できる場合、これは問題なく機能します。

ステップバイステップの実装は次のとおりです。

LogServices クラス

この目的で既存のイベントを再利用することはできません。新しいイベントを作成する必要があります (混乱を避けるため)。これはそれを行う必要があります:

// Subclass of RoutedEventArgs that allows us to easily and nicely pass the message
// to be logged
public class LogEventArgs : RoutedEventArgs
{
    public string Msg { get; set; }
    public LogEventArgs(RoutedEvent routedEvent, Object sender, string Msg)
        :base(routedEvent, sender)
    {
        this.Msg = Msg;
    }
}

// This is the Delegate that's used to grab the Log message
public delegate void RoutedLogEventHandler(Object sender, RoutedEventArgs e);

// This works as the abstraction layer that will allow UC's to raise LOG messages
// and allow your implementation to alter the way it handles those LOG messages.
// Since we're doing this with a routed event, we need an DependencyObject to
// reigster it.
public class LogServices :UIElement
{        
    public static RoutedEvent LogEvent;

    // Static constructor, registers the event
    static LogServices()
    {
        LogEvent = EventManager.RegisterRoutedEvent("Log", RoutingStrategy.Bubble, typeof(RoutedLogEventHandler), typeof(UIElement));
    }

    // This helps raise the relevant shared event
    public static void RaiseLog(string Msg, UIElement sender)
    {
        sender.RaiseEvent(new LogEventArgs(LogEvent, sender, Msg)); 
    }

}

RoutedEventArgs上記のコードは、文字列 Message を渡す必要があるため、サブクラスを宣言します。次に、パラメーターを受け取る新しいデリゲート型を作成し、LogEventArgs最後に の静的コンストラクターからイベントを登録しますLogServices

イベントの送信方法

イベントの送信は非常に簡単です。これはボタンの Click ハンドラーです。

LogServices.RaiseLog("Message to be logged.", sender as Button)

イベントの受け取り

イベントは「バブリング」イベントとして登録されます。イベントは、発生させているコントロールから開始され、ウィンドウに至るまで、すべての親にそれを処理する機会を与えます。最も簡単な方法は、Windowログを記録する でイベントを処理することです。残念ながら、このタイプの共有は から直接設定することはできませんXAML。コードから割り当てる必要があります。これは私がから割り当てようとした方法でXAMLあり、うまくいきませんでした:

<Grid local:LogService.Log="HandlerName" />

次のオプションは、コードから割り当てることです。ここに私のテストからの抜粋がありますWindow1:

    // Window Constructor
    public MainWindow()
    {
        InitializeComponent();
        // Set the event handler.
        base.AddHandler(LogServices.LogEvent, new RoutedLogEventHandler(HandleMsgLog));
    }

    // This is the actual handler.
    public void HandleMsgLog(Object sender, RoutedEventArgs e)
    {
        // Put the received message into the ListBox
        LB.Items.Add((e as LogEventArgs).Msg);
    }
于 2013-03-09T09:46:22.440 に答える
0

オブザーバー パターン ( http://en.wikipedia.org/wiki/Observer_pattern ) について読むことができますが、このパターンは状況よりも広く使用されています。

あなたの状況では、良いバリアントは次のとおりだと思います。

1) 別の方法は、関連する UC のコンストラクターを介して通知マネージャー インスタンス (同じジョブを実行する) を渡すことです。そのマネージャーは、UC をメイン ウィンドウにリンクするために必要なすべての方法を備えています。(c)

2) すべての UC は「NotificationRaised」などのイベントとのインターフェイスを実装する必要があり、メイン ウィンドウでこのイベントを購読する必要があります。あなたの質問へのコメントでジェシーが言ったことについて

于 2013-03-09T09:25:13.417 に答える