0

私は WPF で MVVM をいじっていて、人々に簡単な質問があります。今私は持っています:

  • MenuBar と UserControl で構成される MainWindow
  • UserControl (前述) には、基本的に Grid が含まれています。

UserControl で必要に応じて Grid プロパティへのアクセスを公開しますが、User Control は何も認識せず、MainWindow と対話しません。

MainWindow/UserControl を操作する ViewModel というクラスもあります。私の理解では、ViewModel は View (MainWindow/UserControl) とそれを操作する方法について知っていますが、View は通常 ViewModel について何も知りません。

私がその権利を持っている場合、ここに私の質問があります:

  1. MainWindow MenuBar でボタンをクリックすると、アクションを実行したいと思います。現在、これらのアクションは MainWindow 内の EventHandler にバインドされており、EventHandler は ViewModel をインスタンス化し、次のように処理するためのメソッドを呼び出します。

    private void RunQueryMenuItemAdvClick(object pSender, RoutedEventArgs pRoutedEventArgs)
    {
        ViewModel vViewModel = new ViewModel(this);
        vViewModel.RunQuery();
    }
    

ビュー モデルは次のようになります。

    public class ViewModel
{
    private DataProvider fDataProvider;

    private MainWindow fMainWindow;

    private BackgroundWorker fQueryWorker = new BackgroundWorker();

    public ViewModel(MainWindow pMainWindow)
    {
        fDataProvider = new DataProvider();
        fMainWindow = pMainWindow;

        //Query Worker
        fQueryWorker.DoWork += QueryWorkerDoWork;
        fQueryWorker.RunWorkerCompleted += QueryWorkerCompleted;
    }

    private void QueryWorkerCompleted(object pSender, RunWorkerCompletedEventArgs pRunWorkerCompletedEventArgs)
    {
        fMainWindow.UserControl_Data.busyIndicator1.IsBusy = false;
        fMainWindow.UserControl_Data.DataToPresent = pRunWorkerCompletedEventArgs.Result;
    }

    private void QueryWorkerDoWork(object pSender, DoWorkEventArgs pDoWorkEventArgs)
    {
        pDoWorkEventArgs.Result = this.fDataProvider.GetParticipantsData();
    }

    public void RunQuery()
    {
        if (!fQueryWorker.IsBusy)
        {
            fMainWindow.UserControl_Data.busyIndicator1.IsBusy = true;
            fQueryWorker.RunWorkerAsync();
        }
    }
}

ここでの私のアプローチはベースから外れていますか?

新しいソリューションの編集: まず、応答してくれた皆さんに感謝します。新しいソリューションを提供したいと思います。これは 100% MVVM ではないかもしれませんが、私が持っていたものより少なくとも 80% 優れている必要があります!

私のビューモデル:

    public class ViewModel : ObservableObject
{
    private DataProvider fDataProvider;

    private BackgroundWorker fQueryWorker = new BackgroundWorker();


    public ViewModel()
    {
        fDataProvider = new DataProvider();

        //Query Worker
        fQueryWorker.DoWork += QueryWorkerDoWork;
        fQueryWorker.RunWorkerCompleted += QueryWorkerCompleted;
    }

    //This is my Command for the MainWindow.MenuItem to bind to to run a query
    RelayCommand fRunQueryCommand;
    public ICommand RunQueryCommand
    {
        get
        {
            if (this.fRunQueryCommand == null)
            {
                this.fRunQueryCommand = new RelayCommand(param => this.RunQuery(),
                    param => true);
            }
            return this.fRunQueryCommand;
        }
    }

    //This is my Property for the UserControl.progressBar to bind to
    private bool fIsBusy;
    public bool IsBusy
    {
        get { return this.fIsBusy; }
        set
        {
            if (value != this.fIsBusy)
            {
                this.fIsBusy = value;
                OnPropertyChanged("IsBusy");
            }
        }
    }

    //This is my Property for the UserControl.gridControl.ItemSource to bind to
    private object fSource;
    public object Source
    {
        get { return this.fSource; }
        set
        {
            if (value != this.fSource)
            {
                this.fSource = value;
                OnPropertyChanged("Source");
            }
        }
    }

    private void QueryWorkerCompleted(object pSender, RunWorkerCompletedEventArgs pRunWorkerCompletedEventArgs)
    {
        this.IsBusy = false;
        Source = pRunWorkerCompletedEventArgs.Result;
    }

    private void QueryWorkerDoWork(object pSender, DoWorkEventArgs pDoWorkEventArgs)
    {
        pDoWorkEventArgs.Result = this.fDataProvider.GetParticipantsData();
    }

    public void RunQuery()
    {
        if (!fQueryWorker.IsBusy)
        {
            this.IsBusy = true;
            fQueryWorker.RunWorkerAsync();
        }
    }

MainWindow と UserControl の背後にあるすべてのコードを削除し、必要な要素を ViewModel と 1 Command の 2 つのプロパティにバインドするために XAML に置き換えました。私がリファクタリングで気づいたかもしれないし、気づいていないかもしれないことについて、追加のフィードバックをお気軽に提供してください。(モデルの使用法がないことは別として)。

4

2 に答える 2

5

あなたはここで基地から離れています

  1. これは逆です。View は ViewModel について認識しており、ViewModel は View について何も認識していません。
    ViewModel で MainWindow と UserControl への参照を持つことは、 MVVMではありません。

  2. MVVM を使用する場合、通常、クリック ハンドラーはありません。

この状況を処理する正しい方法は次のとおりです。

  • ViewModel で ICommand をプロパティとして公開します。MainWindow は、そのボタンをそのコマンドにバインドできます。
  • コマンドが ViewModel 内で呼び出されると、 を実行しますが、ViewModel を trueにRunQuery設定するだけです。次に、UserControl がそのプロパティにバインドされます。IsBusy

DataContextこれはすべて、View の を ViewModel のインスタンスに設定することで機能します。

于 2012-09-12T16:29:41.347 に答える
2

ViewModelsダニエルは、あなたがMVVMデザインパターンを誤解しているように見え、実際にUIオブジェクトを参照してはならないということは正しいです。

パターンを説明するために私が考えることができる最良の方法は、あなたViewModelsが実際のアプリケーションであり、あなたModelsがデータオブジェクトであり、Viewsユーザーがあなたと対話できるようにするためのユーザーフレンドリーな方法ViewModelsです。完璧な世界では、テストスクリプトを完全に使用してアプリケーションを実行でき、Viewレイヤーをまったく使用しないでください。

たとえば、ViewModelはアプリケーションであるため、List<ICommand> MenuCommandsそれぞれICommandがコード内のメソッドを指すRelayCommandまたはである、とブールプロパティを持つ場合があります。DelegateCommandIsBusy

ビュー(ウィンドウ)は<Menu>、コレクションにバインドし、ブール値MenuCommandsに基づいた読み込みグラフィックを表示することで、ViewModelを反映するだけです。IsBusy

簡単なMVVMの例を最初から最後まで見ることに興味がある場合は、ブログにかなり基本的なMVVMの例があります。

于 2012-09-12T16:35:51.527 に答える