Click here to Skip to main content
Click here to Skip to main content

How to create a UserControl (WPF) which allows the user to pick a directory

, 5 Jun 2014
Rate this:
Please Sign up or sign in to vote.
In this article we are going to build a UserControl in WPF which is intended to make the user choose a directory in his FIleSystem

Introduction

This article deals with the creation of a control which allows the user to pick a directory. The control might be easily put into a DialogWindow.

Background

In order to understand the tutorial you need to have a basic knowledge of WPF (what's a UserControl, a DialogWindow, ecc.), C# (collections, IO and events) and Data Binding in WPF (dynamic list binding)

Using the code

The control is designed with a listbox in the middle, a textbox in the upper part of the control and, next to it, there is a button to go up the directory tree.

The code of the page is:

<UserControl x:Class="DirectoryPicker.DPick"
             xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>"
             xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a>"
             xmlns:mc="<a href="http://schemas.openxmlformats.org/markup-compatibility/2006">http://schemas.openxmlformats.org/markup-compatibility/2006</a>"
             xmlns:d="<a href="http://schemas.microsoft.com/expression/blend/2008">http://schemas.microsoft.com/expression/blend/2008</a>"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300" Loaded="UserControl_Loaded">

and the code behind is:

public partial class DPick : UserControl
    {
        ObservableCollection<string> Dirs = new ObservableCollection<string>();
        public string CPath
        {
            get { return (string)GetValue(CPathProperty); }
            set { SetValue(CPathProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CPath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CPathProperty =
            DependencyProperty.Register("CPath", typeof(string), typeof(DPick), new PropertyMetadata(""));

        public DPick()
        {
            InitializeComponent();
        }

        private void UserControl_Loaded(object sender, EventArgs e)
        {
            this.lstDirs.ItemsSource = Dirs;
            if (CPath == String.Empty || Directory.Exists(CPath) == false)
            {
		CPath = "";
                foreach (string s in Directory.GetLogicalDrives())
                {
                    Dirs.Add(s);
                }
                this.txtPath.Text = CPath;
            }
            else
            {
                PopulateList();
            }
        }

        private void lstDirs_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            int SelIndex = this.lstDirs.SelectedIndex;
            CPath = System.IO.Path.Combine(CPath, Dirs[SelIndex]);
            PopulateList();
        }

        private void PopulateList()
        {
            try
            {
                Dirs.Clear();
                foreach (var dir in Directory.GetDirectories(CPath))
                {
                    Dirs.Add(GetDirName(dir));
                }
                this.txtPath.Text = CPath;
            }
            catch (Exception)
            {
                Dirs.Clear();
                Dirs.Add("Access Denied");
            }

        }
        private string GetDirName(string Path)
        {
            return Path.Substring(Path.LastIndexOf('\\') + 1);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            CPath = System.IO.Path.GetDirectoryName(CPath);
            PopulateList();
        }

        private void txtPath_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                string old = CPath;
                try
                {
                    CPath = this.txtPath.Text;
                    PopulateList();
                }
                catch (Exception) { CPath = old; }
            }
        }

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {

        }
    }

Comment

The first line defines an ObservableCollection<string> which define the content of the current directory. It is not a list because an ObservableCollection implements from INotifyPropertyChanged and it can notify whenever it is modified. Then we have defined a DependencyProperty which name's CPath which represents the current path of the control. You can set CPath to an initial directory, but it's also the directory the control is currently in (so the directory the user has selected till now).

Then the method UserControl_Loaded is called. If the CPath property has been set and the directory exists, it's used as the initial directory for the control, otherwise the list is populated with the list of LogicalDrives. I would like to focus the first line of the method

this.lstDirs.ItemsSource = Dirs;

this line indicates to the listbox that Dirs is its source of items. Thanks to the peculiar ability of the ObservableCollection class, the content of the Collection and the content of the ListBox will be always the same.

At this point, the method calls another method  called PopulateList. This method cleares the ObservableCollection (and so the ListBox) and begins to add the content of the current directory (just directory names) to it as strings. If an error occurs, or the directory does not exists anymore (the user might have deleted it while the control has been already updated) or we haven't got the access to that directory, so we add to the list the string "Access Denied"

Then the event ListBox_MouseDoubleClick is defined in the code. This event occurs whenever the user double-clicks on the listbox or on one of its child. This happens because of the event bubbling. The event bubbling says that an event can travel up the control tree and reach the main container. I.E. if an item of the listbox is double-clicked, the listbox is double-clicked as well as the UserControl. In this event, we take the selected index and we add it to the CPath string with the help of the static class Path.Combine

In order to "go up", we can use the static class path with the method GetDirectoryName, which returns the path to the directory another element is in. In this case, this element is a directory, so we can use this code in order to go up. I.E. From C:\Dir1\Dir2\Dir3 Path.GetDirectoryName(string) will return C:\Dir1\Dir2

The last little thing: if we insert a path into the textbox and the users presses the Enter button, the control automatically navigates to the specified directory if it exists.

Points of Interest

You can write a DialogWindow with this control. Remember that's a UserControl. This window has to have a DependencyProperty called Path (or whatever you want) and this has to be passed to the CPath DependencyProperty of the control. When the user clicks Ok (so the window returns true) you can access the property Path into the Window and (if you 've written the right code in order to make your Path equal to the CPath of the control) use it for whatever you want!

History

1°Edition of the Article

License

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

About the Author

No Biography provided
Follow on   Twitter

Comments and Discussions

 
QuestionMy vote of 5 PinprofessionalJacob Himes8-Jun-14 13:16 
AnswerRe: My vote of 5 PinmemberLusvardi Gianmarco (Jymmy097)9-Jun-14 8:45 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 5 Jun 2014
Article Copyright 2014 by Lusvardi Gianmarco (Jymmy097)
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid