Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / WPF
Article

WPF BreadcrumbBar

Rate me:
Please Sign up or sign in to vote.
4.93/5 (47 votes)
3 Oct 2008CPOL4 min read 169K   4.6K   162   39
A WPF BreadcrumbBar implementation.

Image 1

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 BreadcrumbItems 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 BreadcrumbItems, 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 a BreadcrumbItem or a hierarchical data source.
  • BreadcrumbBar.Path gets or sets the path of the BreadcrumbBar.
  • BreadcrumbBar.SelectedItem gets the selected data item or BreadcrumbItem.
  • BreadcrumbBar.SelectedBreadcrumb gets the selected (virtual) BreadcrumbItem.
  • BreadcrumbBar.TraceBinding gets or sets the Path of the BreadcrumbBar, which is presented by each selected item, beginning by the root.
  • BreadcrumbBar.ImageBinding specifies a binding to an item that presents the Image property for a BreadcrumbItem in conjunction with a data source.
  • BreadcrumbItem.Trace gets or sets the Trace property required to build the path.
  • BreadcrumbItem.Image gets or sets the Image property that is used to get the image for the BreadcrumbBar 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 BreadcrumbItems to the Root property:

XML
<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:

XML
<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:

XML
<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:

C#
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

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):

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Germany Germany
MCPD
Enterprise Application Developer 3.5
Windows Developer 3.5
.ASP.NET Developer 3.5
.NET 2.0 Windows Developer
.NET 2.0 Web Developer
.NET 2.0 Enterprise Application Developer


MCTS
.NET 3.5 Windows Forms Applications
.NET 3.5 ASP.NET Applications
.NET 3.5, ADO.NET Application Development
.NET 3.5 WCF
.NET 3.5 WPF
.NET 3.5 WF
Microsoft SQL Server 2008, Database Development
.NET 2.0 Windows Applications
.NET 2.0 Web Applications
.NET 2.0 Distributed Applications
SQL Server 2005
Sharepoint Services 3.0 Application Development
Windows Vista Client Configuration

Comments and Discussions

 
QuestionBind Root to a Collection Pin
Member 1052573718-Nov-14 3:10
Member 1052573718-Nov-14 3:10 
QuestionEdit Option Pin
Member 19378065-Aug-14 2:13
Member 19378065-Aug-14 2:13 
QuestionDropDownItemTemplate Does not Work Pin
Vivek Giri28-Mar-13 4:31
Vivek Giri28-Mar-13 4:31 
QuestionCould you provide any soluation for System.Window.Text.TextBlock problem?? Pin
andyyu092028-Nov-12 19:40
andyyu092028-Nov-12 19:40 
AnswerRe: Could you provide any soluation for System.Window.Text.TextBlock problem?? Pin
andyyu092029-Nov-12 16:43
andyyu092029-Nov-12 16:43 
QuestionSetting Selected Item or Path Pin
Anon87623-Aug-12 8:03
Anon87623-Aug-12 8:03 
GeneralRed text? Pin
CocoaJason4-Jul-12 6:32
CocoaJason4-Jul-12 6:32 
GeneralRe: Red text? Pin
CocoaJason4-Jul-12 10:23
CocoaJason4-Jul-12 10:23 
Questionwinforms Pin
Zapss13-Feb-12 23:31
Zapss13-Feb-12 23:31 
GeneralMy vote of 5 Pin
Filip D'haene17-Sep-11 3:50
Filip D'haene17-Sep-11 3:50 
GeneralGreat control + quick question Pin
Daniel Larocque14-Dec-10 4:41
Daniel Larocque14-Dec-10 4:41 
GeneralMy vote of 5 Pin
Ashley Davis29-Nov-10 2:40
Ashley Davis29-Nov-10 2:40 
GeneralThanks Pin
Member 427160326-May-10 3:25
Member 427160326-May-10 3:25 
AnswerItemsSource Property change bug. Pin
Tri Q Tran22-Mar-10 0:34
Tri Q Tran22-Mar-10 0:34 
GeneralRe: ItemsSource Property change bug. Pin
Yomodo25-Dec-11 0:47
Yomodo25-Dec-11 0:47 
GeneralPath not working! Pin
Frederik W. Johansen6-Feb-10 0:18
Frederik W. Johansen6-Feb-10 0:18 
Hi, nice control

But i can not make the Path property to work!! I can only make it work in your browser sample??? even in your data sample it is not working. Is there a bug?

I like to use the control, but without the Path property it is useless. Cry | :((

/Frederik
GeneralRe: Path not working! Pin
evchenic24-Mar-10 3:52
evchenic24-Mar-10 3:52 
GeneralRe: Path not working! Pin
Frederik W. Johansen11-May-10 22:31
Frederik W. Johansen11-May-10 22:31 
GeneralRe: Path not working! Pin
Member 97538154-Feb-13 2:06
Member 97538154-Feb-13 2:06 
GeneralRe: Path not working! Pin
Member 1229362513-May-16 8:47
Member 1229362513-May-16 8:47 
GeneralRe: Path not working! Pin
Member 1229362513-May-16 8:30
Member 1229362513-May-16 8:30 
GeneralHideRootNode does not work Pin
JOezkan11-Jan-10 23:21
JOezkan11-Jan-10 23:21 
GeneralTemplate modifications Pin
wsnigga11-Mar-09 23:26
wsnigga11-Mar-09 23:26 
GeneralSystem.Window.Text.TextBlock Showing on root drop down Pin
Thedurk29-Jan-09 9:35
Thedurk29-Jan-09 9:35 
GeneralBug: Underscores in the BreadcrumbItem.Header [modified] Pin
bigbigllama9-Jan-09 1:35
bigbigllama9-Jan-09 1:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.