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—实时频谱效果»
日历
最新文章
随机文章
热门文章
分类
存档
- 2025年3月(4)
- 2025年2月(3)
- 2025年1月(1)
- 2024年12月(5)
- 2024年11月(5)
- 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
- Open CASCADE
- CascadeStudio
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号
