WPF BreadcrumbBar






4.93/5 (46 votes)
A WPF BreadcrumbBar implementation.
Introduction
This is a Vista like breadcrumb bar for WPF that supports HierarchicalTemplates
, population on demand, dynamic path conversation, and many more.
Background
The BreadcrumbBar
is part of a free WPF control library named Odyssey that I'm currently developing just for fun. It is similar to the Vista breadcrumb bar, hence it is actually a multi-control bar consisting of the breadcrumb part, an editable ComboBox
, a progress bar, and a button area.
The BreadcrumbBar
is a control to display hierarchical data sources. The hierarchy is described by a HierarchicalDataTemplate
the same way as for a TreeView
control. The BreadcrumbBar
contains only one BreadcrumbItem
, which is the Root
property. Root
can be assigned directly to a BreadcrumbItem
by XAML or code, or to a hierarchical data source. In the latter case, virtual BreadcrumbItem
s are built automatically, and the root BreadcrumbItem
can be accessed by the RootItem
property. In contrast to a TreeView
, the BreadcrumbBar
can have only one root item.
BreadcrumbItem
A HeaderedItemsControl
that contains a collection of items which represent the next hierarchy of the data source. The difference between TreeViewItem
and BreadcrumbItem
is that the BreadcrumbItem
displays only the selected item, whereas the TreeViewItem
displays all items.
Since the header is a visual that not necessarily can be converted to a string, the Trace
property is used to build the Path
for the BreadcrumbBar
from all the selected BreadcrumbItem
s, and vice versa. Trace
is of type object
; therefore, it is possible to assign not only a string but also an XmlNode
. If you want to retrieve the value as a string, you can use the TrailValue
property.
The Image
property specifies the ImageSource
for the item to be displayed at the BreadcrumbBar
for the selected item and on the dropdown menu on a BreadcrumbItem
.
Note: Since it is possible to display the image on the BreadcrumbBar
and a dropdown menu, it cannot be an Image
control as a control can only have one parent.
BreadcrumbButton
A HeaderedItemsControl
that opens a drop down menu to select the next breadcrumb.
Note: BreadcrumbButton
is a helper control which is part of BreadcrumbItem
and should not be used directly.
Important dependency properties
BreadcrumbBar.Root
specifies the first breadcrumb. This can be either aBreadcrumbItem
or a hierarchical data source.BreadcrumbBar.Path
gets or sets the path of theBreadcrumbBar
.BreadcrumbBar.SelectedItem
gets the selected data item orBreadcrumbItem
.BreadcrumbBar.SelectedBreadcrumb
gets the selected (virtual)BreadcrumbItem
.BreadcrumbBar.TraceBinding
gets or sets thePath
of theBreadcrumbBar
, which is presented by each selected item, beginning by the root.BreadcrumbBar.ImageBinding
specifies a binding to an item that presents theImage
property for aBreadcrumbItem
in conjunction with a data source.BreadcrumbItem.Trace
gets or sets theTrace
property required to build the path.BreadcrumbItem.Image
gets or sets theImage
property that is used to get the image for theBreadcrumbBar
and each item in the drop down menu.
Using the code
This is an example of how to describe a BreadcrumbBar
in XAML and assign nested BreadcrumbItem
s to the Root
property:
<odc:BreadcrumbBar x:Name="bar"
Path="Computer\C:\"br> PopulateItems="BreadcrumbBar_PopulateItems"
TraceBinding="{Binding Folder}"
ImageBinding="{Binding Image}"
PathConversion="BreadcrumbBar_PathConversion">
The following example shows how to use a data source to obtain the breadcrumbs, and how to bind the Trace
property for each virtual BreadcrumbItem
using the TraceBinding
property:
<Window x:Class="BreadcrumbWithDataSourceExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:odc="clr-namespace:Odyssey.Controls;assembly=Odyssey"
Background="LightSteelBlue"
Title="BeadcrumbBar Demo: Using XmlDataProvider as Root Property"
Height="300" Width="700">
<Window.Resources>
<XmlDataProvider x:Key="dataProvider" XPath="bc">
<x:XData>
<bc xmlns="" title="Desktop">
<bc title="Computer">
<bc title="C:" >
<bc title="Windows" >
<bc title="System32"/>
<bc title="ie7"/>
<bc title="Microsoft.NET"/>
<bc title="Fonts"/>
<bc title="Driver Cache"/>
<bc title="inf"/>
</bc>
<bc title="Program Files">
<bc title="Visual Studio"/>
<bc title="Office"/>
</bc>
<bc title="Users">
<bc title="Administrator"/>
<bc title="Guest"/>
</bc>
</bc>
<bc title="D:"/>
</bc>
<bc title="Network">
<bc title="odyssey">
<bc title="public"/>
<bc title="private"/>
</bc>
<bc title="daedalus">
<bc title="system"/>
<bc title="confidential"/>
</bc>
</bc>
</bc>
</x:XData>
</XmlDataProvider>
<HierarchicalDataTemplate DataType="bc"
ItemsSource="{Binding XPath=*}">
<TextBlock Text="{Binding XPath=@title}"
Foreground="Red"/>
</HierarchicalDataTemplate>
</Window.Resources>
<DockPanel Margin="5">
<odc:BreadcrumbBar x:Name="bar" DockPanel.Dock="Top"
TraceBinding="{Binding XPath=@title}"
Root="{StaticResource dataProvider}"/>
<Grid></Grid>
</DockPanel>
</Window>
It would also be possible to bind the Trace
and Image
properties without TraceBinding
and ImageBinding
, as shown in the following example, but using TraceBinding
and ImageBinding
enables easier XAML code:
<odc:BreadcrumbBar>
<odc:BreadcrumbBar.Style>
<Style TargetType="{x:Type odc:BreadcrumbItem}">
<Setter Property="Trace" Value="{Binding XPath=@title}"/>
</Style>
</odc:BreadcrumbBar.Style>
</odc:BreacrumbBar>
Populate breadcrumbs on demand
The following snippet demonstrates how to populate breadcrumbs on demand, using the PopulateItems
event of the BreadcrumbBar
. This is useful if you cannot, or don't want to specify all possible hierarchies in a data source; for instance, if you want to use the breadcrumb bar to select a file path. Therefore, the BreadcrumbBar
has a RoutedEvent
named PopulateItems
which occurs as soon as a BreadcrumbItem
needs to access its items:
private void BreadcrumbBar_PopulateItems(object sender,
Odyssey.Controls.PopulateItemsEventArgs e)
{
if (e.Item.Items.Count == 0)
{
BreadcrumbBar bar = sender as BreadcrumbBar;
string path = bar.PathFromBreadcrumbItem(e.Item);
string trace = e.Item.TraceValue;
if (trace.Equals("Computer"))
{
string[] dirs = System.IO.Directory.GetLogicalDrives();
foreach (string s in dirs)
{
string dir = s;
if (s.EndsWith(bar.SeparatorString))
dir = s.Remove(s.Length - bar.SeparatorString.Length,
bar.SeparatorString.Length);
FolderItem fi = new FolderItem();
fi.Folder = dir;
e.Item.Items.Add(fi);
}
e.Handled = true;
}
else
{
try
{
string[] paths = System.IO.Directory.GetDirectories(path + "\\");
foreach (string s in paths)
{
string file = System.IO.Path.GetFileName(s);
FolderItem fi = new FolderItem();
fi.Folder = file;
e.Item.Items.Add(fi);
}
}
catch { }
e.Handled = true;
}
}
}
Path Conversion
Path conversion is used to parse the hierarchical structure from the text in the edit box, and vice versa. For instance, a data source has the following structure:
- Desktop
- Computer
- C:
- Windows
- Program Files
- D:
- Network
- Computer A
- Computer B
- Network
- C:
- Computer
But, instead of displaying the path as Desktop/Network/Computer A, it is preferred to show \\Computer A instead.
For that purpose, there is a RoutedEvent
available, named PathConversion
, that allows you to use code to convert between the data structure and the path. The following snippet shows an excerpt from the FileBrowserDemo (it's not very elegant code, I need to admit, but it demonstrates how to use it):
private void BreadcrumbBar_PathConversion(object sender, PathConversionEventArgs e)
{
if (e.Mode == PathConversionEventArgs.ConversionMode.DisplayToEdit)
{
if (e.DisplayPath.StartsWith(@"Computer\",
StringComparison.OrdinalIgnoreCase))
{
e.EditPath = e.DisplayPath.Remove(0, 9);
}
else if (e.DisplayPath.StartsWith(@"Network\",
StringComparison.OrdinalIgnoreCase))
{
string editPath = e.DisplayPath.Remove(0, 8);
editPath = @"\\" + editPath;
e.EditPath = editPath;
}
}
else
{
if (e.EditPath.StartsWith("c:", StringComparison.OrdinalIgnoreCase))
{
e.DisplayPath = @"Desktop\Computer\" + e.EditPath;
}
else if (e.EditPath.StartsWith(@"\\"))
{
e.DisplayPath = @"Desktop\Network\" + e.EditPath.Remove(0, 2);
}
}
}
Points of interests
For more information and updates, visit my web site.
History
- 2008-09-15 - Initial release published.