deerchao的blog

Be and aware who you are.

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

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

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

在目录树这个例子中,每个TreeViewItem要显示的数据可以用System.IO.DirectoryInfo来表示,但是这样做有一个麻烦:DirectoryInfo只能通过GetDirectories()方法来获取子目录,但是WPF里的数据绑定则更倾向于使用属性在数据间导航,所以为了更方便地使用数据绑定,我们最好还是自定义一个类来完成这样的工作:
using System.Collections.Generic;
using System.IO;

namespace WpfApplication1
{

    
class BindDirectory
    
{
        
public BindDirectory(string directoryPath)
        
{
            
//正规化目录路径,确保Path以'\\'结尾
            directoryPath = directoryPath.TrimEnd('\\');
            Path 
= directoryPath + '\\';

            
//计算出目录名称(不包含路径)
            int indexLastSlash = directoryPath.LastIndexOf('\\');
            
if (indexLastSlash >= 0)
            
{
                Name 
= directoryPath.Substring(indexLastSlash + 1);
            }

            
else
            
{
                Name 
= directoryPath;
            }

        }


        
public string Name
        
{
            
get;
            
private set;
        }


        
public string Path
        
{
            
get;
            
private set;
        }


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

                }

                
return directories;
            }


        }

        List
<BindDirectory> directories;
    }

}


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

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

我们可以在Window的代码里设置界面的DataContext,ItemsSource等属性来让界面显示指定的数据,也可以构造一个专门提供数据的类,完全在界面(XAML)里指定,这里使用的是第二种方法:
using System.Collections.Generic;
using System.IO;

namespace WpfApplication1
{
    
class BindDirectoryList : List<BindDirectory>
    
{
        
public BindDirectoryList()
        
{
            
foreach (var drive in DriveInfo.GetDrives())
            
{
                Add(
new BindDirectory(drive.RootDirectory.FullName));
            }

        }

    }

}


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

第三步,设计用户界面

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

运行截图:

posted on 2008-05-08 13:58 deerchao 阅读(353) 评论(5)  编辑 收藏 网摘

评论

#1楼  2008-05-09 14:33 fishgoat [未注册用户]

呵呵。正需要这个。关注ing...   回复  引用    

#2楼  2008-07-23 17:49 凉薯 [未注册用户]

请问如果数据不是在创建时就有,而是运行时动态改变(比如运行过程中增加一个目录)用BindDirectoryList 这个类怎么实现?我在msdn上看的例子也是在构造函数里就把数据造好了。   回复  引用    

#3楼 [楼主] 2008-07-23 22:05 deerchao      

@凉薯
这样BindDirectoryList和BindDirectory需要分别实现以下接口:INotifyCollectionChanged和INotifyPropertyChanged,用以在数据发生变化时,触发相关的事件,通知WPF重新绘制用户界面.   回复  引用  查看    

#4楼  2008-08-21 17:10 凉薯 [未注册用户]

研究了好久,终于明白怎么用INotifyCollectionChanged了,特来向博主致谢   回复  引用    

#5楼  2008-08-25 16:00 凉薯 [未注册用户]

不行了,还是搞不定。博主能否补充一下这篇文章,给个运行时增加treeview item的例子?江湖救急,切盼!

我现在用findresource获得了drives的实例,但是在这个实例上add BindDirectory界面上并不会更新。   回复  引用    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接:
 




<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

导航

统计

公告

给网络添加价值,就是让自己增加价值.

本博客所有内容,均为原创或对互联网已有资源的再加工,希望对你有用.在声明原作者的前提下,你可以任意使用,但本人对其正确性,使用的后果等不做任何担保,也不负任何责任.

正则表达式30分钟入门教程 v2.21 2007-8-3

I Want Spec#!

与我联系

搜索

 

常用链接

留言簿(64)

我管理的小组

我的标签

随笔档案(125)

文章分类(9)

文章档案(9)

新闻档案(9)

Links

积分与排名

最新评论

评论排行榜