22

私の WPF アプリケーションには 2 つの Windows があります (両方の Windows に独自の ViewModel があります)。

  1. 単語のリストを表示するアプリケーションのメイン ウィンドウ (MainViewModel にバインド)

  2. ユーザーが新しい項目をリストに追加できるようにするダイアログ ウィンドウ (AddWordViewModel にバインド)

MainViewModel には、メイン ウィンドウの ListBox にバインドされた List の Articles プロパティがあります (このコレクションは、サービス クラスの 1 つによって取り込まれます)。

AddWordViewModel には、[単語の追加] ダイアログの [保存] ボタンにバインドされた SaveWordCommand があります。そのタスクは、ユーザーが入力したテキストを受け取り、それをサービス クラスに渡すことです。

ユーザーが [保存] ボタンをクリックした後、サービスから記事をリロードするように MainViewModel に通知する必要があります。

私の考えは、MainViewModel でパブリック コマンドを公開し、AddWordViewModel から実行することでした。

それを実装する正しい方法は何ですか?

ありがとう!

4

1 に答える 1

19

Event Aggregatorは、この種の問題を解決する非常に優れた方法です。基本的に、あるオブジェクトから別のオブジェクトにイベントを転送する役割を担う中央集権型のクラスがあります (簡単にするために、これをシングルトンとしましょう。反シングルトン派の怒りに直面する可能性があります)。クラス名を使用すると、使用法は次のようになります。

public class MainViewModel
{
    public MainViewModel()
    {
        WordAddedEvent event = EventAggregator.Instance.GetEvent<WordAddedEvent>();
        event.Subscribe(WordAdded);
    }

    protected virtual void WordAdded(object sender WordAddedEventArgs e)
    {
        // handle event
    }
}

public class AddWordViewModel
{    
    //From the command
    public void ExecuteAddWord(string word)
    {
        WordAddedEvent event = EventAggregator.Instance.GetEvent<WordAddedEvent>();
        event.Publish(this, new WordAddedEventArgs(word));
    }
}

このパターンの利点は、アプリケーションを非常に簡単に拡張して、単語を作成する複数の方法と、追加された単語に関心のある複数の ViewModel を持つことができることです。2 つの間に結合がないため、必要に応じてそれらを追加および削除できます。する必要があります。


シングルトンを回避したい場合 (およびテスト目的でそうすることをお勧めします) は、依存性注入を検討する価値があるかもしれませんが、それは実際にはまったく別の問題です。


さて、最終的な考え。あなたの質問を読み直すと、Word オブジェクトの取得と保存を処理する何らかの Word Service クラスが既にあることがわかります。両方の ViewModel が既に結合されているため、新しい単語が追加されたときにサービスがイベントの発生を担当できない理由はありません。EventAggregator の方がより柔軟で優れたソリューションであると私はまだお勧めしますが、ここではYAGNIが適用される可能性があります。

public class WordService
{
    public event EventHandler<WordAddedEventArgs> WordAdded;

    public List<string> GetAllWords()
    {
        //return words
    }

    public void SaveWord(string word)
    {
        //Save word
        if (WordAdded != null) WordAdded(this, new WordAddedEventArgs(word));
        //Note that this way you lose the reference to where the word really came from
        //probably doesn't matter, but might
    }
}

public class MainViewModel
{
    public MainViewModel()
    {
        //Add eventhandler to the services WordAdded event
    }
}

ただし、回避したいのは、あるViewModelでコマンドを呼び出して作成するViewModel間の結合を導入することです。これにより、アプリケーションを拡張するオプションが大幅に制限されます(2番目のViewModelが新しい単語に興味を持つようになった場合) 、それもそれを伝えるのは AddWordViewModel の責任ですか?)

于 2009-04-28T17:42:49.257 に答える