RSS Feed

Activity Tracker – WPF DataBinding the TabControl with TreeView

In the first post about Activity Tracker, I have created a simple style for my application. In this post, I want to show DataBinding. With this feature, we can make a flexible connection between Model and View Layer. There is no need for code. Everything is constructed in XAML language, which is similar to the HTML Markup.

Simple Binding – DataTemplate

In the first example, we have a simple DataTemplate. It contains a structured Grid,  Button and couple of TextBlocks. By assigning to the Text Property Binding logic we are telling the Template too look for a specific property in a Class, which will be used with the Template.

1 <DataTemplate x:Key="TaskTemplate"> 2 <Grid Width="200"> 3 <Grid.ColumnDefinitions> 4 <ColumnDefinition Width="5*"></ColumnDefinition> 5 <ColumnDefinition Width="1*"></ColumnDefinition> 6 <ColumnDefinition Width="1*"></ColumnDefinition> 7 <ColumnDefinition Width="3*"></ColumnDefinition> 8 </Grid.ColumnDefinitions> 9 <TextBlock Grid.Column="0" Text="{Binding Path=Title}"/> 10 <TextBlock Grid.Column="1" Text="{Binding Path=TimeSpent}"/> 11 <TextBlock Grid.Column="2" Text="{Binding Path=TimeEstimate}"/> 12 <Button Grid.Column="3">Start</Button> 13 </Grid> 14 </DataTemplate>

Template is looking for specified properties in a collection bound to the ItemsSource Property. We can also do this by the DataContext, it’s more powerful concept for another Post.



Simple DataTemplate doesn’t have the ability to automatically create a hierarchy. I could make a code and implement a logic  to get this effect but fortunately WPF have a HierarchicalDataTemplate. This special template is automatically making a hierarchical view used on the TreeViews.

1 <HierarchicalDataTemplate x:Key="TaskTemplate" 2 ItemsSource="{Binding Childrens}" DataType="{x:Type data:Task}" > 3 <Grid Width="200"> 4 <Grid.ColumnDefinitions> 5 <ColumnDefinition Width="5*"></ColumnDefinition> 6 <ColumnDefinition Width="1*"></ColumnDefinition> 7 <ColumnDefinition Width="1*"></ColumnDefinition> 8 <ColumnDefinition Width="3*"></ColumnDefinition> 9 </Grid.ColumnDefinitions> 10 <TextBlock Grid.Column="0" Text="{Binding Path=Title}"/> 11 <TextBlock Grid.Column="1" Text="{Binding Path=TimeSpent}"/> 12 <TextBlock Grid.Column="2" Text="{Binding Path=TimeEstimate}"/> 13 <Button Grid.Column="3">Start</Button> 14 </Grid> 15 </HierarchicalDataTemplate>


Task class contains a list of Childrens which is used in the HierarchicalDataTemplate.

1 public class Task 2 { 3 ..... 4 public List<Task> Childrens { get; set; } 5 ..... 6 }

HierarchicalDataTemplate has a property ItemsSource which is binded to Children’s property. The Template will create the root element and also elements from the Children’s List. I don’t have to worry about how it’s working. Magic happens behind the scene.

Binding TabControl Content

Every TabControl contains a TreeView, which is filled with Task Items. I wanted another Template, which would automatically inject the TreeView into TabControl.

1 <DataTemplate x:Key="TabItemTemplate"> 2 <Grid> 3 <TreeView Background="Transparent" ItemsSource="{Binding Content}" ItemTemplate="{StaticResource TaskTemplate}" > 4 </TreeView> 5 </Grid> 6 </DataTemplate>

TabItem Template creates a Transparent TreeView. It’s bound to the Content property. This is a property of Project class which is used to create a new TabItems with children’s injected to the TreeView.

1 public class Project 2 { 3 public string Title { get; set; } 4 public List<Task> Content { get; set; } 5 } 6  

Project class is a root for every Task set. It’s Title bound to the Header property of a TabItem.

1 <Grid Name="MainTree" Grid.Row="1" Grid.RowSpan="1"> 2 <TabControl Name="MainTabControl" ContentTemplate="{StaticResource TabItemTemplate}"> 3 </TabControl> 4  </Grid>

In order to bind the Title from the Project class to the TabItem the header, I had to change a tab item style a bit. The Content Presenter was replaced by the TextBlock which Text Property is bound to The Title.

1 <Style TargetType="TabItem"> 2 ..... 3 <Grid> 4 <StackPanel Orientation="Horizontal"> 5 <Border Name="Border" Padding="2" BorderBrush="Black" BorderThickness="1,1,1,1" 6 CornerRadius="10,10,0,0" Background="DarkOrange"> 7 <TextBlock Text="{Binding Path=Title}"></TextBlock> 8 </Border> 9 </StackPanel> 10 </Grid> 11 ..... 12  </Style>

When all is done I just need to  create sample data.

1 List<Task> tasks = new List<Task>() 2 { 3 new Task("test",10,"I",DateTime.Now,8,"komentarz"){TimeSpent = "0"}, 4 new Task("test",10,"I",DateTime.Now,8,"komentarz"){TimeSpent = "0"}, 5 new Task("test",10,"I",DateTime.Now,8,"komentarz"){TimeSpent = "0"}, 6 new Task("test",10,"I",DateTime.Now,8,"komentarz"){TimeSpent = "0"} 7 }; 8 9 10 InitializeComponent(); 11 tasks[0].Childrens = new List<Task>() 12 { 13 new Task("test",10,"I",DateTime.Now,8,"komentarz"){TimeSpent = "0"} 14 }; 15 16 List<Project> projects = new List<Project>() { new Project() { Content = tasks, Title = "Projekt1" }, new Project() { Title = "Projekt2" } }; 17 MainTabControl.ItemsSource = projects; 18  

And the result is :


Next post Timers + activity tracker logic.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s