6

序章

実行中にラボ機器データをインポートするアプリケーションがあります。このデータはインポートListViewされ、エンドユーザーがテスト要件に従って設定した間隔で表示されます。監視対象の値が表示されたらListView、[開始] ボタンを押します。アプリケーションは、[停止] ボタンが押されるまで、そのデータと後続のデータの計算を開始します。したがって、画面の左側にはインポートされたデータを表示するためのビューがあり、右側には計算および表示される値と統計を監視するための別のビューがあります。

現在のコード

データのインポート先の ListView を表示するビューは ImportProcessView.xaml であり、それを に設定しDataContextますImportProcessViewModel.cs。先ほど紹介した VM には、ObservableCollection<IrData>先ほど説明した ListView がバインドするプロパティがあります。さて、興味深い部分に...

ImportProcessViewは、ContentControlコンテンツを動的に設定する UserControl があり、エンド ユーザーが選択した Phase のタイプに固有のコントロールとフィールドを表します。

<StackPanel Background="White" Margin="5">
    <ContentControl Content="{Binding CurrentPhaseView}"/>
</StackPanel>

3 つの がありPhaseViews、それぞれが独自のユーザー コントロールにあり、それぞれが に設定さDataContextれていImportProcessViewModelます。その結果、VM が 2000 行にまで膨れ上がりました。ばかげている。知っている。肥大化の理由は、ImporProcessViewModelが 3 つの PhaseView のそれぞれのプロパティを通じて状態を維持しているだけでなく、データがこれらの「PhaseView」に保存および表示される計算を実行するためのメソッドが含まれているためです。

私が達成しようとしていること

明らかにImportProcessViewModel扱いにくくなる前に、各 PhaseView が独自の ViewModel を持つように分割する必要がありますが、各 ViewModel が ImportProcessViewModel との関係を維持して、ObservableCollection によって課せられる依存関係を維持できるようにする必要がありIrDataます。

研究開発

相互に通信する ViewModel について調査しましたが、ほとんどの結果には、特定の MVVM フレームワークで作成されたアプリケーションが含まれています。私はフレームワークを使用していません。プロジェクトのこの時点では、フレームワークを使用するためにリファクタリングするには遅すぎます。

しかし、私はこの記事を見つけました.「hbarck」が提供する答えは、私が望む結果を達成するための構成のような単純なものを示唆していますが、私はDataTemplatesの経験があまりないので、彼/彼女は、「UserControl の ViewModel をメインの ViewModel のプロパティとして公開し、ContentControl をこのプロパティにバインドして、DataTemplate を介して View (つまり UserControl) をインスタンス化する」ことを提案しています。

具体的には、 「ContentControl をこのプロパティにバインドし、DataTemplate を介してビューをインスタンス化するという意味がわかりません。

この例のコンテキストで DataTemplate を介してビューをインスタンス化することの意味を、コード例を使用して誰かが明確にすることはできますか?

さらに、これは良いアプローチですか (「hbarck」で提案されているように)?

ご覧のとおり、ContentControl の Content プロパティを、インスタンス化するフェーズ ビューに既に設定しています。DataTemplate がどのように見えるかはわかりません。

4

2 に答える 2

5

「UserControl の ViewModel をメインの ViewModel のプロパティとして公開し、ContentControl をこのプロパティにバインドすると、DataTemplate を介して View (つまり UserControl) がインスタンス化される」と提案されたときの意味がわかりません。

を使用するDataTemplateと、ビュー (ユーザー コントロールなど) とビュー モデルの間の関係を指定できます。

<DataTemplate DataType="{x:Type myApp:MyViewModel}">
    <myApp:MyUserControl />
</DataTemplate>

これにより、 content プロパティが のインスタンスに設定されるたびContentPresenterに が表示されるようになります。ビュー モデルは、ユーザー コントロールとして使用されます。通常、はアプリケーション リソースに追加されます。MyUserControlMyViewModelDataContextDataTemplate

その答えの作者が言っているのは、のプロパティにバインドされている別のviewModelタイプのプロパティを持つviewModelを持つことができるということContentですContentPresenter

<ContentPresenter Content="{Binding ParentViewModel.ChildViewModelProperty}"/>

DataTemplateユーザー コントロールとユーザー コントロールの間の関係を指定するがあるChildViewModel場合、WPF はユーザー コントロールをビューに自動的に読み込みます。

私が別の質問に提供したこの回答も、あなたに役立つかもしれません。

各 PhaseView が独自の ViewModel を持つように分割する必要がありますが、各 ViewModel が ImportProcessViewModel との関係を維持するようにする必要もあります。

これにより、viewModel をより小さく、より管理しやすい viewModel に分割し、それ自体を管理することができます。これにより、viewModel 間の通信の問題が残ります。

提案どおりにビューモデルをネストすると、子ビューモデルは、親ビューモデルがバインドできるイベントを公開できるため、何かが変更されたときに通知されます。このようなもの:

public class ParentViewModel // Derive from some viewModel base that implements INPC
{
    public ParentViewModel()
    {
         childViewModel = new ChildViewModel();
         childViewModel.SomeEvent += someEventHandler;
         // Don't forget to un-subscribe from the event at some point...
    }

    private void SomeEventHandler(object sender, MyArgs args)
    {
        // Update your calculations from here...
    }
}

これは簡単で、追加のフレームワークは必要ありません。この方法に反対する人もいるかもしれませんが、有効な解決策です。欠点は、イベントをサブスクライブするために、viewModel が互いの存在を認識しなければならないため、密結合になってしまう可能性があることです。ただし、標準のオブジェクト指向設計原則を使用してこれを回避できます (IE は子の viewModel をインターフェイスから派生させて、親が実装ではなくインターフェイスについてのみ知るようにします)。

本当に疎結合通信を行いたい場合は、ある種のイベント集約またはメッセージ バス システムを使用する必要があります。これは上記の方法と似ていますが、ビューモデルの間にオブジェクトがあり、メディエーターとして機能するため、ビューモデルが互いの存在を知る必要はありません。ここでの私の答えは、さらに多くの情報を提供します。

利用可能な既存のソリューションがありますが、これには追加のフレームワークを利用する必要があります。Josh Smith の MVVM 基盤を使用することをお勧めします。これは非常にシンプルであり、とにかく単一のクラスを使用するだけでよいからです。

于 2013-05-06T17:58:26.077 に答える