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:
- FavoriteFolder — an object that can have children: either folders or reports.
- FavoriteReport — an object that cannot have any children: when a user clicks on this item it will run a report.
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
INotifyPropertyChangedinterface). 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. YourObservableCollectionswould 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
ViewModelto yourViewModelLocator(I use themvvmlocatorpropertycode snippet provided in MVVM Light).Bind your
Viewto theViewModelusing theLocator. In yourUserControl, you’d put something like this in the declaration: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
ViewModelLocatoryou need to new up (instantiate) your DAL service class & pass it through yourvm = New ViewModel(MyDALService dalService)call. You also then, obviously, need to accept aMyDALServicereference in yourViewModelconstructor. Here’s an example of myEquipmentViewModelconstructor on a project I’ve worked on:This
ViewModelaccepts a parameter of theIEquipmentServicetype (which is my interface). In theLoadDatamethod, I call theEquipmentService.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. 🙂