Siverlight 自定义TreeView 显示带连接线的组织结构树
效果图
前台代码
<UserControl x:Class="Hotellight.MainPage"
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:Hotellight"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<!-- Put all the items inside a horizontally stacked panel -->
<ItemsPanelTemplate x:Key="ItemsPanel">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
</ItemsPanelTemplate>
<!-- TreeViewItem style to stack a header on top of children -->
<Style x:Key="ContainerStyle" TargetType="sdk:TreeViewItem">
<Setter Property="ItemsPanel" Value="{StaticResource ItemsPanel}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdk:TreeViewItem">
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Stretch">
<Canvas>
<Line X1="0" Y1="0" X2="0" Y2="0" StrokeDashArray="2 4" Stroke="#88444444" StrokeThickness="1" local:TreeViewItemConnectingLine.IsSingleConnectingLineOf="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneTime}"></Line>
</Canvas>
<ContentControl local:TreeViewItemConnectingLine.IsHeaderOf="{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneTime}"
x:Name="HeaderContent"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
VerticalAlignment="Center"/>
<ItemsPresenter Canvas.Left="100" Canvas.Top="80" x:Name="Items" VerticalAlignment="Top" HorizontalAlignment="Center"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- HeaderContent -->
<sdk:HierarchicalDataTemplate x:Key="DepartmentTemplate" ItemsSource="{Binding ChildNodes}" ItemContainerStyle="{StaticResource ContainerStyle}">
<Border Background="AliceBlue" Margin="4 8" Padding="2" BorderBrush="Blue" BorderThickness="1" CornerRadius="6">
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Entity.Name}" Margin="6 4" HorizontalAlignment="Center" FontSize="12" FontWeight="Bold"/>
</StackPanel>
</Border>
</sdk:HierarchicalDataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<sdk:TreeView ItemTemplate="{StaticResource DepartmentTemplate}"
ItemsPanel="{StaticResource ItemsPanel}"
ItemContainerStyle="{StaticResource ContainerStyle}"
ItemsSource="{Binding}">
</sdk:TreeView>
</Grid>
</UserControl>
数据类
1 public class TreeNode<T> : GalaSoft.MvvmLight.ViewModelBase 2 where T:new() 3 { 4 private T _entity; 5 public T Entity 6 { 7 get 8 { 9 return _entity; 10 } 11 internal set 12 { 13 _entity = value; 14 RaisePropertyChanged("Entity"); 15 16 } 17 } 18 private int _level=-1; 19 public int Level 20 { 21 get { 22 return _level; 23 } 24 set { 25 if (_level != value) 26 { 27 _level = value; 28 RaisePropertyChanged("Level"); 29 } 30 } 31 } 32 public TreeNode(T entity) 33 { 34 Entity = entity; 35 _childNode = new ObservableCollection<TreeNode<T>>(); 36 } 37 private TreeNode<T> _parent; 38 public TreeNode<T> Parent 39 { 40 get 41 { 42 return _parent; 43 } 44 set 45 { 46 if (_parent != value) 47 { 48 _parent = value; 49 RaisePropertyChanged("Parent"); 50 } 51 } 52 } 53 private TreeNode<T> _nextNode; 54 55 public TreeNode<T> NextNode 56 { 57 get { 58 return _nextNode; 59 } 60 internal set { 61 if (_nextNode != value) 62 { 63 _nextNode = value; 64 RaisePropertyChanged("NextNode"); 65 } 66 } 67 } 68 private TreeNode<T> _previouNode; 69 70 public TreeNode<T> PreviouNode 71 { 72 get { 73 return _previouNode; 74 } 75 internal set { 76 if (_previouNode != value) 77 { 78 _previouNode = value; 79 RaisePropertyChanged("PreviouNode"); 80 } 81 } 82 } 83 private ObservableCollection<TreeNode<T>> _childNode; 84 public ObservableCollection<TreeNode<T>> ChildNodes 85 { 86 get 87 { 88 return _childNode; 89 } 90 internal set 91 { 92 _childNode = value; 93 RaisePropertyChanged("ChildNodes"); 94 } 95 } 96 } 97 public class TreeCollection<T> : ObservableCollection<TreeNode<T>> 98 where T:new() 99 {100 public const string DefaultKeyProperty = "ID";101 public const string DefaultReferenceProperty = "ParentID";102 internal PropertyInfo KeyProperty103 {104 get;105 set;106 }107 internal PropertyInfo ReferenceProperty108 {109 get;110 set;111 }112 public static Type TType113 {114 get;115 set;116 }117 118 public TreeCollection(string keyProperty, string referenceProperty)119 {120 TType = typeof(T);121 KeyProperty = TType.GetProperty(keyProperty);122 ReferenceProperty =TType.GetProperty( referenceProperty);123 T entity = new T();124 TreeNode<T> node = new TreeNode<T>(entity);125 this.Items.Add(node);126 }127 public TreeCollection(IEnumerable<T> rawDatas,string keyProperty,string referenceProperty):this(keyProperty,referenceProperty)128 {129 foreach (var i in rawDatas)130 {131 Add(i);132 }133 }134 public TreeCollection(IEnumerable<T> rawDatas)135 : this(rawDatas, DefaultKeyProperty, DefaultReferenceProperty)136 { }137 public TreeCollection() : this(DefaultKeyProperty, DefaultReferenceProperty) 138 { }139 public TreeNode<T> RootNode140 {141 get142 {143 return this.Items.Where(i => i.Parent == null).FirstOrDefault();144 }145 }146 public TreeNode<T> Add(T entity)147 {148 foreach (var i in this.Items)149 {150 var val = KeyProperty.GetValue(i.Entity, null);151 if(val != null && val.Equals(KeyProperty.GetValue(entity,null)))152 {153 return i;154 }155 }156 var parent = FindParentNode(RootNode, entity)??RootNode;157 var node = new TreeNode<T>(entity);158 node.Level = parent.Level + 1;159 var len = parent.ChildNodes.Count();160 if (len >0)161 {162 var prev = parent.ChildNodes[len - 1];163 node.NextNode = prev.NextNode;164 prev.NextNode = node;165 node.PreviouNode = prev;166 } 167 node.Parent = parent;168 parent.ChildNodes.Add(node);169 this.Items.Add(node);170 return node;171 172 }173 public TreeNode<T> AddAt(T entity, int index)174 {175 if(index<0)176 {177 throw new ArgumentOutOfRangeException("index");178 }179 180 foreach (var i in this.Items)181 {182 var val = KeyProperty.GetValue(i.Entity, null);183 if (val.Equals(KeyProperty.GetValue(entity, null)))184 {185 return i;186 }187 }188 var parent = FindParentNode(RootNode, entity) ?? RootNode;189 var node = new TreeNode<T>(entity);190 node.Parent = parent;191 var bfcount = parent.ChildNodes.Count;192 193 var prevIndex = index - 1;194 var nextIndex = index;195 if (prevIndex > 0 && prevIndex < bfcount)196 {197 var prev = parent.ChildNodes[prevIndex];198 if (prev != null)199 {200 node.PreviouNode = prev;201 prev.NextNode = node;202 }203 204 }205 if (nextIndex > 0 && nextIndex < bfcount)206 {207 var next = parent.ChildNodes[index];208 if (next != null)209 {210 node.NextNode = next;211 next.PreviouNode = node;212 }213 }214 parent.ChildNodes.Insert(index, node);215 this.Items.Add(node);216 return node;217 }218 219 public TreeNode<T> Remove(T entity)220 {221 var val = KeyProperty.GetValue(entity, null);222 var node = FindNodeByKeyProperty(val);223 if (node != null)224 {225 if (node.PreviouNode != null)226 {227 node.PreviouNode.NextNode = node.NextNode;228 }229 node.Parent.ChildNodes.Remove(node);230 node.Parent = null;231 this.Items.Remove(node);232 }233 return node;234 }235 public void MoveTo(TreeNode<T> node, TreeNode<T> parent,int index)236 {237 if (parent == null)238 {239 return;240 }241 var entity = node.Entity;242 Remove(entity);243 var val = KeyProperty.GetValue(parent, null);244 ReferenceProperty.SetValue(entity, val,null);245 AddAt(entity, index);246 }247 public TreeNode<T> this[int level, int index]248 {249 get250 {251 return this.Items.Where(i => i.Level == level).Skip(index).First();252 }253 }254 public TreeNode<T> FindNodeByKeyProperty(object keyPropertyValue)255 {256 257 foreach (var i in this.Items)258 {259 if (KeyProperty.GetValue(i, null).Equals(keyPropertyValue))260 {261 return i;262 }263 }264 return null;265 }266 267 internal TreeNode<T> FindParentNode(TreeNode<T> node,T entity)268 {269 270 var keyValue = KeyProperty.GetValue(node.Entity, null);271 var refValue = ReferenceProperty.GetValue(entity, null);272 if (refValue.Equals(keyValue))273 {274 return node;275 }276 else277 {278 TreeNode<T> temp = null;279 foreach (var i in node.ChildNodes)280 {281 temp = FindParentNode(i, entity);282 if (temp != null)283 {284 return temp;285 }286 }287 }288 289 return null;290 }291 }
后台树控件扩展代码
1 public static class TreeViewItemConnectingLine 2 { 3 internal static TreeViewItemSingleLineInfo GetSingleConnectingLine(TreeViewItem element) 4 { 5 if (element == null) 6 { 7 throw new ArgumentNullException("element"); 8 } 9 TreeViewItemSingleLineInfo info = element.GetValue(SingleConnectingLineProperty) as TreeViewItemSingleLineInfo; 10 if (info == null) 11 { 12 info = new TreeViewItemSingleLineInfo(element); 13 element.SetValue(SingleConnectingLineProperty, info); 14 } 15 return info; 16 } 17 internal static readonly DependencyProperty SingleConnectingLineProperty = 18 DependencyProperty.RegisterAttached( 19 "SingleConnectingLine", 20 typeof(TreeViewItemSingleLineInfo), 21 typeof(TreeViewItemConnectingLine), 22 new PropertyMetadata(null)); 23 public static TreeViewItem GetIsSingleConnectingLineOf(Line element) 24 { 25 if (element == null) 26 { 27 throw new ArgumentNullException("element"); 28 } 29 return element.GetValue(IsSingleConnectingLineOfProperty) as TreeViewItem; 30 } 31 public static void SetIsSingleConnectingLineOf(Line element, TreeViewItem value) 32 { 33 if (element == null) 34 { 35 throw new ArgumentNullException("element"); 36 } 37 element.SetValue(IsSingleConnectingLineOfProperty, value); 38 } 39 public static readonly DependencyProperty IsSingleConnectingLineOfProperty = 40 DependencyProperty.RegisterAttached("IsSingleConnectingLineOf", 41 typeof(TreeViewItem), 42 typeof(TreeViewItemConnectingLine), 43 new PropertyMetadata(null, OnIsSingleConnectingLineOfPropertyChanged)); 44 private static void OnIsSingleConnectingLineOfPropertyChanged(DependencyObject d, 45 DependencyPropertyChangedEventArgs e) 46 { 47 Line source = d as Line; 48 TreeViewItem value = e.NewValue as TreeViewItem; 49 if (value != null) 50 { 51 TreeViewItemSingleLineInfo info = GetSingleConnectingLine(value); 52 info.ConnectingLine = source; 53 } 54 else 55 { 56 value = e.OldValue as TreeViewItem; 57 if (value != null) 58 { 59 TreeViewItemSingleLineInfo info = GetSingleConnectingLine(value); 60 info.ConnectingLine = null; 61 } 62 } 63 } 64 65 public static TreeViewItem GetIsHeaderOf(FrameworkElement element) 66 { 67 if (element == null) 68 { 69 throw new ArgumentNullException("element"); 70 } 71 return element.GetValue(IsHeaderOfProperty) as TreeViewItem; 72 } 73 public static void SetIsHeaderOf(FrameworkElement element, TreeViewItem value) 74 { 75 if (element == null) 76 { 77 throw new ArgumentNullException("element"); 78 } 79 element.SetValue(IsHeaderOfProperty, value); 80 } 81 public static readonly DependencyProperty IsHeaderOfProperty = 82 DependencyProperty.RegisterAttached( 83 "IsHeaderOf", 84 typeof(TreeViewItem), 85 typeof(TreeViewItemConnectingLine), 86 new PropertyMetadata(null, OnIsHeaderOfPropertyChanged)); 87 private static void OnIsHeaderOfPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 88 { 89 FrameworkElement source = d as FrameworkElement; 90 TreeViewItem value = e.NewValue as TreeViewItem; 91 92 if (value != null) 93 { 94 TreeViewItemSingleLineInfo info = GetSingleConnectingLine(value); 95 info.Header = source; 96 } 97 else 98 { 99 value = e.OldValue as TreeViewItem;100 if (value != null)101 {102 TreeViewItemSingleLineInfo info = GetSingleConnectingLine(value);103 info.Header = null;104 }105 }106 }107 108 }109 110 public class TreeViewItemSingleLineInfo111 {112 public TreeViewItem Item { get; private set; }113 public Line ConnectingLine { get; set; }114 public FrameworkElement Header { get; set; }115 public TreeViewItemSingleLineInfo(TreeViewItem item)116 {117 Debug.Assert(item != null, "item should not be null!");118 Item = item;119 item.LayoutUpdated += (s, e) => PositionConnectingLines("LayoutUpdated");120 item.Expanded += (s, e) => PositionConnectingLines("Expanded");121 item.Collapsed += (s, e) => PositionConnectingLines("Collapsed");122 item.ItemContainerGenerator.ItemsChanged += (s, e) => PositionConnectingLines("ItemsChanged");123 124 }125 126 private void PositionConnectingLines(string eventName)127 {128 if (Item.GetIsRoot())129 {130 131 return;132 }133 if (ConnectingLine == null)134 {135 return;136 137 }138 var parentTreeViewItem = Item.GetParentTreeViewItem();139 if (parentTreeViewItem == null) { return; }140 141 var fromElement = TreeViewItemConnectingLine.GetSingleConnectingLine(parentTreeViewItem).Header;142 if (fromElement == null)143 {144 ConnectingLine.Visibility = Visibility.Collapsed;145 return;146 }147 Rect? bound = fromElement.GetBoundsRelativeTo(ConnectingLine);148 ConnectingLine.X1 = bound.Value.X+bound.Value.Width/2;149 ConnectingLine.Y1 = bound.Value.Y+bound.Value.Height/2;150 151 bound = Header.GetBoundsRelativeTo(ConnectingLine);152 153 ConnectingLine.X2 = bound.Value.X + bound.Value.Width / 2;154 ConnectingLine.Y2 = bound.Value.Y + bound.Value.Height / 2;155 156 ConnectingLine.Visibility = Visibility.Visible;157 158 }159 }
转载于:https://www.cnblogs.com/mayamoon/archive/2011/10/06/Custom_Organization_TreeView.html
Siverlight 自定义TreeView 显示带连接线的组织结构树相关推荐
- android java 圆角_Android自定义View实现带4圆角或者2圆角的效果
1 问题 实现任意view经过自定义带4圆角或者2圆角的效果 2 原理 1) 实现view 4圆角 我们只需要把左边的图嵌入到右边里面去,最终显示左边的图就行. 2) 实现view上2圆角 我们只需要 ...
- android 两边圆角,Android自定义View实现带4圆角或者2圆角的效果
1 问题 实现任意view经过自定义带4圆角或者2圆角的效果 2 原理 1) 实现view 4圆角 我们只需要把左边的图嵌入到右边里面去,最终显示左边的图就行. 2) 实现view上2圆角 我们只需要 ...
- 一分钟学会自定义右上角显示数字的ImageView
平时在一些app上会看到一些图标的右上角会显示数字,如微信的头像右上角显示信息数量,淘宝的购物车图标右上角显示商品数量.本人最近也在努力学习自定义控件,下面是本人实现的一个简陋的带数字的ImageVi ...
- 基于vue的组织架构树组件_Vue组件基于D3.js布局显示树
基于vue的组织架构树组件 Vue.D3.tree (Vue.D3.tree) Update documentationVue components to display graphics based ...
- HQChart使用教程2- 如何把自定义指标显示在K线图页面
如何把自定义指标显示在K线图页面 自定义一个指标 通过Option设置指标 自定义一个带参数的指标 让我们用上证指数来回测这个奇葩的BS指标吧 HQChart代码地址 效果图 自定义一个指标 假设我们 ...
- Leaflet中使用awesome-markers插件显示带图标的marker
场景 Vue+Leaflet实现加载OSM显示地图: Vue+Leaflet实现加载OSM显示地图_BADAO_LIUMANG_QIZHI的博客-CSDN博客 在上面的基础上,实现Marker上带图标 ...
- Android自定义文件路径箭头,Android自定义ViewGroup实现带箭头的圆角矩形菜单
本文和大家一起做一个带箭头的圆角矩形菜单,大概长下面这个样子: 要求顶上的箭头要对准菜单锚点,菜单项按压反色,菜单背景色和按压色可配置. 最简单的做法就是让UX给个三角形的图片往上一贴,但是转念一想这 ...
- bootstrap bootstraptable 固定列_1个Excel公式按条件自定义格式显示固定电话号码
点击右上角"关注",每天免费获取干货教程 前面写了很多篇关于数据查询.数据统计.数据分析.公式排错的教程,今天换一个口味,写个关于自定义格式显示数据的教程. 因为工作中很多时候都需 ...
- Android 自定义 ListView 显示网络上 JSON 格式歌曲列表
本文内容 环境 项目结构 演示自定义 ListView 显示网络上 JSON 歌曲列表 参考资料 本文最开始看的是一个国人翻译的文章,没有源代码可下载,根据文中提供的代码片段,自己新建的项目(比较可恶 ...
- WPF学习笔记(7):DataGrid中数字自定义格式显示
WPF学习笔记(7):DataGrid中数字自定义格式显示 原文:WPF学习笔记(7):DataGrid中数字自定义格式显示 DataGrid中数据显示如下图,数据格式比较杂乱.希望达到以下要求:(1 ...
最新文章
- vue饼图统计_做可交互的统计图表,这套图形语法不容错过
- jQuery中读取json文件示例代码
- 在大数据时代,每家公司都要有大数据部门吗?
- fastdfs连接mysql_fastDFS文件上传简单案例
- Spring Boot笔记-@PathVariable的使用
- mybatis分页插件_MyBatis 分页插件 5.2.0 发布
- 使用IIS 7.0 Smooth Streaming 优化视频服务
- c语言入门经典+第5版+习题答案,《C语言入门经典(第5版)》—甲虎网一站式图书批发平台...
- opencv如何隐藏窗口
- 计算机二级考试能不能用键盘,计算机二级 ,你中招了吗?
- 没有公网IP?快解析实现内网穿透
- 如何进行大数据处理?大数据处理的方法步骤
- java如何等待异步结果_你如何等待所有异步调用在Java中完成?
- windows 平台使用dul 抽取Linux oracle ASM 磁盘数据文件
- C++STL详解(一)string类的使用及其模拟实现
- 用switch做了一个简单的计算器可以进行四则运算和模运算
- 【证明】线性变换在两个基下的矩阵相似
- Matlab中连续信号与离散信号的绘制
- 基于云的视频会议五大优点
- 使用python读取gif,合并gif,视频转换为gif
热门文章
- 常见的三种Content-Type
- SqlServer修改sa的密码
- 15. 注意string实现的多样性
- ipoo3可以用鸿蒙,vivo新机入网!支持44W快充 配置与iQOO Neo3类似
- Spring基于XML的IOC细节
- java文件编译为class文件需要键入什么命令_Day02:Java语言基础-第一个Java程序以及编译与运行机制...
- vb6 由于超出容量限制 不能创建新事务_Executors类创建四种常见线程池
- arraylist 线性不安全_Java面试系列(一)--集合类ArrayList
- Javascript:获取点击的li标签内部文字
- SQL:postgresqll查询某字段各情况数量