Multi level Nested TreeView with Dynamic Binding in WPF - wpf

I am trying to create an application in which i require to display employees and their departments in the treeview kind of structure as below :
Employee1
Department
Dept1
Dept2
Employee2
Department
Dept3
Dept4
how could i do this with WPF ?

The correct way to do this is to use a HierarchicalDataTemplate. The most basic one I can imagine is the following:
<UserControl.Resources>
<HierarchicalDataTemplate
x:Key="RecursiveData" DataType="TreeViewItem" ItemsSource="{Binding Items}">
</HierarchicalDataTemplate>
</UserControl.Resources>
Which can be used in the XAML as follows:
<TreeView ItemTemplate="{StaticResource RecursiveData}" />
Of course you can customize the template at will with styles and subcomponents.
Note that the ItemSource of your TreeView needs to actually provide nested TreeViewItems where each TreeViewItem contains it's subitems in Items.

If you've structure like this:
public ObservableCollection<ChartOfAccount> ChartOfAccounts { get; set; }
public class ChartOfAccount
{
public Book Book { get; set; }
public List<LedgerHierarchy> ControlLedgers { get; set; }
}
public class LedgerHierarchy
{
public ControlLedger ControlLedger { get; set; }
public ObservableCollection<Ledger> Ledgers { get; set; }
}
you could bind directly in TreeView like this:
<TreeView ItemsSource="{Binding ChartOfAccounts}"
BorderThickness="0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemContainerStyle="{StaticResource treeStyle}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ControlLedgers}">
<TextBlock Text="{Binding Book.Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Ledgers}">
<TextBlock Text="{Binding ControlLedger.Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
instead of creating HierarchicalDataTemplate in Control.Resource.

Related

Set TreeView HierarchicalDataTemplate with 2 levels in WPF

I have a View Model that is represented in the DataContext of the window.
public class SchoolViewModel:ViewModelBase
{
public ObservableCollection<SchoolClassGroup> ClassesCollection { get; set; }
....
}
public class SchooleClassGroup:ViewModelBase
{
public string ClassName {get;set;}
public string TeacherName {get;set;}
public ObservableCollection<Students> StudentCollection{ get; set; }
}
public class Student
{
public string Name {get;set;}
public int Age {get;set;}
public DateTime BirthDate {get;set;}
...
}
I want to represent a TreeView that will show me schools,class and students.
How can I do it?
Thanks!
You need to create HeirarchicalDataTemplates for each level of your object tree that has a Parent-Child relationship, plus a simple DataTemplate for the leaf node.
Your object tree should be School -> Class -> Student
class School has a
List<Class>
class Class has a
List<Student>
Then it's simple
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Classes}" DataType="{x:Type School}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Students}" DataType="{x:Type Class}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type Student}">
<TextBlock Text="{Binding Name}" />
</DataTemplate >
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding Schools}" >
</Grid>

Rendering Collection of collections - ItemsControl

I have an object model like below:
public class ViewModel
{
public List<Group> Groups{ get; set; }
}
public class Group
{
public string Name { get; set; }
public List<Contact> Contacts { get; set; }
}
public class Contact
{
public string Name { get; set; }
public bool IsOnline { get; set; }
}
and I'm binding the groups to an itemscontrol like this:
<ItemsControl ItemsSource="{Binding Path=Groups}"
ItemTemplate="{StaticResource GroupTemplate}" >
</ItemsControl>
and I have datatemplate for rendering them.
<DataTemplate x:Key="GroupTemplate" DataType="{x:Type Group}">
</DataTemplate>
<DataTemplate x:Key="ContactTemplate" DataType="{x:Type Contact}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanle>
</DataTemplate>
How can I get the contacts displayed inside the items control? The contacts is a collection inside each group and my viewmodel has a collection of groups. To complicate it a bit further, I have different datatemplates for different contacts, and I should be using a datatemplateselector for choosing the appropriate contact template. Also please note, I have nothing to display in the group template, and I only need to show Contacts.
Thanks,
-Mike
Use another ItemsControl in the first template:
<DataTemplate x:Key="GroupTemplate" DataType="{x:Type my:Group}">
<ItemsControl ItemsSource="{Binding Contacts}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type my:Contact}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
And with a template selector:
<DataTemplate x:Key="GroupTemplate" DataType="{x:Type my:Group}">
<ItemsControl ItemsSource="{Binding Contacts}"
ItemTemplateSelector="{StaticResource yourContactItemSelector}"/>
</DataTemplate>

Using Commands in WPF TreeView with HierarchicalDataTemplate

is there a way to use commands in a treeview with a HierarchicalDataTemplate, so that i can react on the click on an item in the treeview?
i would prefer a solution without code-behind if there is one.
Here is my TreeView:
<TreeView ItemsSource="{Binding Main.TreeItems}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=Header}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
provide an property of type ICommand on your Item (ViewModel) and Bind to that. So your item class would be something like:
class MyTreeItem
{
public MyTreeItem()
{
this.SomeCommand = /* create command here */ null;
this.Children = new ObservableCollection<MyTreeItem>();
}
public ICommand SomeCommand { get; private set; }
public ObservableCollection<MyTreeItem> Children { get; private set; }
}
In xaml you can then write:
<TreeView ItemsSource="{Binding Main.TreeItems}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
<TextBlock Text="{TemplateBinding Header}" />
<Button Text="My Command" Command="{TemplateBinding SomeCommand}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
I think that should work, at least it did similarily last time i used that :)

How to Dynamically Populate a treeView in WPF getting value from database?

I want to populate a tree getting parent and nodes from database in WPF. My database structure is as;
Here deficiencyID is the id of the node and parentID is the id of the parent.
You can model your db table with an entity like this:
public class Deficiency
{
public int DeficiencyID { get; set; }
public int ParentID { get; set; }
//... OTHER PROPERTIES ...//
}
then take a look at this answer.
EDIT: Your XAML with the treeview can be like this:
<!--Bind to Groups generated from codebehind
Every group have property Name and Items -->
<TreeView Name="treeview1" ItemsSource="{Binding Groups}" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Items}">
<!-- Here Bind to the name of the group => this is the Parent ID -->
<TextBlock Text="{Binding Path=Name}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- Here the data context is your class Deficiency,
so bind to its properties-->
<TextBlock Text="{Binding Path=DeficiencyID}"/>
<!-- ... -->
<TextBlock Text="{Binding Path=OtherProperties}"/>
<!-- ... -->
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
and your codebehind should be something like this:
List<Deficiency> myList = new List<Deficiency>();
// here load from DB //
ICollectionView view = CollectionViewSource.GetDefaultView(myList);
view.GroupDescriptions.Add(new PropertyGroupDescription("ParentID"));
treeview1.DataContext = view;
HTH

Treeview binding problem

I have a window MainWindow.xaml and
private static Tutorial tutorial; there.
Also I have class Structure.cs where I describe child types
public class Tutorial
{
public string Name { get; set; }
public IList<Chapter> Chapters = new List<Chapter>();
}
public class Chapter
{
public string Name { get; set; }
public IList<Unit> Units = new List<Unit>();
}
public class Unit
{
public string Name { get; set; }
public IList<Frame> Frames = new List<Frame>();
...
}
I want to bind tutorial structure to treeview. How can I do this?
I tried this way.
<TreeView Grid.Row="2" x:Name="treeViewStruct" Margin="5,0,5,0" Background="LemonChiffon" BorderBrush="Bisque" BorderThickness="1" ScrollViewer.VerticalScrollBarVisibility="Auto" IsTextSearchEnabled="True" Cursor="Hand">
<TreeView.Resources>
<HierarchicalDataTemplate DataType = "{x:Type Structure:Chapter}"
ItemsSource = "{Binding Path=Units}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type Structure:Unit}">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</TreeView.Resources>
</TreeView>
It doesn't work.
Please, help! I'm a newbie in WPF. I need dynamic tree
so that when I add a chapter or a unit in the object tutorial, tree is updated.
And for this way of binding please throw the idea how can I get a collection item, when I selected some tree node.
This may help :
<HierarchicalDateTemplate DataType = "{x:Type local:Tutorial}"
ItemsSource="{Binding Chapters}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDateTemplate>
<HierarchicalDateTemplate DataType = "{x:Type local:Chapter}"
ItemsSource="{Binding Units}"
<TextBlock Text="{Binding Name}"/>
</HierarchicalDateTemplate>
<DateTemplate DataType = "{x:Type local:Unit}"
<TextBlock Text="{Binding Name}"/>
</DateTemplate>

Resources