2012-09-12 150 views
0

我一直在使用WPF中的MVVM,併爲人們提供了一個快速的問題。現在,我有:在WPF中查看和查看模型

  • 主窗口它由一個菜單欄和一個用戶控件
  • 用戶控件(上述)的基本上包含一個網格。

我公開對網格屬性的訪問,因爲我需要在UserControl中,但用戶控件一無所知,也不與MainWindow交互。

我也有一個類,我調用ViewModel,它爲我操作MainWindow/UserControl。我的理解是,ViewModel知道View(MainWindow/UserControl)以及如何操作它,而View通常對ViewModel一無所知。

如果我有這個權利,這是我的問題:

  1. 當我在主窗口菜單欄按鈕點擊我要執行的操作。現在,這些措施在不能不說,在主窗口一個事件處理程序和事件處理程序實例化視圖模型,並調用方法來處理類似這樣的:

    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(); 
     } 
    } 

我和XAML刪除了所有我的代碼從主窗口和用戶控件後面,取代它綁定,我需要在視圖模型的兩個屬性和1的元素命令。隨意提供額外的反饋,說明我可能會或可能沒有選擇重新分解。 (除了缺少模型使用)。

回答

5

你是方式在這裏偏離基地。

  1. 這是相反的:視圖知道ViewModel和ViewModel對視圖一無所知。
    對ViewModel中的MainWindow和UserControl的引用是,而不是 MVVM。

  2. 當你使用MVVM時,你通常沒有點擊處理程序。

來處理這種情況將是以下正確的方法:

  • 在您的視圖模型公開一個ICommand的一個屬性。 MainWindow可以將其按鈕綁定到該命令。
  • 當在ViewModel中調用該命令時,執行RunQuery,但您只需將ViewModel上的IsBusy設置爲true即可。 UserControl反過來將綁定到該屬性。

所有這些都可以通過將View的DataContext設置爲ViewModel的實例來工作。

+0

感謝您的答覆。我一直在通過一些重構來完成整理。快速提問 - 我想將控件的屬性綁定到ViewModel的IsBusy屬性,但是,我沒有爲UserControl設置「DataContext」。我明白這個錯誤,但是爲MainControlow中的UserControl設置上下文的正確方法是什麼(誰已經設置了DataContext) – Tada

+2

@Tada DataContext被繼承,所以如果你的MainWindow有一個'你的'ViewModel'的DataContext',那麼你的'ContentControl'也會有''ViewModel''的DataContext,假設你沒有設置它。我的博客中實際上有一個[數據上下文的概述](http://rachel53461.wordpress.com/2012/07/14/what-is-this-datacontext-you-speak-of/),以及你可能有興趣閱讀:) – Rachel

+0

@Rachel - 感謝您的回覆。你的博客很棒。非常容易閱讀和理解!保持這些博客,並不斷回答我的問題!我的問題不像我想的那樣是DataContext,實際上是我忘了繼承ObserverableObject類並引發屬性更改! – Tada

2

丹尼爾是正確的,你似乎是誤解了MVVM設計模式,並且你的ViewModels不應該實際引用任何UI對象。我能想到的來形容模式

最好的辦法是你ViewModels是你的實際應用中,你Models是你的數據對象,和你的Views只是一個用戶友好的方式,讓用戶與您的互動ViewModels。在完美的世界中,您可以完全使用測試腳本來運行您的應用程序,並且永遠不會使用View層。

例如,您的視圖模型是應用程序,所以它可能有一個List<ICommand> MenuCommands,每個ICommand是一個RelayCommandDelegateCommand指向你的代碼的方法,和一個布爾IsBusy屬性。

您的視圖(窗口)通過將您的<Menu>綁定到MenuCommands集合,並可能顯示基於IsBusy布爾值的一些加載圖形來簡單反映您的ViewModel。

我有一個相當basic MVVM example on my blog如果你有興趣在看到從開始一個簡單的例子MVVM完成

+0

您的博客非常有幫助。我已經使用它開始重新分解我現在的WPF應用程序。 – Tada