user266003
user266003

Reputation:

A simple WPF explorer tree

I'm developing a simple WPF explorer tree. Sacha Barber wrote a good article about it http://www.codeproject.com/Articles/21248/A-Simple-WPF-Explorer-Tree, I like this approach and I'm using it.

There is a thing I can't do. I would like to show files also, not only the directories. But I don't understand how do I recognize if it's a file or a folder.

Here is the full code

public partial class Window1 : Window
    {
        private object dummyNode = null;

        public Window1()
        {
            InitializeComponent();
        }

        public string SelectedImagePath { get; set; }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            foreach (string s in Directory.GetLogicalDrives())
            {
                TreeViewItem item = new TreeViewItem();
                item.Header = s;
                item.Tag = s;
                item.FontWeight = FontWeights.Normal;
                item.Items.Add(dummyNode);
                item.Expanded += new RoutedEventHandler(folder_Expanded);
                foldersItem.Items.Add(item);
            }
        }

        void folder_Expanded(object sender, RoutedEventArgs e)
        {
            TreeViewItem item = (TreeViewItem)sender;
            if (item.Items.Count == 1 && item.Items[0] == dummyNode)
            {
                item.Items.Clear();
                try
                {
                    foreach (string s in Directory.GetDirectories(item.Tag.ToString()))
                    {
                        TreeViewItem subitem = new TreeViewItem();
                        subitem.Header = s.Substring(s.LastIndexOf("\\") + 1);
                        subitem.Tag = s;
                        subitem.FontWeight = FontWeights.Normal;
                        subitem.Items.Add(dummyNode);
                        subitem.Expanded += new RoutedEventHandler(folder_Expanded);
                        item.Items.Add(subitem);
                    }
                    // this code I added to show the files
                    foreach (string f in Directory.GetFiles(item.Tag.ToString()))
                    {
                        TreeViewItem subitem = new TreeViewItem();
                        subitem.Header = f.Substring(f.LastIndexOf("\\") + 1);
                        subitem.Tag = f;
                        subitem.FontWeight = FontWeights.Normal;
                        subitem.Items.Add(dummyNode);
                        item.Items.Add(subitem);   
                    }
                }
                catch (Exception) { }
            }
        }

        private void foldersItem_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            TreeView tree = (TreeView)sender;
            TreeViewItem temp = ((TreeViewItem)tree.SelectedItem);

            if (temp == null)
                return;
            SelectedImagePath = "";
            string temp1 = "";
            string temp2 = "";
            while (true)
            {
                temp1 = temp.Header.ToString();
                if (temp1.Contains(@"\"))
                {
                    temp2 = "";
                }
                SelectedImagePath = temp1 + temp2 + SelectedImagePath;
                if (temp.Parent.GetType().Equals(typeof(TreeView)))
                {
                    break;
                }
                temp = ((TreeViewItem)temp.Parent);
                temp2 = @"\";
            }
            //show user selected path
           // MessageBox.Show(SelectedImagePath);
        }

    }

The window

<Window x:Class="WPF_Explorer_Tree.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPF_Explorer_Tree" 
    Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
    <Grid>
        <TreeView x:Name="foldersItem" SelectedItemChanged="foldersItem_SelectedItemChanged" Width="Auto" Background="#FFFFFFFF" BorderBrush="#FFFFFFFF" Foreground="#FFFFFFFF">
            <TreeView.Resources>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="HeaderTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                <Image Name="img"  Width="20" Height="20" Stretch="Fill" 
                                       Source="{Binding 
                                       RelativeSource={RelativeSource 
                                       Mode=FindAncestor, 
                                       AncestorType={x:Type TreeViewItem}}, 
                                       Path=Header, 
                                       Converter={x:Static local:HeaderToImageConverter.Instance}}"       
                                       />
                                    <TextBlock Text="{Binding}" Margin="5,0" />
                                </StackPanel>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</Window>

The converter

[ValueConversion(typeof(string), typeof(bool))]
    public class HeaderToImageConverter : IValueConverter
    {
        public static HeaderToImageConverter Instance = new HeaderToImageConverter();

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // this is a diskdrive
            if ((value as string).Contains(@"\"))
            {
                Uri uri = new Uri("pack://application:,,,/Images/diskdrive.png");
                BitmapImage source = new BitmapImage(uri);
                return source;
            }
            else
            {
                //maybe this is a directory or maybe this is a file. How do I know it?
                Uri uri = new Uri("pack://application:,,,/Images/folder.png");
                //Uri uri = new Uri("pack://application:,,,/Images/file.png");
                BitmapImage source = new BitmapImage(uri);
                return source;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("Cannot convert back");
        }
    }

How do I know inside HeaderToImageConverter.Convert if the current value is the name of a directory or the name of a file?

Upvotes: 0

Views: 2276

Answers (2)

Clemens
Clemens

Reputation: 128061

A far as i've understood your code, a TreeViewItem's Tag property contains an absolute path. You could bind to the Tagproperty instead of Header and in your converter check like this:

string path = value as string;
if (File.Exists(path))
{
    ...
}
else if (Directory.Exists(path))
{
    ...
}

See also here.

Upvotes: 1

Chen Kinnrot
Chen Kinnrot

Reputation: 21015

First, your code is not perfect, I strongly recommend you to work with hierarchical data template and view models, it will solve this issue and many more you'll have in future.

But, if you want a quick and dirty solution, you can try 2 things: 1. The header string of files will have file extension. 2. You can inject you're own context to the tree view item through the Data Context property

Upvotes: 0

Related Questions