WPF: TreeView in MVVM

I have a TreeView that I (finally) was able to populate from a database using data binding.

There are two objects in the tree:

  • FavoriteFolder - an object that can have children: either folders or reports.
  • FavoriteReport - an object that cannot have children: when the user clicks on this element, he will run the report.

Currently, I have a Model-View type setting (I think), and I would like to change it to MVVM so that I can do something with TreeView elements, and not just display them.

I looked at a lot of examples, but I'm still new to MVVM and WPF in general, so any guidance for my specific example would be much appreciated

My two classes that exist in TreeView are as follows:

Folder Items:

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

Report Elements:

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

And 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; } } 
+4
source share
2 answers

My first recommendation would be to abandon the MVVM toolkit, as this is easier than doing everything yourself (for example, implementing the INotifyPropertyChanged interface). I am using MVVM Light from Laurent Bungion .

Assuming you are using MVVM Light (you can extrapolate this if you use other tools) ...

So, in order to convert this to MVVM, you need to do a few things.

  • Create specific Models . I usually use POCO, simply defining the properties of the model. This means abstracting the level of data access (see below for more details).

  • Create your ViewModel . Here you will find your properties that you attach in your application. Here will be ObservableCollections . The initialization of the instance of the classes you created will go here. Calls to your DAL level will go here. (and not in the constructor of your view, for example).

    Add this ViewModel to your ViewModelLocator (I use the mvvmlocatorproperty code mvvmlocatorproperty provided in MVVM Light).

    Bind View to ViewModel using Locator . In UserControl you would add something like an declaration:

     DataContext="{Binding YourViewModel, Source={StaticResource Locator}}" 
  • I would advise Brennan Vincent. Usually I create a service interface (note: not on the class, but on the interface), which defines the methods of my DAL (data access level). I do this to enable blendability as well as development time data. If you're not familiar with interfaces, maybe just the DAL class is a good way to get started. Then I use dependency injection (DI) to inject an instance of my DAL service. DI is quite simple - in ViewModelLocator you need to update (instantiate) your DAL service class and pass it through your vm = New ViewModel(MyDALService dalService) . You should also obviously accept the MyDALService link in your ViewModel constructor. Here is an example of my EquipmentViewModel constructor in a project I was working on:

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

This ViewModel takes a parameter of type IEquipmentService (which is my interface). In the LoadData method LoadData I call the EquipmentService.GetEquipment() method of my DAL, which falls into my database level.

Any questions let me know. MVVM can be a pain, but I am very glad that I was stuck with it. Good luck. :)

+3
source

Josh Smith gave a final description of how to use MVVM to simplify TreeView. There is not much more I can add to it.

+1
source

All Articles