学习WPF: 创建数据绑定目录树

如果使用了WPF而不使用数据绑定(手工在界面和数据间进行同步),总会感觉不值.但是大部分讨论WPF数据绑定的文章,主题大多集中在ListBox这样平坦的数据集合上,讲如何绑定层次结构数据的比较少,这里我就通过一个简单的显示磁盘目录树的例子来展示如何完成这样的任务.

第一步,当然是定义要绑定的数据类型了.

在目录树这个例子中,每个TreeViewItem要显示的数据可以用System.IO.DirectoryInfo来表示,但是这样做有一个麻烦:DirectoryInfo只能通过GetDirectories()方法来获取子目录,但是WPF里的数据绑定则更倾向于使用属性在数据间导航,所以为了更方便地使用数据绑定,我们最好还是自定义一个类来完成这样的工作:
None.gif using  System.Collections.Generic;
None.gif
using  System.IO;
None.gif
None.gif
namespace  WpfApplication1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
InBlock.gif    
class BindDirectory
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
public BindDirectory(string directoryPath)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//正规化目录路径,确保Path以'\\'结尾
InBlock.gif
            directoryPath = directoryPath.TrimEnd('\\');
InBlock.gif            Path 
= directoryPath + '\\';
InBlock.gif
InBlock.gif            
//计算出目录名称(不包含路径)
InBlock.gif
            int indexLastSlash = directoryPath.LastIndexOf('\\');
InBlock.gif            
if (indexLastSlash >= 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                Name 
= directoryPath.Substring(indexLastSlash + 1);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                Name 
= directoryPath;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string Name
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get;
InBlock.gif            
private set;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string Path
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get;
InBlock.gif            
private set;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public IEnumerable<BindDirectory> Directories
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
//延迟加载
InBlock.gif
                if (directories == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    directories 
= new List<BindDirectory>();
InBlock.gif                    
foreach (string d in Directory.GetDirectories(Path))
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        directories.Add(
new BindDirectory(d));
ExpandedSubBlockEnd.gif                    }

ExpandedSubBlockEnd.gif                }

InBlock.gif                
return directories;
ExpandedSubBlockEnd.gif            }

InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif        List
<BindDirectory> directories;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

这个类所作的工作很简单,就是正规化目录路径,获取目录名称,以及延迟加载子目录(以提升性能)的列表,我们的界面也只要求它具有这些功能就行了.

第二步,创建一个数据提供类(DataProvider)

我们可以在Window的代码里设置界面的DataContext,ItemsSource等属性来让界面显示指定的数据,也可以构造一个专门提供数据的类,完全在界面(XAML)里指定,这里使用的是第二种方法:
None.gif using  System.Collections.Generic;
None.gif
using  System.IO;
None.gif
None.gif
namespace  WpfApplication1
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
class BindDirectoryList : List<BindDirectory>
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
public BindDirectoryList()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
foreach (var drive in DriveInfo.GetDrives())
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                Add(
new BindDirectory(drive.RootDirectory.FullName));
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

这个类就更简单了,仅仅是在创建的时候加载所有的磁盘的根目录.

第三步,设计用户界面

只需要在Window中添加一个TreeView,然后修改几行代码,就能轻松地显示我们的数据了:
None.gif <!-- xml:sample这一行用来引入我们自己代码的命名空间 -->
None.gif
< Window  x:Class ="WpfApplication1.Window1"
None.gif    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
None.gif    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
None.gif    xmlns:sample
="clr-namespace:WpfApplication1"
None.gif    Title
="Window1"  Height ="300"  Width ="300" >
None.gif    
< Window.Resources >
None.gif        
<!-- 引入我们自己的数据提供对象 -->
None.gif        
< ObjectDataProvider  x:Key ="drives"  ObjectType =" {x:Type sample:BindDirectoryList} "   />
None.gif        
<!-- 设置如何显示数据,以及如何获取下一级数据的列表 -->
None.gif        
< HierarchicalDataTemplate  x:Key ="itemTemplate"  DataType =" {x:Type sample:BindDirectory} "  ItemsSource =" {Binding Directories} " >
None.gif            
< TextBlock  Text =" {Binding Name} "   />
None.gif        
</ HierarchicalDataTemplate >
None.gif    
</ Window.Resources >
None.gif    
< TreeView  ItemsSource =" {Binding Source={StaticResource drives}} "
None.gif             ItemTemplate
=" {StaticResource itemTemplate} "   >
None.gif    
</ TreeView >
None.gif
</ Window >
None.gif
这里我们在XAML里定义了一个drives对象,它的类型为BindDirectoryList,创建时会自动加载磁盘的根目录;
我们还定义了一个针对BindDirectory类型的层次型数据模板itemsTemplate,指定了要获取此类型的数据的子数据需要通过Directories属性,并且告诉WPF用一个TextBlock来显示它的名称.
最后,我们设置一下TreeView的ItemsSource和ItemTemplate就完成工作了.

运行截图:
r_wpf.directorytree.jpg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值