2011-06-22 17 views
4

我有一個TreeView,我終於可以使用數據綁定從數據庫中填充。WPF:MVVM中的TreeView

有2個對象是居住在樹:

  • FavoriteFolder - 一個對象,可以有孩子:無論是文件夾或報表。
  • FavoriteReport - 一個不能有任何孩子的對象:當用戶點擊這個項目時,它會運行一個報告。

目前,我有一個模型 - 視圖類型的設置(我認爲),我想將它更改爲MVVM,所以我可以做的事情與TreeView -items而不是簡單地顯示出來。

我已經看過很多例子,但我還是新的MVVM和WPF一般,所以對我特別的例子任何指導,將不勝感激

我的兩個存在於TreeView類:

文件夾項目:

public class FavoriteFolder 
{ 
    private string _connectionString = new ServerInfo().ConnectionString; 
    private string _folderID; 
    private string _parentID; 
    private string _folderTitle; 

    private ObservableCollection<FavoriteFolder> _folders; 
    private ObservableCollection<FavoriteReport> _reports; 
    private ObservableCollection<object> _children; 

    public FavoriteFolder() 
    { 

    } 

    public ObservableCollection<object> Children 
    { 
     get 
     { 
      _getChildren(); 
      return _children; 
     } 
    } 

    public string FolderID 
    { 
     get { return _folderID; } 
     set { _folderID = value; } 
    } 

    public string ParentID 
    { 
     get { return _parentID; } 
     set { _parentID = value; } 
    } 

    public string FolderTitle 
    { 
     get { return _folderTitle; } 
     set { _folderTitle = value; } 
    } 

    private void _getChildren() 
    { 
     _folders = new ObservableCollection<FavoriteFolder>(); 
     _reports = new ObservableCollection<FavoriteReport>(); 

     using (SqlConnection cnn = new SqlConnection(_connectionString)) 
     { 
      cnn.Open(); 
      string sql = "SELECT * FROM tbl_report_folders where fdr_parent_id =" + _folderID; 
      SqlCommand cmd = new SqlCommand(sql, cnn); 

      SqlDataReader reader = cmd.ExecuteReader(); 

      while (reader.Read()) 
      { 
       FavoriteFolder folder = new FavoriteFolder(); 

       folder.FolderID = reader["fdr_folder_id"].ToString(); 
       folder.FolderTitle = reader["fdr_folder_name"].ToString(); 
       folder.ParentID = reader["fdr_parent_id"].ToString(); 

       _folders.Add(folder); 
      } 

      reader.Close(); 

      sql = "SELECT * FROM tbl_reports where rpt_folder_id =" + _folderID; 
      cmd = new SqlCommand(sql, cnn); 

      reader = cmd.ExecuteReader(); 

      while (reader.Read()) 
      { 
       FavoriteReport report = new FavoriteReport(); 

       report.ReportID = reader["rpt_report_id"].ToString(); 
       report.ReportTitle = reader["rpt_report_name"].ToString(); 
       report.ParentID = reader["rpt_folder_id"].ToString(); 

       _reports.Add(report); 
      } 
     } 

     //add the children to the collection 
     foreach (var folder in this._folders) 
      _children.Add(folder); 

     foreach (var report in this._reports) 
      _children.Add(report); 
    } 
} 

報告項目:

public class FavoriteReport 
{ 
    private string _reportID; 
    private string _parentID; 
    private string _reportTitle; 

    public FavoriteReport() 
    { 

    } 

    public string ReportID 
    { 
     get { return _reportID; } 
     set { _reportID = value; } 
    } 

    public string ParentID 
    { 
     get { return _parentID; } 
     set { _parentID = value; } 
    } 

    public string ReportTitle 
    { 
     get { return _reportTitle; } 
     set { _reportTitle = value; } 
    } 
} 

而且MainWindow.xaml.cs -

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     ObservableCollection<object> items = new ObservableCollection<object>(); 

     FavoriteFolder fdr = new FavoriteFolder(); 

     fdr.FolderID = "0"; 

     items = fdr.Children; 

     this.DataContext = items; 
    } 
} 
+0

我不是設計專家,但是不會讓您的數據訪問邏輯與您的模型分離很多嗎? –

+0

我同意,你認爲是否創建了一個與數據庫接口的獨立類,該類有返回子元素或其他方法的方法? – ChandlerPelhams

回答

3

我的第一個建議是在MVVM工具包丟棄,因爲它不必自己做的一切更容易(例如實現接口INotifyPropertyChanged)。我使用MVVM Light by Laurent Bungion

在您使用MVVM光(你可以,如果你使用其他工具包從這個推斷)的假設......

所以,將它轉換爲MVVM你需要做一些事情。

  1. 創建定義Models。我通常使用POCO,只是定義模型的屬性。這意味着抽象出你的數據訪問層(更多)。

  2. 創建您的ViewModel。這是你在你的視角中擁有你的財產的地方。你的ObservableCollections會坐在這裏。初始化你創建的類的一個實例將會在這裏。調用你的DAL層將會在這裏。 (而不是在你的視圖的構造函數中)。

    將此ViewModel添加到您的ViewModelLocator(我使用MVVM Light中提供的mvvmlocatorproperty代碼片段)。

    使用LocatorView綁定到ViewModel。在你UserControl,你就會把這樣的宣言:

    DataContext="{Binding YourViewModel, Source={StaticResource Locator}}" 
    
  3. 我會按照布倫南文森特的建議。我通常創建一個定義我的DAL(數據訪問層)方法的服務接口(注意:不是類,而是接口)。我這樣做是爲了考慮混合性,也就是設計時間數據。如果你不熟悉接口,也許簡單的DAL類是一個很好的開始。然後我使用依賴注入(DI)來注入我的DAL服務的一個實例。 DI非常簡單 - 在ViewModelLocator中,您需要更新(實例化)您的DAL服務類&將其傳遞給您的vm = New ViewModel(MyDALService dalService)調用。顯然,您還需要在ViewModel構造函數中接受MyDALService引用。這裏有一個項目,我已經對我的工作構造EquipmentViewModel的例子:

    public EquipmentViewModel(Services.IEquipmentService equipmentService) 
    { 
        EquipmentService = equipmentService; 
        LoadData(); 
    } 
    

ViewModel接受IEquipmentService類型的參數(這是我的接口)。在LoadData方法中,我調用了我的DAL的EquipmentService.GetEquipment()方法,它碰到了我的數據庫層。

有任何問題讓我知道。 MVVM可以是一個痛苦,但我很高興我堅持下去。 祝你好運。 :)

+0

有一件事我不瞭解MVVM;該模型。假設我有一個帶有'Foo'集合的模型。現在我想將集合綁定到我的UI控件,那麼我需要在ViewModel中創建另一個集合,並將其與模型集合保持同步?希望我錯過了一些東西,因爲這對我來說似乎很荒謬。 –

+0

爲什麼你只有一個只有'Foo'集合的模型?創建一個名爲'Foo'的模型(又名Foo的單個實例,而不是集合),並且在您的視圖模型中,在那裏創建一個「Foo」類的集合。 –

+0

顯然這是一個例子...好吧,我有一個模型,一個ID,一個Foo的集合,一個名字是一個字符串。這有幫助嗎?無論如何,你的例子在語義上與我所問的不同。你不能想象一個集合類型的模型嗎?它適用於任何類型。我沒有看到有一個模型的目的,然後是一個ViewModel,它本質上模仿了所有這些屬性,併爲視圖提供了PropertyChanged通知。就像我說的,我一定會錯過一些東西,因爲那隻會是......愚蠢的。 –

1

喬希史密斯給出瞭如何使用的明確說明MVVM to simplify the TreeView我可以添加更多的東西。

+0

我已閱讀過那篇文章(幾次),但由於我仍然在學習某些方面對我沒有意義......根據他的解決方案,我需要創建一些類型的treeviewitem視圖模型,該文件夾和報告視圖模型類會來自?另外,我並不十分清楚在TreeViewItemViewModel類Josh中使用的「DummyChild」用於 – ChandlerPelhams

+0

dummychild用於延遲加載。在這種情況下,treeviewitem的孩子只能按需求加載。 Bea Stollnitz(nee Costa)在她的博客中討論數據虛擬化。 –