I have a TreeView
that I (finally) have been able to populate from a database using data binding.
There are 2 objects that live in the tree:
Currently I have a Model-View type setup (I think), and I would like to change it to MVVM so I can do things with the TreeView
-items rather than simply display them.
I have looked at many examples, but I am still new to MVVM and WPF in general, so any guidance for my particular example would be much appreciated
My two classes that exist in the TreeView
are:
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 Items:
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 the 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;
}
}
My first recommendation would be to drop in an MVVM toolkit, as it's easier than having to do everything yourself (e.g. implement the INotifyPropertyChanged
interface). I use MVVM Light by Laurent Bungion.
On the assumption that you're using MVVM Light (you can extrapolate from this if you're using another toolkit)...
So, to convert this to MVVM you need to do a few things.
Create defined Models
. I generally use POCO's, simply defining the properties of a model. This means abstracting out your data access layer (more below).
Create your ViewModel
. This is where you'd have your properties that you're binding to in your veiw. Your ObservableCollections
would sit here. Initializing an instance of the classes you created would go here. Calls to your DAL layer would go here. (instead of in the constructor of your view, for example).
Add this ViewModel
to your ViewModelLocator
(I use the mvvmlocatorproperty
code snippet provided in MVVM Light).
Bind your View
to the ViewModel
using the Locator
. In your UserControl
, you'd put something like this in the declaration:
DataContext="{Binding YourViewModel, Source={StaticResource Locator}}"
I would follow Brennan Vincent's advice. I generally create a service interface (note: not a class, but an interface) that defines the methods my DAL (data access layer) will have. I do this to allow for Blendability, aka design time data. If you're not familiar with interfaces, perhaps simply a DAL class is a good way to start. Then I use dependency injection (DI) to inject an instance of my DAL Service. DI is pretty simple - in the ViewModelLocator
you need to new up (instantiate) your DAL service class & pass it through your vm = New ViewModel(MyDALService dalService)
call. You also then, obviously, need to accept a MyDALService
reference in your ViewModel
constructor. Here's an example of my EquipmentViewModel
constructor on a project I've worked on:
public EquipmentViewModel(Services.IEquipmentService equipmentService)
{
EquipmentService = equipmentService;
LoadData();
}
This ViewModel
accepts a parameter of the IEquipmentService
type (which is my interface). In the LoadData
method, I call the EquipmentService.GetEquipment()
method of my DAL that hits my database layer.
Any questions let me know. MVVM can be a pain, but I'm very happy I stuck with it. Good luck. :)
Josh Smith gave the definitive description of how to use MVVM to simplify the TreeView There's not much more I can add to it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With