In this article I will make a WPF project with categories from Joomla! displayed as tree view.
Create new WPF project, in my case I name it TreeViewDetailed. First I will load top level categories. For this part we will need just treeview, XAML looks like this:
<Window x:Class="TreeViewDetailed.View.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:viewModel="clr-namespace:TreeViewDetailed.ViewModel" xmlns:system="clr-namespace:System;assembly=mscorlib" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.Resources> <viewModel:TreeViewDetailedViewModel x:Key="TreeViewDetailedViewModel" /> </Grid.Resources> <TreeView DataContext="{StaticResource TreeViewDetailedViewModel}" ItemsSource="{Binding CategoriesList}"/> </Grid> </Window>
Here notice how I declared TreeView:
<TreeView DataContext="{StaticResource TreeViewDetailedViewModel}" ItemsSource="{Binding CategoriesList}"></TreeView>
Now, we will need model for our CategoriesList property:
public class CategoriesListModel { public string Name { get; set; } public int Id { get; set; } public List<CategoriesListModel> Categories { get; set; } }
Note line:
List<CategoriesListModel> Categories { get; set; }
That is because each category can have parent category, in this first part we don't need that line, we will need it later when we start loading leafs (tree view items).
Next thing is view model which we have to define. First lets declare connection string which we will use to connect to our Joomla! MySQL database. Open App.config file:
...and write your connection string in my case App.config looks like this:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name="JoomlaCon" connectionString=" SERVER=myServer; DATABASE=myDatabase; UID=myUid; PASSWORD=myPass; Convert Zero Datetime=True; " /> </connectionStrings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> </configuration>
Here note:
Convert Zero Datetime=True
without that you will receive error:
Unable to convert MySQL date/time value to System.DateTime
As I already explained here.
Next thing which you will need is to add mySql support to your references, you can download it as I explained here, or you can install it over nuget:
Then search for mySql:
After that your reference list should look like:
Now we can start building our view model:
public class TreeViewDetailedViewModel { private string JoomlaConStr = ConfigurationManager.ConnectionStrings["JoomlaCon"].ConnectionString; public List<CategoriesListModel> CategoriesList { get; set; } public TreeViewDetailedViewModel() { var connection = new MySqlConnection(JoomlaConStr); string sql = "select * from jos_categories where level = 0 order by id "; var cmdSel = new MySqlCommand(sql, connection); connection.Open(); MySqlDataReader dataReader = cmdSel.ExecuteReader(); CategoriesList = new List<CategoriesListModel>(); var i = 0; while (dataReader.Read()) { i++; CategoriesList.Add(new CategoriesListModel { Name = dataReader["title"].ToString(), Id = int.Parse(dataReader["id"].ToString()) }); } } }
Here note line:
private string JoomlaConStr = ConfigurationManager.ConnectionStrings["JoomlaCon"].ConnectionString;
with ConfigurationManager.ConnectionStrings["JoomlaCon"].ConnectionString we are calling connection string which we defined in App.config
then note line:
private List<CategoriesListModel> CategoriesList;
as you can see our CategoriesList property is defined as list of CategoriesListModel.
Now, when you start the application you should see something like:
Next thing which we will need is to display nodes in some human readable format.
We will achieve this if we change our XAML to:
<Window x:Class="TreeViewDetailed.View.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:viewModel="clr-namespace:TreeViewDetailed.ViewModel" xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:treeViewModel="clr-namespace:TreeViewDetailed.Model" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.Resources> <viewModel:TreeViewDetailedViewModel x:Key="TreeViewDetailedViewModel" /> </Grid.Resources> <TreeView DataContext="{StaticResource TreeViewDetailedViewModel}" ItemsSource="{Binding CategoriesList}"> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Categories}" DataType="{x:Type treeViewModel:CategoriesListModel}"> <TreeViewItem Header="{Binding Name}"/> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> </Grid> </Window>
Note that I added lines:
<TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Categories}" DataType="{x:Type treeViewModel:CategoriesListModel}"> <TreeViewItem Header="{Binding Name}"/> </HierarchicalDataTemplate> </TreeView.ItemTemplate>
In these lines, notice:
<HierarchicalDataTemplate ItemsSource="{Binding Categories}" DataType="{x:Type treeViewModel:CategoriesListModel}">
Where Categories is (recursive) property defined in CategoriesListModel, and then:
<TreeViewItem Header="{Binding Name}"/>
This first step you can download from here.
Now, we have to change our view model so that we load all leafs, so first our categories list we will fill like this:
CategoriesList.Add(new CategoriesListModel { Name = dataReader["title"].ToString(), Id = int.Parse(dataReader["id"].ToString()), Categories = new List<CategoriesListModel>() });
Note that I added line Categories = new List<CategoriesListModel>().
Next thing which we need is recursive load of leafs:
private void CreateListRecursively(List<CategoriesListModel> CategoriesList) { int i = -1; foreach (CategoriesListModel category in CategoriesList) { i++; var connection = new MySqlConnection(JoomlaConStr); string sql = "select * from jos_categories where parent_id = " + category.Id + " order by id "; var cmdSel = new MySqlCommand(sql, connection); connection.Open(); MySqlDataReader dataReader = cmdSel.ExecuteReader(); while (dataReader.Read()) { CategoriesList[i].Categories.Add(new CategoriesListModel { Name = dataReader["title"].ToString(), Id = int.Parse(dataReader["id"].ToString()), Categories = new List<CategoriesListModel>() }); } CreateListRecursively(CategoriesList[i].Categories); } }
And that is all... Example project you can download from here.