2013-11-22 118 views
3

我遇到了一些與我正在使用我的mvvm應用程序的設置有關的問題。在這裏看到一些帖子後,我覺得我可能會做這個稍微錯誤的。WPF - MVVM Viewmodel設置

我有包含子模型的列表,如幾種模式:

  • 項目 - 包含形式表的列表
  • 備考 - 包含出貨orderedItems
  • 出貨名單 - 包含列表集裝箱
  • 容器 - 包含包

我們沒有任何viewmo名單與當前這些模型直接相關的dels,我們只需要擁有代表模型列表的視圖模型,例如我們有一個proformalistview模型,它只包含一個形式列表。

我的問題是,對於這個設置,我對於哪個視圖模型應該擁有哪些數據有點困惑,例如ProfomalistViewModel引用了當前選擇的項目,這些模型的所有數據管理並保存表格清單)是通過經由DI加載的管理器類來完成的。

我的問題是我應該跟隨我所看到的並且有一個包含形式列表的ProjectViewModel以及一個包含貨件和訂單列表等的ProformaViewModel。

原因是,最初沒有我們鏈接的模型,項目沒有擁有它們的代碼清單,而是通過使用選定項目ID(使用關係數據庫)的管理器單獨加載,我們目前正在將模型更改爲上述系統。

回答

4

一個ViewModel應該是用戶交互的模型的功能

例如,一個特定的區域,如果你有一個項目列表頁面,用戶可以像某些事情刪除項目編輯項目,有關項目打印信息,那麼你應該設計一個包含與此接口相關聯的數據和操作的視圖模型:

如該視圖模型應該包括:

* A bindable container for the project data (list of projects) 
* Actions that handle edit/delete interaction 
* An action to handle the print functionality 

這些行動中的實際功能可能不包含在視圖模型中(虛擬機可能會收到注射服務,如打印服務或項目資源庫),但這些執行的責任行動在於虛擬機。

也可能需要將每個數據項(項目)包裝在視圖模型中,以便可以添加額外的交互相關屬性/操作 - 比如「selected」屬性(想象用戶想要多選一個負載在視圖項目 - 你可以添加一個選擇屬性來ProjectViewModel將包裹這使得結合容易每個項目)

你最終可能會像下面這樣:

public class ProjectOverviewViewModel 
{ 
    public IList<ProjectViewModel> Projects { get;set; } 

    public ProjectViewModel SelectedProject { get;set;} 

    public void EditSelected() 
    { 
     // Code to open edit page for the selected project 
    } 

    public void Print() 
    { 
    } 
} 

ProjectViewModel用可選屬性

public class ProjectViewModel 
{ 
    // Either put the actual data item in here and wrap it: 
    public Project Project {get;set;} 

    // Or copy properties onto the viewmodel using automapper or some other mapping framework... 
    // or manually :(
    // e.g. properties mirrored from the entity object: 
    public int ProjectId { get;set;} 
    public string ProjectName { get;set;} 

    // The selected property - now your 'Selected' logic is a function of the view/viewmodel 
    // not the entity. The entity should only be concerned with data persistence 
    public bool IsSelected {get;set;} 
} 

您可能還想將視圖模型組合在一起以構建更復雜的視圖。假設您有一個項目頁面和一個「參與項目的用戶」頁面,並且您想要另一個並排顯示的頁面(並允許您單擊一個項目來刷新用戶窗格) - 這可以通過合成的ViewModels(通過創建包含兩個的ViewModels的性質和電線了兩者之間的相互作用的另一個視圖模型)

public class ProjectAndUserOverView 
{ 
    public ProjectOverviewViewModel ProjectOverview {get;set;} 
    public ProjectUsersViewModel ProjectUsers {get;set;} 

    // Code here to listen for property changes in ProjectOverview and if SelectedProject changes 
    // call ProjectUsersViewModel to refresh the data for the selected user 
} 

最終你只是模擬用戶交互,以及更模塊化,你可以把它,就越容易將是更清潔更可維護的代碼

有一些很好的MVVM框架 - 我個人喜歡的是Caliburn Micro,因爲它使上述非常簡單(它大量使用conventiontio ns),並且很容易進入。

+0

謝謝,這實際上清除了一些困惑,措辭措辭簡單,我也認識到你的名字已經回答了我的一些其他問題。謝謝!我已經使用caliburn.micro根據您的建議在另一個問題,我喜歡它。 – Ben

+0

如果有人對'selected'屬性感到困惑,我可能會清除它--ProjectOverviewViewModel中的SelectedProject將是用戶點擊的行,以便他們可以單擊編輯按鈕,並且'Selected'屬性在'ProjectViewModel'上將是一個用於多選操作的網格上的'行選擇器'(例如複選框列)。通常你會擁有一個或另一個,但不能同時擁有兩個 - 但是你可以**(你的Grid控件上的SelectedItem綁定到SelectedProject上,並且每個綁定到Selected上的每一行都有一個複選框列) – Charleh

1

我的5分是MVVM是一種模式,而不是宗教。我在遠程使用它並且合理。有許多MVVM未定義的部分(如用戶與命令的交互),並且我閱讀了很多關於ViewModel的內容,這些ViewModel只是爲了適應MVVM(這使設計和對象數量膨脹)而被創建。我建議你認爲更多的DataContext明智,如「全球利益的選擇保存在一個全球DataContext,形式相關的數據保存在一個形式DataContext」等等,其中DataContext是某種ViewModel。最後,你可能會用UI來解決這些問題。

+0

看到這裏,我總是迷失方向,如何分享全球信息,如果我正確地跟蹤你,你建議有一個類包含全局數據說活動形式,並建立一個使用它的視圖模型? – Ben

+0

是的 - 至少,這是我出於實際原因所做的。我的應用程序的很多部分都需要一次選擇(例如您的案例中的Proforma),我的特定DataContext(= VM)具有對全局數據的引用,以便我可以隨處訪問它。我不知道MVVM有什麼要說的,但我相處得很好。 –

+0

我認爲,由於ViewModel在技術上是一個視圖的模型,所以沒有以某種方式顯示的東西不是視圖模型。你描述的datacontext聽起來更像倉庫或服務 - 這是爲依賴注入創建的。但是,是的,爲了滿足模式而創建一個ViewModel確實有效,但它可能會嚮應用程序添加不必要的代碼(例如,沒有意義的是,只需要查找數據類就可以爲下拉菜單創建視圖模型,而該查找數據類只是鍵/值綁定到下拉) – Charleh

1

您不應該爲您的模型對象創建ViewModels。 一般來說,一個ViewModel應該屬於一個UserControl。它的作用是將您的視圖(您的XAML)與您的模型(業務邏輯)連接起來。在你的情況下,如果我理解正確,你有一堆實現業務邏輯的類(Project,Shipment等)。您的ViewModel將有權訪問業務邏輯,並提供視圖綁定的屬性。

+0

因此,有一個數據網格的視圖模型(如我目前有),其中包含一個形式列表比視圖模型更有意義的項目,它包含形式列表。 – Ben

+0

@ user1412240這可能是語言障礙,但我不會說你有一個ViewModel「爲你的對象」。 ViewModel屬於視圖(顯示給用戶的內容)。如果你想顯示一個項目的一些屬性,那麼你的ViewModel必須有權訪問一個項目對象。如果您只想顯示形式(我不知道這個單詞的含義),那麼最好在ViewModel中使用ObservableCollection 屬性。 – Marton

+0

Marton,是這就是我的意思,profomas只是一個在實際賬單之前發送商品的文件,它是「這是你打算購買的東西,以及我們打算向你收取多少費用」。問題出現了,ObservableCollection 屬於我當前設置中的項目模型,因爲形式屬於一個項目,或者這是不好的設計? – Ben

2

MVVM是設計模式,它有3個部分:Model,ViewModel,View。圖如下所示: enter image description here

http://en.wikipedia.org/wiki/Model_View_ViewModel#Pattern_description

您使用的ViewModels錯了。只有用於顯示的數據應該在ViewModel中。 您例如型號:

public class Project 
{ 
    public Proforma Pr{get;set;} 
} 

public class Proforma 
{ 
    public string Name{get; set;}; 
} 

你查看項目顯示(我注入視圖模型來構造,土特產品可以使用的DataContext代替):

public partial class ProjectView 
{ 
    private ProjectViewModel vm; 
    public ProjectView(ProjectViewModel vm) 
    { 
     this.vm = vm; 
    } 
} 

如果你想顯示在項目視圖備考名,你應該在ViewModel中以字符串形式提供它。 public class ProjectViewModel { private project pr; 公共字符串ProformaName {獲得{返回pr.Pr.Name;}} }

如果您提供類似形式的形式,您的視圖將知道模型。這將違反該模式。

+0

但即時顯示數據網格形式列表,所以viewmodel有一個項目和項目有一個ObservableCollection 視圖模型暴露給視圖,視圖永遠不會知道模型,因爲它只是綁定到模型列表viewmodel公開。 – Ben

+1

我並不完全同意這一點:雖然我同意分離,但在這種情況下,視圖並不真正使用模型。如果要用另一個對象替換ViewModel中的模型引用,只要它具有相同的屬性,綁定仍然可以工作。如果通過將代碼隱藏直接引入模型類型**的視圖來直接影響模型,那麼視圖/模型會耦合違反模式。綁定是一個完全不同的球類遊戲,並且爲了綁定一些屬性而創建一個視圖模型有時可能是矯枉過正的。 – Charleh

1

我沒有看到任何包含模型數據對象的視圖模型的問題。視圖模型不一定是「每個視圖一個」。它們可以代表列表中的一行或其他內容。

話雖如此,我很高興直接綁定到模型對象,我做了很多。我創建一個視圖模型來包裝它的唯一時間是如果我需要視圖所需的每個對象的額外狀態。

+0

看到了這一點,如果我要創建一個視圖模型來包裝數據對象,它只是爲了滿足模式,並且實際上沒有用,因爲90%的模型只能在數據網格中顯示 – Ben

+0

如果是這種情況,那麼不要這樣做。數據項的包裝不是必需的,但可以用於添加額外的非實體屬性,如未選中的行標記或聚合總數,這些屬性不會保留到數據存儲區 – Charleh

+1

否,根據我的第二段,只有在需要時才做。僅僅爲了滿足一些純粹的MVVM模式是沒有意義的。綁定到模型是好的,如果它給你你需要的一切。 – GazTheDestroyer