WPF中的视图和视图模型

Tad*_*ada 0 c# wpf mvvm backgroundworker viewmodel

我一直在使用WPF中的MVVM,并且对于人们有一个快速的问题.现在我有:

  • MainWindow由MenuBar和UserControl组成
  • UserControl(如上所述)基本上包含一个Grid.

我在UserControl中公开了对Grid Properties的访问,但是User Control不知道什么也不与MainWindow交互.

我还有一个我调用ViewModel的类,它为我操作MainWindow/UserControl.我的理解是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();
    }
    
    Run Code Online (Sandbox Code Playgroud)

View Model看起来像这样:

    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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的方法在这里偏离基础吗?

编辑新解决方案: 首先,感谢大家的回应.我想提供我的新解决方案.这可能不是100%的MVVM,但它必须至少比我的好80%!

我的ViewModel:

    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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

我已经从MainWindow和UserControl后面删除了所有代码,并将其替换为XAML,用于将我需要的元素绑定到ViewModel和1 Command中的两个属性.请随意提供有关我可能会或可能没有重新考虑因素的额外反馈.(除了缺乏模型用法).

Dan*_*rth 5

你离这里很.

  1. 反过来说:View了解ViewModel,而ViewModel对View一无所知.
    在ViewModel中引用MainWindow和UserControl 不是 MVVM.

  2. 使用MVVM时,通常没有点击处理程序.

处理这种情况的正确方法如下:

  • 在ViewModel中将ICommand作为属性公开.MainWindow可以将其按钮绑定到该命令.
  • 在ViewModel中调用该命令时,执行RunQuery,但您只需将IsBusy ViewModel设置 为true即可.然后,UserControl将绑定到该属性.

所有这些都可以通过将DataContextView 设置为ViewModel的实例来实现.

  • @Tada`DataContext`被继承,所以如果你的`MainWindow`有一个`ViewModel`的`DataContext`,那么你的`ContentControl`也会有一个你的`ViewModel`的DataContext,你不要把它设置为任何东西其他.我实际上在我的博客上有[数据上下文的概述](http://rachel53461.wordpress.com/2012/07/14/what-is-this-datacontext-you-speak-of/)以及你可能有兴趣阅读:) (2认同)