WPF—TreeView
作者:追风剑情 发布于:2020-12-23 17:44 分类:C#
xaml
<Window x:Class="DataEditor.JsonWindow" 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:DataEditor" mc:Ignorable="d" Title="JsonWindow" Height="450" Width="800" WindowStyle="ToolWindow"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="190*"/> <ColumnDefinition Width="167*"/> </Grid.ColumnDefinitions> <TreeView Name="JsonTree" Margin="5"> <TreeView.ItemContainerStyle> <!--TargetType指定要作用的对象类型--> <Style TargetType="TreeViewItem"> <Style.Resources> <!--选中且处于激活状态的样式--> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="DodgerBlue"/> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="White"/> <!--选中且处于非激活状态的样式--> <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="DodgerBlue"/> <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="White"/> </Style.Resources> <!--将一些TreeViewItem属性与数据对象属性做绑定(Mode=TwoWay)--> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" /> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> <!--TextBlock.Text与TreeNodeModel.NodeName做数据双向绑定--> <Setter Property="TextBlock.Text" Value="{Binding NodeName, Mode=TwoWay}"/> <!--为TargetType注册事件处理器--> <EventSetter Event="PreviewMouseRightButtonDown" Handler="JsonTreeItem_PreviewMouseRightButtonDown"/> <EventSetter Event="Selected" Handler="TreeViewItem_Selected"/> </Style> </TreeView.ItemContainerStyle> <TreeView.ItemTemplate> <!--ItemsSource:指定子节点字段名称--> <HierarchicalDataTemplate DataType="{x:Type local:TreeNodeModel}" ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Path=NodeName}"></TextBlock> </HierarchicalDataTemplate> </TreeView.ItemTemplate> <!--右键菜单--> <TreeView.ContextMenu> <ContextMenu> <MenuItem x:Name="ContextMenuAddNode" Header="添加元素" Click="ContextMenuAddNode_Click"/> <MenuItem x:Name="ContextMenuRemoveNode" Header="删除元素" Click="ContextMenuRemoveNode_Click"/> </ContextMenu> </TreeView.ContextMenu> </TreeView> </Grid> </Window>
xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Windows.Controls.Primitives; using System.Reflection; namespace DataEditor { /// <summary> /// JsonWindow.xaml 的交互逻辑 /// </summary> public partial class JsonWindow : Window { public JsonWindow() { InitializeComponent(); Initialize(); } private void Initialize() { ShowTestData(); } //显示测试数据 private void ShowTestData() { TestTreeObject obj = new TestTreeObject(); List<TreeNodeModel> root = TreeNodeModel.Convert(obj); JsonTree.ItemsSource = root; } private TreeViewItem _selectedTreeViewItem; //TreeView选择节点 private void TreeViewItem_Selected(object sender, RoutedEventArgs e) { _selectedTreeViewItem = e.OriginalSource as TreeViewItem; Console.WriteLine(_selectedTreeViewItem); } //TreeView节点上点击右键 private void JsonTreeItem_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { var treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem; if (treeViewItem != null) { treeViewItem.Focus(); e.Handled = true; } TreeNodeModel model = treeViewItem.DataContext as TreeNodeModel; this.ContextMenuAddNode.IsEnabled = model.IsArray; this.ContextMenuRemoveNode.IsEnabled = model.CanRemove; } //向上搜索父控件 static DependencyObject VisualUpwardSearch<T>(DependencyObject source) { while (source != null && source.GetType() != typeof(T)) source = VisualTreeHelper.GetParent(source); return source; } //右键菜单-添加节点 private void ContextMenuAddNode_Click(object sender, RoutedEventArgs e) { AddArrayNode(); } //右键菜单-删除节点 private void ContextMenuRemoveNode_Click(object sender, RoutedEventArgs e) { RemoveArrayNode(); } //添加数组节点 private void AddArrayNode() { TreeNodeModel selectedValue = JsonTree.SelectedValue as TreeNodeModel; if (selectedValue == null || !selectedValue.DataFieldInfo.IsArray()) return; if (selectedValue.Children == null) selectedValue.Children = new List<TreeNodeModel>(); int childrenCount = selectedValue.Children.Count; TreeNodeModel newModel = new TreeNodeModel(); newModel.CanRemove = true; newModel.NodeName = string.Format("[{0}]", childrenCount); if (selectedValue.DataFieldInfo.IsJsonObjectArray()) { Type elementType = selectedValue.DataFieldInfo.GetElementType(); Console.WriteLine("Add Array Element: {0}", elementType.FullName); var newElement = Activator.CreateInstance(elementType); newModel.Children = TreeNodeModel.Convert(newElement); newModel.IsExpanded = false; newModel.IsSelected = false; } selectedValue.Children.Add(newModel); newModel.Parent = selectedValue; TreeViewRefresh(); } //删除数组节点 private void RemoveArrayNode() { TreeNodeModel selectedValue = JsonTree.SelectedValue as TreeNodeModel; if (selectedValue == null || !selectedValue.CanRemove) return; selectedValue.Parent.Children.Remove(selectedValue); List<TreeNodeModel> children = selectedValue.Parent.Children; //重置索引节点编号 for (int i=0; i<children.Count; i++) { var model = children[i]; model.NodeName = string.Format("[{0}]", i); } selectedValue.Parent.IsSelected = true; TreeViewRefresh(); } //TreeView刷新显示 private void TreeViewRefresh() { //刷新数据 JsonTree.Items.Refresh(); //判断节点生成器状态 if (JsonTree.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) JsonTree.UpdateLayout(); } } //TreeView的显示模型 public class TreeNodeModel { //节点名称 private string _NodeName; public string NodeName { get { if (DataFieldInfo.IsArray()) { int childCount = Children != null ? Children.Count : 0; return string.Format("{0} [{1}]", _NodeName, childCount); } return _NodeName; } set { _NodeName = value; } } //是否展开 public bool IsExpanded { get; set; } //是否选中 public bool IsSelected { get; set; } //是否为可删除结点 public bool CanRemove { get; set; } //是否为数组 public bool IsArray { get; set; } public object DataObject { get; set; } public FieldInfo DataFieldInfo { get; set; } public PropertyInfo DataPropertyInfo { get; set; } public List<TreeNodeModel> Children { get; set; } public TreeNodeModel Parent { get; set; } public void SetValue(object value) { DataPropertyInfo.SetValue(DataObject, value); } public override string ToString() { return string.Format("NodeName={0}, ChildrenCount={1}", NodeName, Children == null ? 0 : Children.Count); } //数据模型转显示模型 public static List<TreeNodeModel> Convert(Object obj) { List<TreeNodeModel> list = new List<TreeNodeModel>(); Type t = obj.GetType(); return Convert(t); } private static List<TreeNodeModel> Convert(Type t, TreeNodeModel parent=null) { List<TreeNodeModel> list = new List<TreeNodeModel>(); FieldInfo[] fis = t.GetFields(BindingFlags.Instance | BindingFlags.Public); for (int i = 0; i < fis.Length; i++) { FieldInfo fi = fis[i]; object[] attrs = fi.GetCustomAttributes(typeof(DescriptionAttribute), true); if (attrs == null || attrs.Length < 1) continue; DescriptionAttribute datt = (DescriptionAttribute)attrs[0]; string desc = datt.description; TreeNodeModel model = new TreeNodeModel(); model.Parent = parent; model.NodeName = desc; model.DataFieldInfo = fi; model.IsArray = fi.IsArray(); if (parent != null && parent.IsArray) model.CanRemove = true; list.Add(model); //Type ft = fi.FieldType; //Console.WriteLine("FieldType: {0}", fi.FieldType); if (fi.IsInt32()) { //Console.WriteLine("{0} is Int32", fi.Name); } if (fi.IsArray()) { //Console.WriteLine("{0} is Array", fi.Name); } if (fi.IsString()) { //Console.WriteLine("{0} is String", fi.Name); } if (fi.IsObject()) { //Console.WriteLine("{0} is Object", fi.Name); } if (fi.FieldType.BaseType == typeof(JsonObject)) { //Console.WriteLine("{0} is JsonObject", fi.Name); model.Children = Convert(fi.FieldType, model); } } return list; } } [Serializable] public class JsonObject { } [Serializable] public class TestTreeObject : JsonObject { [Description("ID")] public int id; [Description("名称")] public string name; [Description("时间")] public TestTimebject time; [Description("时间数组")] public TestTimebject[] times; [Description("字符串数组")] public string[] arr; } [Serializable] public class TestTimebject : JsonObject { [Description("时")] public int hour; [Description("分")] public int minute; [Description("秒")] public int second; } }
using System; using System.Reflection; namespace DataEditor { /// <summary> /// FieldInfo扩展方法 /// </summary> internal static class FieldInfoExtensions { public static bool IsInt32(this FieldInfo fi) { if (fi == null) return false; return fi.FieldType == typeof(Int32); } public static bool IsString(this FieldInfo fi) { if (fi == null) return false; return fi.FieldType == typeof(String); } public static bool IsArray(this FieldInfo fi) { if (fi == null) return false; return fi.FieldType.BaseType == typeof(Array); } public static bool IsObject(this FieldInfo fi) { if (fi == null) return false; return fi.FieldType.BaseType == typeof(Object); } public static bool IsJsonObject(this FieldInfo fi) { if (fi == null) return false; return fi.FieldType.BaseType == typeof(JsonObject); } public static bool IsJsonObjectArray(this FieldInfo fi) { if (!fi.IsArray()) return false; Type t = fi.GetElementType(); return t.IsSubclassOf(typeof(JsonObject)); } public static Type GetElementType(this FieldInfo fi) { Type elType = fi.FieldType; string typeName = string.Empty; if (fi.IsArray()) { typeName = fi.FieldType.FullName.Replace("[]", string.Empty); elType = fi.FieldType.Assembly.GetType(typeName); } return elType; } } }
运行测试
将数据对象转成TreeView显示,且支持对数组进行添加/删除节点
标签: C#
« 模型粒子化效果
|
UGUI—实时频谱效果»
日历
最新文章
随机文章
热门文章
分类
存档
- 2024年11月(3)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号