Friday, July 20, 2012

How to customize the look and feel of WPF tree view? [part1]

Why we need to customize Tree view?

Intention is to modify default look and feel so that we can use the tree view as custom purpose control not just hierarchical data structure, a good example could be a folder explorer.

In this short article we are going to see how to customize tree view look and feel. first we will look at how to customize the style of a tree view item, then move on to the expand and collapse icon, and lastly we would see how to style a selected item.

image_thumb11_thumb2

Styling the items

Lets say we want to display a icon before each tree view “item node” so that the user knows what type of file item it is, right now we have drive, directory and file, so we would add thee resources to display. Bellow a simple code is given to demonstrate how to read a file system, and then populate in a dependency object so that it can be bind to a tree view.

[Sample c# code]

using System.Collections.Generic;
using System.IO;
using System.Windows;

namespace WPFFolderExplorer
{
public class FileSystemPresenter : DependencyObject
{
public FileSystemPresenter()
{
LoadFileSystem();
}

private void LoadFileSystem()
{
var liteDirectoryInfos = new List<LiteDirectoryInfo>();
var driveInfos = DriveInfo.GetDrives();
foreach (var driveInfo in driveInfos)
{
if (driveInfo.DriveType == DriveType.Fixed)
{
var liteDirectoryInfo = new LiteDirectoryInfo
{
FileName = driveInfo.Name,
FileType = FileType.Drive
};
var info = new DirectoryInfo(driveInfo.Name);
var directoryInfos = info.GetDirectories();
foreach (var directoryInfo in directoryInfos)
{
liteDirectoryInfo.Files.Add(new LiteDirectoryInfo
{ FileName = directoryInfo.Name,
FileType = FileType.Folder });
}
liteDirectoryInfos.Add(liteDirectoryInfo);
}
}
FileSystem = liteDirectoryInfos;
}

public List<LiteDirectoryInfo> FileSystem
{
get { return (List<LiteDirectoryInfo>)GetValue(FileSystemProperty); }
set { SetValue(FileSystemProperty, value); }
}

public static readonly DependencyProperty FileSystemProperty =
DependencyProperty.Register("FileSystem", typeof(List<LiteDirectoryInfo>),
typeof(FileSystemPresenter), new UIPropertyMetadata(null));
}

public class LiteDirectoryInfo
{
public LiteDirectoryInfo()
{
Files = new List<LiteDirectoryInfo>();
}
public string FileName { get; set; }
public FileType FileType { get; set; }
public List<LiteDirectoryInfo> Files { get; set; }
}

public enum FileType
{
Drive,
Folder,
File
}
}

In the above code we have a enum FileType for distinguishing the file type. And a composite LiteDirectoryInfo where we have populated the directory structure. Finally After construction we preserved the data on FileSystem dependency property.


[Sample c# code for view c# part]


namespace WPFFolderExplorer
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new FileSystemPresenter();
}
}
}

Above code shows only the part where I have assigned our custom presenter to the WPFFolderExplorer’s DataContext to follow MVP Pattern (Model,View,Presenter) where model is our own local drives and file system.


[Sample code for XAML is Given here]


<Window x:Class="WPFFolderExplorer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="Background" Value="Gray"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<DockPanel LastChildFill="True">
<Border DockPanel.Dock="Top" Height="30">
<!--tool bar will go here-->
</Border>
<TreeView DockPanel.Dock="Left" MinWidth="200" ItemsSource="{Binding FileSystem}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Files}">
<Border x:Name="itemBorder">
<DockPanel Margin="2">
<ContentControl Content="{DynamicResource FolderIcon}" DockPanel.Dock="Left"/>
<TextBlock Text="{Binding FileName}"></TextBlock>
</DockPanel>
</Border>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ContentControl>
</ContentControl>
</DockPanel>
</Grid>
</Window>

In above xaml code its shown that how the binding with the presenter dependency is done. Also note that the item template is defined for a tree view.

No comments:

Post a Comment