WPF学习TreeView和ValueConverter
界面代码如下:
<Window x:Class="WPF_TreeView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_TreeView"
mc:Ignorable="d"
Loaded="Window_Loaded"
Title="MainWindow" Height="600" Width="400">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="225*"/>
<ColumnDefinition Width="169*"/>
</Grid.ColumnDefinitions>
<TreeView x:Name="FolderView" Grid.ColumnSpan="2" Margin="0,0,-0.4,0.4">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<!-- Standard data template-->
<StackPanel Orientation="Horizontal" >
<!--Image Width="20" Source="Images/folder_closed.png"/-->
<Image Width="20" Source="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor
,AncestorType={x:Type TreeViewItem}},Path=Tag
,Converter={x:Static local:HeaderToImageConverter.Instance}}"/>
<TextBlock x:Name="FolderName" VerticalAlignment="Center" Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
后台代码:
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
namespace WPF_TreeView
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
#region Default Constructor
/// <summary>
/// Default Constructor
/// </summary>
public MainWindow()
{
InitializeComponent();
}
#endregion
#region loaded
/// <summary>
/// when the application first loaded
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Get every logical drive on the machine
var dirs = Directory.GetLogicalDrives();
foreach(var drive in dirs)
{
// create a new item fot it
var item = new TreeViewItem();
// set the header
item.Header = drive;
// Add the full path
item.Tag = drive;
// add a dummy item
item.Items.Add(null);
// Listen out item being expanded
item.Expanded += FolderExpanded;
// Add it to the main tree-view
FolderView.Items.Add(item);
}
}
#endregion
#region Folder Expanded
/// <summary>
/// while the folder expanded find sub folders/fieles
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FolderExpanded(object sender, RoutedEventArgs e)
{
var item = (TreeViewItem)sender;
if (item.Items.Count != 1 || item.Items[0] != null) return;
item.Items.Clear();
#region Get folders
// Get the full path
var fullpath = (string)item.Tag;
// Ceate a blank list for directories
var directories = new List<string>();
// try and get directories from the folder
// ignoring any issues doing so
try
{
var dirs = Directory.GetDirectories(fullpath);
if (dirs.Length > 0)
directories.AddRange(dirs);
}
catch { }
// For each directory
directories.ForEach(directorypath =>
{
// Create direcory item
var subItem = new TreeViewItem()
{
// set header as folder name
Header = GetFileFolderName(directorypath),
// And tag as fullpath
Tag = directorypath
};
// Add a dummy item so we can expand folder
subItem.Items.Add(null);
// Handle expanding
subItem.Expanded += FolderExpanded;
// Add subitem to parent item
item.Items.Add(subItem);
});
#endregion
#region Get files
// Ceate a blank list for directories
var files = new List<string>();
// try and get directories from the folder
// ignoring any issues doing so
try
{
var fs = Directory.GetFiles(fullpath);
if (fs.Length > 0)
files.AddRange(fs);
}
catch { }
// For each file
files.ForEach(filepath =>
{
// Create file item
var subItem = new TreeViewItem()
{
// set header as file name
Header = GetFileFolderName(filepath),
// And tag as fullpath
Tag = filepath
};
// Add subitem to parent item
item.Items.Add(subItem);
});
#endregion
}
#endregion
#region Helpers
/// <summary>
/// Get file and folder name from a path
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetFileFolderName(string path)
{
// If we have no path,retun empty string
if (string.IsNullOrEmpty(path))
return string.Empty;
// Make all slashes back slash
var normalize = path.Replace('/', '\\');
var lastIndex = normalize.LastIndexOf('\\');
// If we don't find a backslash,the return the path itself
if (lastIndex <= 0)
return path;
//Return after the name after backslash
return normalize.Substring(lastIndex + 1);
}
#endregion
}
}
ValueConverter的实现类:
using System;
using System.Globalization;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;
namespace WPF_TreeView
{
/// <summary>
/// Convert fullpath to a specific image type of a drive,foldeer or file
/// </summary>
[ValueConversion(typeof(string),typeof(BitmapImage))]
public class HeaderToImageConverter : IValueConverter
{
public static HeaderToImageConverter Instance = new HeaderToImageConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Get the full path
var path = (string)value;
// If the path is null,ignore
if (path == null)
return null;
// Define a image to store the image path
string image = "Images/file.png";
// Get the name of file/folder
var name = MainWindow.GetFileFolderName(path);
//if the name is blank,we assume it as a drive,as we cannot have a blank file or folder name
if (string.IsNullOrEmpty(name))
image = "Images/drive.png";
else if (new FileInfo(path).Attributes.HasFlag(FileAttributes.Directory))
image = "Images/folder_closed.png";
//else if(new FileInfo(path).Attributes.HasFlag(FileAttributes))
//
return new BitmapImage(new Uri($"pack://application:,,,/{image}"));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
参考视频
效果如下:
整个项目的Github地址