From f92fd2f1cc5f53fd10e89552bb8c719f4be44f4b Mon Sep 17 00:00:00 2001 From: SugarChes Date: Mon, 10 Aug 2026 14:55:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=86=E4=B8=BB=E9=A1=B5=E5=B7=A6?= =?UTF-8?q?=E4=BE=A7=E8=8F=9C=E5=8D=95=E8=BF=81=E7=A7=BB=E5=88=B0=20TreeLi?= =?UTF-8?q?st?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Lskj.Main/Control/MainPanelControlEx.cs | 328 ++++++++++++------ 插件库/Lskj.Main/Lskj.Main.csproj | 5 +- 2 files changed, 219 insertions(+), 114 deletions(-) diff --git a/插件库/Lskj.Main/Control/MainPanelControlEx.cs b/插件库/Lskj.Main/Control/MainPanelControlEx.cs index dd7a9db..590ea38 100644 --- a/插件库/Lskj.Main/Control/MainPanelControlEx.cs +++ b/插件库/Lskj.Main/Control/MainPanelControlEx.cs @@ -11,6 +11,9 @@ using DevExpress.LookAndFeel; using DevExpress.XtraEditors; using DevExpress.XtraTab; using DevExpress.XtraTab.ViewInfo; +using DevExpress.XtraTreeList; +using DevExpress.XtraTreeList.Columns; +using DevExpress.XtraTreeList.Nodes; using Lskj.Business; using Lskj.Business.Impl; using Lskj.Control; @@ -129,12 +132,19 @@ namespace Lskj.Main.Control /// 缓存分组控件 /// private Dictionary _groupItems = new Dictionary(); - private TreeView _leftGroupTreeView; - private ImageList _leftGroupTreeIcons; + private TreeList _leftGroupTreeView; + private TreeListNode _leftGroupHotNode; + private TreeListNode _leftGroupSelectedNode; + private ImageList _leftGroupTreeImageList; private Panel _leftGroupSeparator; private const string LeftGroupTreeNodeTypeMenu = "menu"; private const string LeftGroupTreeNodeTypeGroup = "group"; private const int GroupControlTopPadding = 8; + private static readonly Color LeftGroupTreeBackgroundColor = Color.FromArgb(39, 45, 81); + private static readonly Color LeftGroupTreeActiveColor = Color.FromArgb(52, 142, 216); + private static readonly Color LeftGroupTreeTextColor = Color.FromArgb(235, 255, 255, 255); + private static readonly Color LeftGroupTreeArrowColor = Color.FromArgb(173, 255, 255, 255); + /// /// 缓存右上菜单控件 /// @@ -741,32 +751,171 @@ namespace Lskj.Main.Control return groupCaption.Length > 2 ? groupCaption.Remove(0, 2) : groupCaption; } - private TreeView GetLeftGroupTreeView() + private TreeList GetLeftGroupTreeView() { if (_leftGroupTreeView != null) return _leftGroupTreeView; - _leftGroupTreeView = new TreeView + _leftGroupTreeView = new TreeList { Dock = DockStyle.Fill, - BorderStyle = BorderStyle.None, - BackColor = Color.FromArgb(250, 253, 255), - DrawMode = TreeViewDrawMode.Normal, - Font = new Font("微软雅黑", 10F), - ForeColor = Color.FromArgb(38, 73, 98), - HideSelection = false, - Indent = 20, - ImageList = GetLeftGroupTreeIcons(), - ItemHeight = 29, - LineColor = Color.FromArgb(198, 214, 226), - ShowLines = false, - ShowPlusMinus = false, - ShowRootLines = false + BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder, + RowHeight = ScaleLeftGroupTreeMetric(44), + TreeLevelWidth = ScaleLeftGroupTreeMetric(18) }; - _leftGroupTreeView.NodeMouseClick += OnLeftGroupTreeViewNodeMouseClick; + + TreeListColumn textColumn = new TreeListColumn + { + Caption = "功能导航", + FieldName = "nodetext", + Visible = true, + VisibleIndex = 0 + }; + textColumn.OptionsColumn.AllowEdit = false; + _leftGroupTreeView.Columns.Add(textColumn); + + _leftGroupTreeView.OptionsBehavior.Editable = false; + _leftGroupTreeView.OptionsSelection.EnableAppearanceFocusedCell = false; + _leftGroupTreeView.OptionsSelection.EnableAppearanceFocusedRow = true; + _leftGroupTreeView.OptionsView.AutoWidth = true; + _leftGroupTreeView.OptionsView.ExpandButtonCentered = true; + _leftGroupTreeView.OptionsView.ShowButtons = false; + _leftGroupTreeView.OptionsView.ShowColumns = false; + _leftGroupTreeView.OptionsView.ShowFocusedFrame = false; + _leftGroupTreeView.OptionsView.ShowHorzLines = false; + _leftGroupTreeView.OptionsView.ShowIndentAsRowStyle = true; + _leftGroupTreeView.OptionsView.ShowIndicator = false; + _leftGroupTreeView.OptionsView.ShowVertLines = false; + + _leftGroupTreeView.Appearance.Empty.BackColor = LeftGroupTreeBackgroundColor; + _leftGroupTreeView.Appearance.Empty.Options.UseBackColor = true; + _leftGroupTreeView.Appearance.Row.BackColor = LeftGroupTreeBackgroundColor; + _leftGroupTreeView.Appearance.Row.ForeColor = LeftGroupTreeTextColor; + _leftGroupTreeView.Appearance.Row.Font = new Font("微软雅黑", 10F); + _leftGroupTreeView.Appearance.Row.Options.UseBackColor = true; + _leftGroupTreeView.Appearance.Row.Options.UseForeColor = true; + _leftGroupTreeView.Appearance.Row.Options.UseFont = true; + _leftGroupTreeView.Appearance.FocusedRow.BackColor = LeftGroupTreeActiveColor; + _leftGroupTreeView.Appearance.FocusedRow.ForeColor = Color.White; + _leftGroupTreeView.Appearance.FocusedRow.Options.UseBackColor = true; + _leftGroupTreeView.Appearance.FocusedRow.Options.UseForeColor = true; + _leftGroupTreeView.Appearance.HideSelectionRow.BackColor = LeftGroupTreeActiveColor; + _leftGroupTreeView.Appearance.HideSelectionRow.ForeColor = Color.White; + _leftGroupTreeView.Appearance.HideSelectionRow.Options.UseBackColor = true; + _leftGroupTreeView.Appearance.HideSelectionRow.Options.UseForeColor = true; + + _leftGroupTreeView.SelectImageList = GetLeftGroupTreeImageList(); + _leftGroupTreeView.AfterCollapse += OnLeftGroupTreeListAfterExpandOrCollapse; + _leftGroupTreeView.AfterExpand += OnLeftGroupTreeListAfterExpandOrCollapse; + _leftGroupTreeView.MouseClick += OnLeftGroupTreeListMouseClick; + _leftGroupTreeView.MouseLeave += OnLeftGroupTreeListMouseLeave; + _leftGroupTreeView.MouseMove += OnLeftGroupTreeListMouseMove; return _leftGroupTreeView; } + private ImageList GetLeftGroupTreeImageList() + { + if (_leftGroupTreeImageList != null) return _leftGroupTreeImageList; + + _leftGroupTreeImageList = new ImageList + { + ColorDepth = ColorDepth.Depth32Bit, + ImageSize = new Size(ScaleLeftGroupTreeMetric(14), ScaleLeftGroupTreeMetric(14)), + TransparentColor = Color.Transparent + }; + _leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(false, LeftGroupTreeArrowColor)); + _leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(true, LeftGroupTreeArrowColor)); + _leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(false, Color.White)); + _leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(true, Color.White)); + return _leftGroupTreeImageList; + } + + private Bitmap CreateLeftGroupTreeArrowImage(bool expanded, Color color) + { + Size imageSize = _leftGroupTreeImageList.ImageSize; + Bitmap bitmap = new Bitmap(imageSize.Width, imageSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + using (Graphics graphics = Graphics.FromImage(bitmap)) + { + graphics.Clear(Color.Transparent); + graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + int centerX = imageSize.Width / 2; + int centerY = imageSize.Height / 2; + Point[] points; + if (expanded) + { + int width = ScaleLeftGroupTreeMetric(8); + int height = ScaleLeftGroupTreeMetric(6); + points = new[] + { + new Point(centerX - width / 2, centerY - height / 2), + new Point(centerX + width / 2, centerY - height / 2), + new Point(centerX, centerY + height / 2) + }; + } + else + { + int width = ScaleLeftGroupTreeMetric(6); + int height = ScaleLeftGroupTreeMetric(8); + points = new[] + { + new Point(centerX - width / 2, centerY - height / 2), + new Point(centerX - width / 2, centerY + height / 2), + new Point(centerX + width / 2, centerY) + }; + } + + using (SolidBrush arrowBrush = new SolidBrush(color)) + { + graphics.FillPolygon(arrowBrush, points); + } + } + return bitmap; + } + + private int ScaleLeftGroupTreeMetric(int value) + { + float dpi = DpiX > 0 ? DpiX : 96F; + return Math.Max(1, Convert.ToInt32(value * dpi / 96F)); + } + + private void OnLeftGroupTreeListAfterExpandOrCollapse(object sender, NodeEventArgs e) + { + UpdateLeftGroupTreeNodeArrow(e == null ? null : e.Node); + } + + private void UpdateLeftGroupTreeNodeArrow(TreeListNode node) + { + if (node == null || node.Level != 0) return; + + node.ImageIndex = node.Expanded ? 1 : 0; + node.SelectImageIndex = node.Expanded ? 3 : 2; + } + + private void OnLeftGroupTreeListMouseMove(object sender, MouseEventArgs e) + { + TreeList treeList = sender as TreeList; + if (treeList == null) return; + + TreeListHitInfo hitInfo = treeList.CalcHitInfo(e.Location); + TreeListNode hotNode = hitInfo == null ? null : hitInfo.Node; + if (hotNode == _leftGroupHotNode) return; + + _leftGroupHotNode = hotNode; + treeList.FocusedNode = _leftGroupHotNode ?? _leftGroupSelectedNode; + } + + private void OnLeftGroupTreeListMouseLeave(object sender, EventArgs e) + { + TreeList treeList = sender as TreeList; + if (treeList == null) return; + + _leftGroupHotNode = null; + if (_leftGroupSelectedNode != null) + { + treeList.FocusedNode = _leftGroupSelectedNode; + } + } + private Panel GetLeftGroupSeparator() { if (_leftGroupSeparator != null) return _leftGroupSeparator; @@ -823,118 +972,71 @@ namespace Lskj.Main.Control } } - private ImageList GetLeftGroupTreeIcons() - { - if (_leftGroupTreeIcons != null) return _leftGroupTreeIcons; - - _leftGroupTreeIcons = new ImageList(); - _leftGroupTreeIcons.ColorDepth = ColorDepth.Depth32Bit; - _leftGroupTreeIcons.ImageSize = new Size(18, 18); - - string iconPath = PubUtil.MainTreeviewImagePath; - if (Directory.Exists(iconPath)) - { - string[] files = Directory.GetFiles(iconPath, "*.png").OrderBy(n => n).ToArray(); - foreach (string file in files) - { - using (Image image = ImageHelper.ReadImage(file)) - { - if (image != null) - { - _leftGroupTreeIcons.Images.Add(new Bitmap(image)); - } - } - } - } - - if (_leftGroupTreeIcons.Images.Count == 0) - { - _leftGroupTreeIcons.Images.Add(new Bitmap(18, 18)); - } - return _leftGroupTreeIcons; - } private void BindLeftGroupTreeView(DataTable treeTable, string defaultNode) { - TreeView treeView = GetLeftGroupTreeView(); - treeView.BeginUpdate(); - treeView.Nodes.Clear(); - - Dictionary nodeMap = new Dictionary(); - List rows = treeTable.Rows.Cast() - .OrderBy(n => Convert.ToInt32(n["sortno"])) - .ToList(); - int iconCount = GetLeftGroupTreeIcons().Images.Count; - - foreach (DataRow row in rows) + TreeList treeList = GetLeftGroupTreeView(); + treeList.BeginUpdate(); + try { - TreeNode node = new TreeNode(row["nodetext"] + ""); - int iconIndex = 0; - int.TryParse(row["iconindex"] + "", out iconIndex); - iconIndex = Math.Abs(iconIndex) % iconCount; - node.ImageIndex = iconIndex; - node.SelectedImageIndex = iconIndex; - node.Name = row["nodekey"] + ""; - node.Tag = row; - nodeMap[node.Name] = node; - } + treeList.Nodes.Clear(); + _leftGroupHotNode = null; + _leftGroupSelectedNode = null; - foreach (DataRow row in rows) - { - string nodeKey = row["nodekey"] + ""; - string parentKey = row["parentkey"] + ""; - TreeNode node = nodeMap[nodeKey]; - - if (!string.IsNullOrEmpty(parentKey) && nodeMap.ContainsKey(parentKey)) + Dictionary nodeMap = new Dictionary(); + List rows = treeTable.Rows.Cast() + .OrderBy(n => Convert.ToInt32(n["sortno"])) + .ToList(); + foreach (DataRow row in rows) { - nodeMap[parentKey].Nodes.Add(node); + string nodeKey = row["nodekey"] + ""; + string parentKey = row["parentkey"] + ""; + TreeListNode parentNode = !string.IsNullOrEmpty(parentKey) && nodeMap.ContainsKey(parentKey) + ? nodeMap[parentKey] + : null; + TreeListNode node = treeList.AppendNode(new object[] { row["nodetext"] + "" }, parentNode); + node.Tag = row; + if (parentNode == null) + { + UpdateLeftGroupTreeNodeArrow(node); + } + else + { + node.ImageIndex = -1; + node.SelectImageIndex = -1; + } + nodeMap[nodeKey] = node; } - else + + treeList.CollapseAll(); + if (!string.IsNullOrEmpty(defaultNode) && nodeMap.ContainsKey(defaultNode)) { - treeView.Nodes.Add(node); + _leftGroupSelectedNode = nodeMap[defaultNode]; + treeList.FocusedNode = _leftGroupSelectedNode; } } - - treeView.CollapseAll(); - FocusLeftGroupTreeNode(defaultNode); - treeView.EndUpdate(); - } - - private void FocusLeftGroupTreeNode(string nodeKey) - { - if (_leftGroupTreeView == null || string.IsNullOrEmpty(nodeKey)) return; - - TreeNode node = FindLeftGroupTreeNode(_leftGroupTreeView.Nodes, nodeKey); - if (node == null) return; - - _leftGroupTreeView.SelectedNode = node; - } - - private TreeNode FindLeftGroupTreeNode(TreeNodeCollection nodes, string nodeKey) - { - foreach (TreeNode node in nodes) + finally { - if (node.Name.Equals(nodeKey)) return node; - - TreeNode childNode = FindLeftGroupTreeNode(node.Nodes, nodeKey); - if (childNode != null) return childNode; + treeList.EndUpdate(); } - return null; } - private void OnLeftGroupTreeViewNodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + private void OnLeftGroupTreeListMouseClick(object sender, MouseEventArgs e) { try { - TreeView treeView = sender as TreeView; - if (treeView == null || e.Node == null || e.Button != MouseButtons.Left) return; + TreeList treeList = sender as TreeList; + if (treeList == null || e.Button != MouseButtons.Left) return; - treeView.SelectedNode = e.Node; - if (e.Node.Nodes.Count > 0) + TreeListHitInfo hitInfo = treeList.CalcHitInfo(e.Location); + if (hitInfo == null || hitInfo.Node == null) return; + + _leftGroupSelectedNode = hitInfo.Node; + treeList.FocusedNode = _leftGroupSelectedNode; + if (hitInfo.Node.HasChildren && hitInfo.HitInfoType != HitInfoType.Button) { - e.Node.Toggle(); + hitInfo.Node.Expanded = !hitInfo.Node.Expanded; } - - OnLeftGroupTreeRowClick(e.Node.Tag as DataRow); + OnLeftGroupTreeRowClick(hitInfo.Node.Tag as DataRow); } catch (Exception ex) { @@ -950,11 +1052,11 @@ namespace Lskj.Main.Control string expandNode = GetLeftGroupTreeDefaultNode(treeTable, defaultParentMenu); this.pl_center_left.Controls.Clear(); this.pl_center_left.Padding = Padding.Empty; - this.pl_center_left.BackColor = Color.FromArgb(250, 253, 255); + this.pl_center_left.BackColor = LeftGroupTreeBackgroundColor; this.pl_center_main.Padding = Padding.Empty; this.pl_center_main.BackColor = Color.FromArgb(240, 240, 240); SetLeftGroupSeparatorVisible(true); - TreeView treeView = GetLeftGroupTreeView(); + TreeList treeView = GetLeftGroupTreeView(); this.pl_center_left.Controls.Add(treeView); BindLeftGroupTreeView(treeTable, expandNode); diff --git a/插件库/Lskj.Main/Lskj.Main.csproj b/插件库/Lskj.Main/Lskj.Main.csproj index 896046f..ea87bb7 100644 --- a/插件库/Lskj.Main/Lskj.Main.csproj +++ b/插件库/Lskj.Main/Lskj.Main.csproj @@ -73,6 +73,9 @@ False + + False + False ..\..\引用DLL\libzkfpcsharp.dll @@ -584,4 +587,4 @@ --> - \ No newline at end of file +