wpf listview用户控件:具有节点折叠效果

wpf 原生的 treeview 选中效果只能选中contentpresenter部分 如图: & 要实现的效果如图:
主要的点在于
1.treeviewitem的 模板结构修改达到 统一背景颜色和填充长度 2.处理由于子节点的向右偏移造成的 背景色填充不够,如图:
这种情况就是由于 模板中的ItemsPresenter 在布局中第二列造成的,由于item包含的item 初始位置就在于顶级的第二列所以 一次会偏移一个第一列宽度。 解决: 百度了一下 ,发现一篇帖子讲如何实现,主要原理是在布局中取消掉层级间的缩进,来实现每一级的背景色都可以填充到最左边,然后通过代码记录item的级别然后计算偏移,偏移项目。但是我觉得这样太麻烦了 所以就写了一个取巧的纯xaml的方式。上代码 &Style TargetType="{x:Type TreeViewItem}"&
&Setter Property="Foreground" Value="#FFF0F0F0"/&
&Setter Property="Template"&
&Setter.Value&
&ControlTemplate TargetType="{x:Type TreeViewItem}"&
&Grid.ColumnDefinitions&
&ColumnDefinition
Width="16"/&
&ColumnDefinition/&
&/Grid.ColumnDefinitions&
&Grid.RowDefinitions&
&RowDefinition/&
&RowDefinition/&
&/Grid.RowDefinitions&
&Border Grid.ColumnSpan="2" Margin="-,0"
x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"
SnapsToDevicePixels="true"/&
&ToggleButton
x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" /&
&ContentPresenter Grid.Column="1" x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/&
&ItemsPresenter
x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/&
&ControlTemplate.Triggers&
&Trigger Property="IsExpanded" Value="false"&
&Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/&
&/Trigger&
&Trigger Property="HasItems" Value="false"&
&Setter Property="Visibility" TargetName="Expander" Value="Hidden"/&
&/Trigger&
&Trigger Property="IsSelected" Value="true"&
&Setter Property="Background" TargetName="Bd" Value="#FF404040" /&
&Setter Property="Background" TargetName="Expander" Value="#FF404040"/&
&/Trigger&
&MultiTrigger&
&MultiTrigger.Conditions&
&Condition Property="IsSelected" Value="true"/&
&Condition Property="IsSelectionActive" Value="false"/&
&/MultiTrigger.Conditions&
&Setter Property="Background" TargetName="Bd" Value="#FF404040"/&
&Setter Property="Background" TargetName="Expander" Value="#FF404040"/&
&/MultiTrigger&
&Trigger Property="IsEnabled" Value="false"&
&Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/&
&/Trigger&
&/ControlTemplate.Triggers&
&/ControlTemplate&
&/Setter.Value&
&/Style& 既简单 又实用 ,但是还是需要建立在搞清楚布局的基础上,当然如果超过了 100级父子关系(16*100 )长度 就会有问题了,不过一般不会有100级那么长吧=。。=
TreeView控件研究(WPF篇)(创建+数据绑定+整行选中)_mickal1988_...wpf treeview 之 整行选中 效果-ASP-第七城市wpf treeview 之 整行选中 效果 21:17:0blogs-GISER_U- 点击数: wpf 原生的 treeview 选中效果只能选中contentpresenter部分 如图: image...采用MVVM方式实现WPF的TreeView_银光中国 Silverlight Windows8 ...(1)MainWindow,里面只有两行代码,关键实现便是对DataContext赋值,那么所赋的值...上一篇:WPF中自定义ListView 下一篇:WPF treeview 之 整行选中 效果 收藏 ...如何让QTreeView选中行的颜色拓展到整个width? - 开源中国社区Windows8/Silverlight/WPF/WP7/HTML5周学习导读(1月28日-2月3日) ...实现Windows 7 样式 Aero TreeView 控件(一):差异分析 - WPF - 第...但是WPF做出来的控件和Windows 7原生效果有所差异,手头真好有一个项目,... 下一篇文章: 实现Windows 7样式Aero TreeView控件(二):实现整行选中 ...WPF中使用MVVM模式操作TreeView - IT技术博客 - 秋色园WPF Treeview 点击右键弹出菜单,同时鼠标点击处的TreeViewItem被...有时候我们需要在TreeView中实现这样的功能: 在TreeView上点击右键弹出菜单,同时鼠标点击处的TreeViewItem被选中,然后我们针对选中的数据进行处理。 不过,WPF的Tree...关于WPf TreeView 布局美化得一个问题_博问_博客园关于WPf TreeView 布局美化得一个问题-1 悬赏园豆:80 [待解决问题] 浏览: 4187次 想用TreeView实现如下效果 可是做出来确实这样的效果 存在的问题: 1:TreeView...Windows8/Silverlight/WPF/WP7/HTML5周进修导读(1月28日-2月3日)-... WPF treeview 之 整行选中 结果 GISER_U WPF中全屏的设置 Grace_0642 WPF中应用串口 迦楼罗 WPF的图像处理惩罚(5) 风涛 WPF 自定义窗体 另一种实现体式格式...通用一个??WPF的TreeView_Windows Presentation_平台,框架和库_或...求:WPF中TreeView如何实现展开一个节点其他节点关闭!_百度知道2个回答 - 提问时间: 日知道达人: Mickal小米楼主可以用两种思路来解决此问题。第一种,运用TreeView的SelectedItemChanged事件假设TreeView控件的nam...WPF之TreeView绑定后的查询和定位--随遇而安--凤凰博客最近在写一个小软件,WPF的TreeView绑定一个三层实体后,想要定位到最后一层的节点,并处于选中状态, 尝试过很多方法,发现WPF中的TreeView很多属性都是只读的,不能...WPF中TreeView控件的简单用法-控件新闻-慧都控件同时呢,TreeView在很多项目中都有运用,甚至某些做自定义的属性控件,当然了,我在此就和大家一起分享一下WPF中系统预设的 TreeView控件吧!...WPF treeView1的选中节点改变触发的事件是什么_百度知道1个回答 - 提问时间: 日SelectedItemChanged,treeview控件的默认事件。潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多...潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归...效果,不一定只有这三个字段,拓展他以达到treeview显示更丰富的效果,而且treeview...wpf中选中treeview的某个子节点后获取子节点所在的所有..._百度知道1个回答 - 提问时间: 日csdn上的例子 (仅供参考): private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs&object& e) { TreeViewItem item = ...WPF编程技术 - Lassewang的成长历程 - 博客频道 - CSDNStyle设置整行选中的TreeView(Silverlight) 稍微搜索了一下,发现上很多都是...”制作的,最后,我们可以利用WPF的资源特性,随时更换“皮肤”,变成你想要的效果...WPF中TreeView控件实现动态加载节点 - 马路灯 - 博客园wpf 中treeview控件如何获取选中的对象_百度知道2个回答 - 提问时间: 日我当时只用TextBlock 的时候也很苦恼,最后只好加了一个CheckBox来进行选中。看能不能帮到你。。 &StackPanel Orientation=&Horizontal&& &CheckBox ...[WPF]如何正确地用代码设置ListBox的当前选中项 - 南柯之石 - ... 运行的效果如下。 图1. TextBox得到焦点 其实这就是个问题,一个ListBoxItem...在智者千虑的【WPF】如何让TreeView实现右键选中的功能里就描述了TreeView上的...WPF 中TreeView的子节点选中时父节点 - 下载频道 - CSDNWPF 中TreeView的子节点选中时父节点 wanghongtao_-11-16上传 WPF 中TreeView的子节点选中时父节点资源积分:2分 下载次数:46 资源类型:文档 资源大小:6KB...[求助]wpf中TreeView的显示问题-CSDN论坛-CSDN-中国最大的IT...6条回复&-&发帖时间:&日WPF中TreeView控件如何获取选中的TreeViewItem对象? - bitfan(...WPF中TreeView控件如何获取选中的TreeViewItem对象? WPF的TreeView控件与过去的TreeView控件完全不同,几乎是从头重写了一遍,其最重要的特点之一就是支持绑定到...【WPF】带有TreeView控件boBox-WPF-第七城市。总之我们进入正题:带有TreeView控件boBox 之 菜鸟的实现方法 要实现带有...下拉与选中后的效果如下 还挺逼真的有木有~~ 跟大神们用继承做出来的效果一...wpf:怎么遍历treeview数据模板里选中的checkbox项_已解决_博问_...wpf:怎么遍历treeview数据模板里选中的checkbox项0 悬赏园豆:20 [已解决问题] 浏览: 227次 &TreeView Name=&tvDataTags& Grid.Column=&0& Grid.Row=&4& ...WPF TreeView如何展开到某个节点_百度知道1个回答 - 提问时间: 日解决问题的思路是,得到从树的根节点到特定节点的路线,并打开所有父节点。但是曲折的地方就是如何得到下一级的子节点,也就是如何从Items集合中取得对应的...wpf TreeView MVVM添加节点,删除选中节点,重命名,上下移动小弟刚解除wpf不久,求一个wpf MVVM操作TreeView的小例子,大概功能包括:添加节点,删除选中节点,重命名选中的节点,上下移动 望大侠们指点,感激不尽~~~ 程序人生2012...wpf带checkbox的treeview开发 - 江下飞雪 - 博客频道 - CSDN了tree的级选模式,即当选中一个节点时,自动选中它...效果如图: 关于该大神的示例代码大家可以从这里去...主题推荐 checkbox treeview wpf 源代码 数据 ...wpf程序中,用treeview读取选择目录下文件夹和文件-CSDN论坛-CSDN...14条回复&-&发帖时间:&日WPF 数据绑定TreeView+DataGrid+XML - 游の侠 - 博客园 实现功能:WPF通过读取XML数据绑定到TreeView, 在通过TreeView选择项(Node)获取的对应的数据绑定到DataGrid控件上,再通过DataGrid选中行的详细信息数据绑定到DataGrid。...WPF 带CheckBox、图标的TreeView - 盛胜的专栏 - 博客频道 - CSDN...[]CheckBox的TreeView,虽然微软在WPF的TreeView中没有...获取选中项 /// /// /// &returns&&/returns... 显示效果: 其实还可以完成共多功能,等有时间在去...Style设置整行选中的TreeView(Silverlight) - Lassewang的成长...Style设置整行选中的TreeView(Silverlight) 分类: WPF编程技术
14... 效果图: (黄色为选中,浅蓝色为MouseOver) 没啥解释的,看代码。ps:Expanded...WPF开发实例-独立应用程序
Windows Presentation Foundation(WPF)是.NET 3.0之后推出的Windows下的新一代显示系统,在.NET 3.5中进行了增强。通过WPF可以开发极其灵活、美观、震撼用户体验的UI应用程序,包括桌面应用程序和承载于浏览器的应用程序。本章将简单介绍如何利用WPF进行应用程序开发
  Windows Presentation Foundation(WPF)是.NET 3.0之后推出的Windows下的新一代显示系统,在.NET 3.5中进行了增强。通过WPF可以开发极其灵活、美观、震撼用户体验的UI应用程序,包括桌面应用程序和承载于浏览器的应用程序。本章将简单介绍如何利用WPF进行应用程序开发。
9.1 WPF简介
在进一步介绍WPF应用程序开发方法之前,首先介绍一下WPF的基本概念、体系结构、开发模式等,同时也介绍一下XAML的概念。只有对这些基本概念有一个基本认识,才可能开发出更好的WPF应用程序。
9.1.1 什么是WPF
Windows Presentation Foundation(WPF)是Microsoft在.NET 3.0中推出的一个重要新特性,它为Windows下应用程序开发提供一套全新的显示系统,旨在为用户提供方便的用户操作和震撼视觉体验的界面。WPF支持一套完整的应用程序开发功能,包括应用程序开发模型、资源、控件、图形、动画、布局、数据绑定、文档读写、本地化、安全性等。
WPF的核心是一个与分辨率无关的基于向量的呈现引擎,旨在充分发挥现代图形设备的优势,WPF开发和C#集成可以通过Visual Studio 2008非常方便地进行应用程序开发。WPF和公共语言运行环境(CLR)的完全集成,充分利用了CLR提供的类型安全、跨平台等特性。
另外,WPF在CLR之上提供自身的程序模型和类库,如图9-1所示为MSDN上介绍的WPF体系结构。其中,PresentationFramework和PresentationCore都是基于CLR之上,以托管代码的方式公开应用程序开发接口(API)的。而milcore则在CLR之下,是以非托管代码方式,直接和DirectX紧密集成的,可以充分利用DirectX在图形处理上的巨大便利和性能优势,从而为用户提供具有震撼视觉感受的用户界面。milcore是WPF隐藏于CLR之下的核心驱动组件,在实际应用程序开发中不太可能访问到,这里不再进一步介绍。
WPF体系结构中一个重要原理就是--基于属性,WPF提供的类库、操作方式等都尽可能使用属性,而不是方法或事件。因为属性是声明性的,较之方法和事件更加容易指定对象的意图(这在XAML中相当重要),所以属性系统是WPF体系结构中一个重要部分。在WPF属性系统中,属性可以被继承和监视,当属性被更改时,属性联系的双方都被通知。由于被继承,所以子元素可以感受到父元素属性的变化,例如,父窗体的窗体大小属性被更改时,会自动通知到子窗体,并同步刷新界面。WPF属性系统的根本是System.Windows. DependencyObject类型,它是WPF属性系统的基类。
图9-1 WPF体系结构
在WPF中,System.Windows.Media.Visual类型提供了界面元素的显示支持,它用于生成一个可视化树,树中每个元素都包含特定的绘制和实现能力,从而将需要的数据显示到界面。另外,Visual类还将托管的WPF组件和非托管的milcore组件链接到一起,通过在屏幕上定义一个矩形显示区域来提供显示框架,从而将可视化树中各元素呈现到屏幕上。
WPF中大部分类都是从UIElement、FrameworkElement、ContentElement、Framework ContentElement 4个类派生而来,这4个类称为基元素类。其中,UIElement是主要类,它是从Visual类派生而来,适用于支持大型数据模型的元素,这些元素用于在可以称为矩形屏幕区域的区域内进行呈现和布局,在该区域内,内容模型特意设置得更加开放,以允许不同的元素进行组合。
在WPF中,改变了传统Windows窗体应用程序中的窗体中相对位置计算的布局模式,在WPF中的布局更像网页上元素的布局,显得更加灵活。WPF支持5种常用的布局形式,如表9-1所示。
表9-1 WPF中的常用布局模式
定义一个区域,在此区域内,可以使用相对于Canvas区域的坐标显式定位子元素,类似于传统的Windows窗体程序中相对坐标的布局方式
定义一个区域,在此区域内,可以使子元素互相水平或垂直排列,对于简单的单行或单列元素布局比较适用
定义由行和列组成的灵活网格区域,类似于网页开发中的网格布局,对于比较复杂而灵活的界面布局比较适用
StackPanel
沿水平或垂直方向将子元素排列成一行,对于简单的行或列布局比较适用
从左至右按顺序位置定位子元素,在包含框的边缘处将内容断开至下一行,后续排序按照从上至下或从右至左的顺序进行,具体取决于Orientation属性的值
表9-1中列出的布局模式实际是不同类型的面板控件,这些面板本身可以装入其他类型的面板,这样就可以得到不同布局模式的组合,从而构建丰富灵活的应用程序界面。例如,在一个Grid面板的各单元内放入Canvas面板,就可以得到整体为Grid布局,但内部却是绝对位置布局的界面样式。
除了在窗体布局上的更改之外,WPF支持动画、二维图形、三维图形等图像处理和多媒体技术,另外,WPF还支持文档的打开和阅读等。由于篇幅限制,这里不再详细介绍。总之,通过WPF可以轻松开发出具有丰富UI的应用程序。
9.1.2 WPF开发模式
Windows Presentation Foundation(WPF)通过Visual Studio 2008提供了一套新的应用程序开发模式,该模式与ASP.NET网页开发模式有几分相似之处,也是一种前后台开发模式。本节简单介绍一下这种开发模式的一些基本概念。
和普通的Windows窗体应用程序一样,WPF应用程序的开发也分界面设计和后台代码两个部分,WPF应用程序界面设计代码和ASP.NET页面(见本书第19章)相似。WPF的界面代码是一种新的标记性语言--XAML,后台代码则是C#、VB.NET等.NET高级语言(本书实例中都使用 C#)。
XAML可以理解成一种特殊的XML文件,因为它的格式和XML一致,但是,根据节点的不同意义,XAML节点可以描述不同的界面元素,所以 XAML被用作WPF的UI编写语言。XAML简化了为.NET Framework编程模型创建UI的过程,XAML文件是指通常使用.xaml为扩展名的XML文件。
在XAML中,界面上的每个UI元素都是一个节点,该节点包含多个子节点,每个子节点表示了父节点所包含的一个UI元素,从而就可以体现出UI上的控件等元素的布局方式。开发人员可以使用代码隐藏文件将UI定义与运行时逻辑相分离。与普通的XML不同,XAML直接呈现托管对象的实例化,这种常规设计原则简化了使用XAML创建的对象的代码和调试访问。
XAML具有一组规则,这些规则将对象元素映射为类或结构,将XML节点的属性(Attribute)映射为类的属性(Property)或事件,并将XML命名空间映射为CLR命名空间。XAML元素映射为引用的程序集中定义的Microsoft.NET类型,而属性(Attribute)则映射为这些类型的成员。
示例代码9-1演示了一个简单的WPF窗体的XAML代码,层次大致是,一个Windows窗体包含一个Grid,Grid内部包含一个Label 控件和一个Button控件。其中Windows窗体映射到后台代码中的类为HelloWPF.Window1,标题为Title属性的值 --HelloWPF,对象名称(Name属性)为FrmMain等。另外,Button控件的名称为btnShowMsg,Click事件处理函数为 btnShowMsg_Click()。
示例代码9-1:
&Window x: xmlns=&/winfx/2006/xaml/presentation&
xmlns:x=&/winfx/2006/xaml&
Title=&HelloWPF& Height=&179& Width=&262& Name=&FrmMain&&
&Label Height=&28& Margin=&44,31,49,0& Name=&lbHint&
VerticalAlignment=&Top&&Hello WPF, I'm coming !&/Label&
&Button Height=&34& Margin=&32,0,36,35& Name=&btnShowMsg&
VerticalAlignment=&Bottom& Click=&btnShowMsg_Click& &Show Message&/Button &
在WPF应用程序中,与XAML所描述的UI界面对应,还包含一个后台代码文件,本书用C#语言开发,名称为XAML文件名后面添加.cs后缀名,如示例代码9-1对应的XAML文件名称为Window1.xaml,对应的后台代码文件名为Window1.xaml.cs,如示例代码9-2所示为与示例代码9-1对应的后台代码。
其中,类Window1从Window类继承,对应到示例代码9-1中的FrmMain窗体所使用的类,btnShowMsg_Click()方法则对应到示例代码9-1中btnShowMsg的Click事件处理函数。这两个代码文件相互关联,并且一一对应,一个发生修改必须同时修改另外一个。
示例代码9-2:
namespace HelloWPF{/// &summary&/// Window1.xaml 的交互逻辑/// &/summary&public partial class Window1 : Window{public Window1( ){InitializeComponent( );}
private void btnShowMsg_Click(object sender, RoutedEventArgs e)
MessageBox.Show(&Hello WPF, I'm coming !&);
9.1.3 WPF应用程序
Windows Presentation Foundation(WPF)旨在提供用户界面应用程序开发框架,所以基于WPF的应用程序多为用户界面程序。Visual Studio 2008集成了WPF开发支持,提供下面4种类型的WPF应用程序创建向导。
WPF应用程序:也称WPF独立应用程序,创建一个在客户端直接运行的独立的应用程序,和Windows窗体应用程序类似。
WPF浏览器应用程序:创建一个可以承载在浏览器(IE6、IE7及以上版本)之内的应用程序,可以进行页面导航,但是和Web页面不一样。
WPF用户控件库:创建包含开发人员自行开发的WPF用户控件类库。
WPF自定义控件库:创建包含开发人员自行开发的自定义控件类库。
这些应用程序类型都包含在&C#&&&Windows&分类中。其中,WPF独立应用程序和WPF浏览器应用程序都比较常用,而控件库应用程序则多用在需要自行开发并发布独立的用户控件类库中。
一个可执行的WPF应用程序通常需要一组核心功能,包括创建和管理通用应用程序基础结构、跟踪应用程序的生命周期、检索和处理命令行参数、处理资源文件、拦截未处理异常、返回退出代码等。另外,一个WPF应用程序除了可执行文件之外,还需要其他外部文件的支持,这些文件主要有资源文件、内容文件、源站点文件3类。
WPF应用程序的资源文件和Windows窗体应用程序的资源文件一样,在程序开发时期准备,并且被编译到应用程序内部。
内容文件则是独立于应用程序的文件,但是应用程序运行时这些文件是必需的,例如应用程序配置文件、数据库文件等。这些文件在发布时与应用程序一起发布,在开发期间不一定存在,但在应用程序编译时肯定存在,因为它们会被Visual Studio 2008自动移动到目标目录中。
最后,源站点文件是在编译时无法确定是否存在的文件,这些文件可能保存在远程应用程序中或是保存在远程Web网站上,需要在程序运行时临时从外部站点获取。在WPF应用程序中,如果使用这类文件,必须考虑到文件不存在的情况,并给出相应的处理。
WPF提供了4种类型的应用程序,本章将通过实例详细介绍最常用的两种应用程&&& 序--WPF独立应用程序和WPF浏览器应用程序,并将介绍在Visual Studio 2008中如何开发WPF应用程序。
9.2 WPF独立应用程序
WPF独立应用程序是可以在客户端独立运行的应用程序,它在操作界面、运行方式上和Win Form窗体应用程序十分类似,所以也是最常用的WPF应用程序之一,本节将介绍WPF独立应用程序的开发过程、代码结构、窗体和控件的使用等基础知识。
9.2.1 创建WPF独立应用程序
在Visual Studio 2008中,要创建一个WPF独立应用程序,只需根据创建向导执行即可,主要包括下面4个步骤:
(1)打开Visual Studio 2008开发环境,通过选择&文件&&&新建&&&项目&命令打开&新建项目&对话框。
------分隔线----------------------------
Tab Control in WPF The Tab control is a common UI element that has been around f...WPF对初学者来说一个比较复杂的概念是它用两个树来组织其元素的。了解一些WPF的同学一般都知道它们分别是逻辑树(Logical Tree)和视觉树(Visual Tree)。而这两者的关系,以及一个界面中元素究竟如何与另一个元素在这两棵树上联系起来却相当复杂,很难一言两语涵盖其规则。而树和WPF中的元素类的特性有关系,也对应了XAML构成,所以非常重要,是比较深入理解WPF的关键。网上有不少文章就是专门讨论这个问题的。
比如以下是一些关于这个问题的比较经典的文章:
其实,我学和用WPF至今,也没有把这些内容完全弄明白,甚至很大部分都不是很明白。但是WPF的一个好处是其基本使用可以不用涉及这些。但当要开发比较高级的界面程序,用到比较多的WPF控件及其嵌套和事件响应,尤其是要启用大量关系复杂的WPF Templates和Styles以发挥出WPF的真正能量的时候,对树的深入理解,以及对各控件属性的了解就显得必不可少。
为此在对基本原理有些了解以后,我制作了一个小小的WPF用户控件(User Control),当这个控件和一个WPF容器绑定的时候,其内含的树形视图(TreeView)将会显示出被绑定容器中的元素在这两个关系树上的位置和相互关系。
这个显示树的根节点就是这个容器。这里的问题是如何显示两棵树?答案很简单,由于根节点只有一个,只要将每个节点的两组孩子(也包括同时是视觉和逻辑的孩子)都放在其下,用颜色来标识即可。
当用户点击一个目标控件时,树形视图中的中对应的节点会被高亮选中。有趣的是,由于Visual Studio的IDE对WPF开发支持,如果这个控件和目标容器同时放到设计窗体下,只要在XAML中将该控件和目标容器绑定,无需代码(C# Code Behind),无需执行,只要通过Build,控件树形视图就能显示目标容器的内容,如图1所示,其中蓝色表示作为逻辑树孩子,黄色表示作为视觉树孩子,浅绿色表示同时作为两者。可见树和XAML有很高的相关性(XAML实际上是省略了一些树的节点的版本)。
图1 设计期控件对容器内元素的展示
这个控件采用MVVM设计模式实现,View端就是其内含的树形控件,Model端就是被绑定的目标元素(节点),ViewModel是连接两者的控制翻译体。几乎所有逻辑全在ViewModel中。
有趣的是,我在开始做之前就估计这个东西做起来比较简单,而事实上它比我想象的还容易。只要对两个树、WPF以及MVVM有所了解就不难实现。而不难实现的主要原因也还是这个实例恰好利用了MVVM模式的特点和强大之处。
以下简要说明一下代码(看完代码这个设计思路也就清楚了),
先看这个控件的XAML。很简单就是包含了一个树形控件,连属性什么的也不需要设置,就命了个名称,在Code Behind中有一处要引用。
&UserControl x:Class=&WpfTreeViewer.WpfTreeViewerControl&
xmlns=&/winfx/2006/xaml/presentation&
xmlns:x=&/winfx/2006/xaml&
xmlns:mc=&http://schemas.openxmlformats.org/markup-compatibility/2006&
xmlns:d=&/expression/blend/2008&
mc:Ignorable=&d& d:DesignHeight=&300& d:DesignWidth=&300&&
&UserControl.Resources&
&ResourceDictionary Source=&ControlResources.xaml&/&
&/UserControl.Resources&
&TreeView x:Name=&WpfTreeView&&
&/TreeView&
&/UserControl&
这里有一处资源的引用,其实可以直接内嵌在这里,但为了清晰分置在资源XAML中,如下。这个XAML是关键所在,它规定了这个树形控件和ViewModel如何绑定,从而决定了其行为和样式。这个需要和ViewModel一起来看。
&ResourceDictionary xmlns=&/winfx/2006/xaml/presentation&
xmlns:x=&/winfx/2006/xaml&
xmlns:ViewModel=&clr-namespace:WpfTreeViewer.ViewModel&&
&Style TargetType=&TreeViewItem&&
&Setter Property=&IsExpanded& Value=&True&/&
&Setter Property=&IsSelected& Value=&{Binding Path=IsSelected, Mode=TwoWay}&/&
&HierarchicalDataTemplate DataType=&{x:Type ViewModel:WpfTreeNodeViewModel}&
ItemsSource=&{Binding Path=Children}&&
&StackPanel Orientation=&Horizontal&&
&TextBlock Foreground =&{Binding Path=RelationBrush}&&
&TextBlock.Text&
&Binding Path=&DisplayName&/&
&/TextBlock.Text&
&/TextBlock&
&/StackPanel&
&/HierarchicalDataTemplate&
&/ResourceDictionary&
所以接下来来看这个ViewModel,如下。ViewModel在一侧和对应的数据模型Model(这里就是目标容器中的一个具体的元素)一一对应,另一侧和表现视图View中的表现元素(这里就是树的一个节点)一一对应。对于树的节点,它需要暴露几个在上述XAML中引用到的属性,其中一个是Children,它指示了节点的儿子,于是树可以沿着各个节点伸展下去;另一个是IsSelected属性,它用于树节点的选中。这里的设计是高亮选中被点击的元素所对应的树节点。WPF默认的树形视图控件是单选的,但对这里的使用已经足够,因为只会有一个元素被单击。显然这里的传递应该是单向的。但上述指定为TwoWay,原因比较特殊,因为我们这里用代码来屏蔽用户选择对另一侧的影响的(我觉得应该有更好的解决方案,例如通过属性指定在视图侧树形控件不可被用户点击选择,但目前还没找到这个方案);还有一个是规定绘制颜色的Brush,用来设置节点文本的背景色以指示节点的属性。IsExpanded默认设置为True,这样树形视图控件默认展开,于是在设计期就能查看效果(如前面图1所示)。ViewModel中主要完成将一个元素绑定之后递归绑定所有子元素的逻辑,由其静态函数Create()肇始。
namespace WpfTreeViewer.ViewModel
public class WpfTreeNodeViewModel : ViewModelBase&object&
#region Enumerations
public enum RelationsWithParent
Logical = 0,
LogicalAndVisual
#endregion
#region Constants
private readonly Color[] _reltionColorMap = new[] { Colors.Blue, Colors.Orange, Colors.Chartreuse };
#endregion
#region Properties
#region Exposed as ViewModel
public bool IsSelected
get { return _isS }
private bool IsSelectedInternal
_isSelected =
OnPropertyChanged(&IsSelected&);
public ObservableCollection&WpfTreeNodeViewModel& Children
get { return _children ?? (_children = new ObservableCollection&WpfTreeNodeViewModel&()); }
public Brush RelationBrush
get { return new SolidColorBrush(RelationColor); }
public Color RelationColor
get { return _relationC }
if (value == _relationColor)
_relationColor =
OnPropertyChanged(&RelationColor&);
OnPropertyChanged(&RelationBrush&);
#endregion
#region Internal use
public RelationsWithParent RelationWithParent
get { return _relationWithP }
if (value == _relationWithParent)
_relationWithParent =
RelationColor = _reltionColorMap[(int)value];
#endregion
#endregion
#region Construcotrs
private WpfTreeNodeViewModel(object model)
: base(model)
_relationWithParent = RelationsWithParent.L
_relationColor = _reltionColorMap[(int)RelationWithParent];
IsSelected =
if (Model is FrameworkElement)
((FrameworkElement)Model).PreviewMouseDown += ModelOnPreviewMouseD
#endregion
#region Methods
public static WpfTreeNodeViewModel Create(DependencyObject model)
var viewModel = new WpfTreeNodeViewModel(model);
MapNode(viewModel, model);
return viewM
private static void MapNode(WpfTreeNodeViewModel viewModel, object model)
var dobj = model as DependencyO
if (dobj == null)
// TODO generate a suitable name
viewModel.DisplayName = model.ToString();
var mergedChildren = new HashSet&object&();
var mergedChildrenDesc = new Dictionary&object, RelationsWithParent&();
var logicChildren = LogicalTreeHelper.GetChildren(dobj);
foreach (var logicChild in logicChildren)
mergedChildren.Add(logicChild);
mergedChildrenDesc[logicChild] = RelationsWithParent.L
if (dobj is Visual || dobj is Visual3D)
var visualChildrenCount = VisualTreeHelper.GetChildrenCount(dobj);
for (var i = 0; i & visualChildrenC i++)
var visualChild = VisualTreeHelper.GetChild(dobj, i);
if (!mergedChildren.Contains(visualChild))
mergedChildren.Add(visualChild);
mergedChildrenDesc[visualChild] = RelationsWithParent.V
else if (mergedChildrenDesc[visualChild] == RelationsWithParent.Logical)
mergedChildrenDesc[visualChild] = RelationsWithParent.LogicalAndV
// TODO generate a suitable name
viewModel.DisplayName = dobj.GetType().ToString();
foreach (var child in mergedChildren)
var childViewModel = new WpfTreeNodeViewModel(child)
RelationWithParent = mergedChildrenDesc[child]
viewModel.Children.Add(childViewModel);
MapNode(childViewModel, child);
private void ModelOnPreviewMouseDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
if (_lastSelected != null)
_lastSelected.IsSelectedInternal =
IsSelectedInternal =
_lastSelected =
#endregion
#region Fields
private ObservableCollection&WpfTreeNodeViewModel& _
private RelationsWithParent _relationWithP
private Color _relationC
private static WpfTreeNodeViewModel _lastS
private bool _isS
#endregion
如此在这个用户控件的主体Code Behind中主要只需暴露一个Root属性,用于外部调用者绑定容器控件即可:
namespace WpfTreeViewer
/// &summary&
/// Interaction logic for WpfTreeViewerControl.xaml
/// &/summary&
public partial class WpfTreeViewerControl
#region Fields
public static DependencyProperty RootProperty = DependencyProperty.Register(&Root&, typeof (DependencyObject),
typeof (WpfTreeViewerControl),
new PropertyMetadata(null,
PropertyChangedCallback));
#endregion
#region Properties
public DependencyObject Root
get { return (DependencyObject)GetValue(RootProperty); }
set { SetValue(RootProperty, value); }
#endregion
#region Constructors
public WpfTreeViewerControl()
InitializeComponent();
#endregion
#region Methods
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
var control = dependencyObject as WpfTreeViewerC
var rootViewModel = WpfTreeNodeViewModel.Create((DependencyObject)e.NewValue);
System.Diagnostics.Trace.Assert(control != null);
control.WpfTreeView.ItemsSource = new List&object& { rootViewModel };
#endregion
主窗体的XAML(包括容器定义)大致如图1中XAML文本编辑器中所示。
执行期就如下图所示(树节点选中高亮还存在一些微小的问题,但貌似不算Bug):
图2 运行截图
托WPF-MVVM的福,程序显得过于简单,就不代码维护了,但肯定可以增加不少特性用于进一步WPF学习和分析。源码下载(用VS2010和VS2012打开应该没有任何问题),欢迎拍砖:
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:199233次
积分:4465
积分:4465
排名:第2256名
原创:200篇
评论:207条
(4)(4)(4)(6)(2)(1)(2)(2)(5)(1)(1)(2)(2)(1)(1)(7)(19)(14)(4)(3)(2)(6)(1)(1)(1)(1)(1)(1)(1)(5)(3)(7)(1)(2)(1)(1)(1)(2)(2)(1)(2)(8)(7)(1)(1)(4)(1)(10)(2)(1)(1)(1)(2)(4)(3)(9)(5)(1)(2)(1)(1)(1)(1)(1)(3)(2)(1)(2)(1)(1)(2)(3)(1)

我要回帖

更多关于 wpf编程宝典 的文章

 

随机推荐