2 Commits

Author SHA1 Message Date
tdx f1ce6ff658 fix: 优化左侧菜单高度与悬浮状态 2026-08-10 17:12:40 +08:00
tdx f92fd2f1cc feat: 将主页左侧菜单迁移到 TreeList 2026-08-10 17:12:40 +08:00
2 changed files with 259 additions and 114 deletions
+255 -113
View File
@@ -11,6 +11,9 @@ using DevExpress.LookAndFeel;
using DevExpress.XtraEditors; using DevExpress.XtraEditors;
using DevExpress.XtraTab; using DevExpress.XtraTab;
using DevExpress.XtraTab.ViewInfo; using DevExpress.XtraTab.ViewInfo;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using DevExpress.XtraTreeList.Nodes;
using Lskj.Business; using Lskj.Business;
using Lskj.Business.Impl; using Lskj.Business.Impl;
using Lskj.Control; using Lskj.Control;
@@ -129,12 +132,20 @@ namespace Lskj.Main.Control
/// 缓存分组控件 /// 缓存分组控件
/// </summary> /// </summary>
private Dictionary<string, Panel> _groupItems = new Dictionary<string, Panel>(); private Dictionary<string, Panel> _groupItems = new Dictionary<string, Panel>();
private TreeView _leftGroupTreeView; private TreeList _leftGroupTreeView;
private ImageList _leftGroupTreeIcons; private TreeListNode _leftGroupHotNode;
private TreeListNode _leftGroupSelectedNode;
private ImageList _leftGroupTreeImageList;
private Panel _leftGroupSeparator; private Panel _leftGroupSeparator;
private const string LeftGroupTreeNodeTypeMenu = "menu"; private const string LeftGroupTreeNodeTypeMenu = "menu";
private const string LeftGroupTreeNodeTypeGroup = "group"; private const string LeftGroupTreeNodeTypeGroup = "group";
private const int GroupControlTopPadding = 8; 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 LeftGroupTreeHoverColor = Color.FromArgb(79, 101, 132);
private static readonly Color LeftGroupTreeTextColor = Color.FromArgb(235, 255, 255, 255);
private static readonly Color LeftGroupTreeArrowColor = Color.FromArgb(173, 255, 255, 255);
/// <summary> /// <summary>
/// 缓存右上菜单控件 /// 缓存右上菜单控件
/// </summary> /// </summary>
@@ -741,32 +752,198 @@ namespace Lskj.Main.Control
return groupCaption.Length > 2 ? groupCaption.Remove(0, 2) : groupCaption; return groupCaption.Length > 2 ? groupCaption.Remove(0, 2) : groupCaption;
} }
private TreeView GetLeftGroupTreeView() private TreeList GetLeftGroupTreeView()
{ {
if (_leftGroupTreeView != null) return _leftGroupTreeView; if (_leftGroupTreeView != null) return _leftGroupTreeView;
_leftGroupTreeView = new TreeView _leftGroupTreeView = new TreeList
{ {
Dock = DockStyle.Fill, Dock = DockStyle.Fill,
BorderStyle = BorderStyle.None, BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder,
BackColor = Color.FromArgb(250, 253, 255), RowHeight = ScaleLeftGroupTreeMetric(44),
DrawMode = TreeViewDrawMode.Normal, TreeLevelWidth = ScaleLeftGroupTreeMetric(18)
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
}; };
_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.OptionsBehavior.AutoNodeHeight = false;
_leftGroupTreeView.OptionsSelection.EnableAppearanceFocusedCell = false;
_leftGroupTreeView.OptionsSelection.EnableAppearanceFocusedRow = true;
_leftGroupTreeView.OptionsSelection.MultiSelect = 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.Appearance.SelectedRow.BackColor = LeftGroupTreeHoverColor;
_leftGroupTreeView.Appearance.SelectedRow.ForeColor = Color.White;
_leftGroupTreeView.Appearance.SelectedRow.Options.UseBackColor = true;
_leftGroupTreeView.Appearance.SelectedRow.Options.UseForeColor = true;
_leftGroupTreeView.SelectImageList = GetLeftGroupTreeImageList();
_leftGroupTreeView.AfterCollapse += OnLeftGroupTreeListAfterExpandOrCollapse;
_leftGroupTreeView.AfterExpand += OnLeftGroupTreeListAfterExpandOrCollapse;
_leftGroupTreeView.CalcNodeHeight += OnLeftGroupTreeListCalcNodeHeight;
_leftGroupTreeView.MouseClick += OnLeftGroupTreeListMouseClick;
_leftGroupTreeView.MouseLeave += OnLeftGroupTreeListMouseLeave;
_leftGroupTreeView.MouseMove += OnLeftGroupTreeListMouseMove;
return _leftGroupTreeView; 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 OnLeftGroupTreeListCalcNodeHeight(object sender, CalcNodeHeightEventArgs e)
{
if (e == null || e.Node == null) return;
e.NodeHeight = ScaleLeftGroupTreeMetric(e.Node.Level == 0 ? 44 : 36);
}
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;
if (_leftGroupHotNode != null && _leftGroupHotNode != _leftGroupSelectedNode)
{
_leftGroupHotNode.Selected = false;
}
_leftGroupHotNode = hotNode;
if (_leftGroupHotNode != null && _leftGroupHotNode != _leftGroupSelectedNode)
{
_leftGroupHotNode.Selected = true;
}
treeList.Invalidate();
}
private void OnLeftGroupTreeListMouseLeave(object sender, EventArgs e)
{
TreeList treeList = sender as TreeList;
if (treeList == null) return;
if (_leftGroupHotNode != null && _leftGroupHotNode != _leftGroupSelectedNode)
{
_leftGroupHotNode.Selected = false;
}
_leftGroupHotNode = null;
if (_leftGroupSelectedNode != null)
{
_leftGroupSelectedNode.Selected = true;
treeList.FocusedNode = _leftGroupSelectedNode;
}
treeList.Invalidate();
}
private Panel GetLeftGroupSeparator() private Panel GetLeftGroupSeparator()
{ {
if (_leftGroupSeparator != null) return _leftGroupSeparator; if (_leftGroupSeparator != null) return _leftGroupSeparator;
@@ -823,118 +1000,83 @@ 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) private void BindLeftGroupTreeView(DataTable treeTable, string defaultNode)
{ {
TreeView treeView = GetLeftGroupTreeView(); TreeList treeList = GetLeftGroupTreeView();
treeView.BeginUpdate(); treeList.BeginUpdate();
treeView.Nodes.Clear(); try
Dictionary<string, TreeNode> nodeMap = new Dictionary<string, TreeNode>();
List<DataRow> rows = treeTable.Rows.Cast<DataRow>()
.OrderBy(n => Convert.ToInt32(n["sortno"]))
.ToList();
int iconCount = GetLeftGroupTreeIcons().Images.Count;
foreach (DataRow row in rows)
{ {
TreeNode node = new TreeNode(row["nodetext"] + ""); treeList.Nodes.Clear();
int iconIndex = 0; _leftGroupHotNode = null;
int.TryParse(row["iconindex"] + "", out iconIndex); _leftGroupSelectedNode = null;
iconIndex = Math.Abs(iconIndex) % iconCount;
node.ImageIndex = iconIndex;
node.SelectedImageIndex = iconIndex;
node.Name = row["nodekey"] + "";
node.Tag = row;
nodeMap[node.Name] = node;
}
foreach (DataRow row in rows) Dictionary<string, TreeListNode> nodeMap = new Dictionary<string, TreeListNode>();
{ List<DataRow> rows = treeTable.Rows.Cast<DataRow>()
string nodeKey = row["nodekey"] + ""; .OrderBy(n => Convert.ToInt32(n["sortno"]))
string parentKey = row["parentkey"] + ""; .ToList();
TreeNode node = nodeMap[nodeKey]; foreach (DataRow row in rows)
if (!string.IsNullOrEmpty(parentKey) && nodeMap.ContainsKey(parentKey))
{ {
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];
_leftGroupSelectedNode.Selected = true;
treeList.FocusedNode = _leftGroupSelectedNode;
} }
} }
finally
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)
{ {
if (node.Name.Equals(nodeKey)) return node; treeList.EndUpdate();
TreeNode childNode = FindLeftGroupTreeNode(node.Nodes, nodeKey);
if (childNode != null) return childNode;
} }
return null;
} }
private void OnLeftGroupTreeViewNodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) private void OnLeftGroupTreeListMouseClick(object sender, MouseEventArgs e)
{ {
try try
{ {
TreeView treeView = sender as TreeView; TreeList treeList = sender as TreeList;
if (treeView == null || e.Node == null || e.Button != MouseButtons.Left) return; if (treeList == null || e.Button != MouseButtons.Left) return;
treeView.SelectedNode = e.Node; TreeListHitInfo hitInfo = treeList.CalcHitInfo(e.Location);
if (e.Node.Nodes.Count > 0) if (hitInfo == null || hitInfo.Node == null) return;
if (_leftGroupHotNode != null && _leftGroupHotNode != hitInfo.Node)
{ {
e.Node.Toggle(); _leftGroupHotNode.Selected = false;
} }
if (_leftGroupSelectedNode != null && _leftGroupSelectedNode != hitInfo.Node)
OnLeftGroupTreeRowClick(e.Node.Tag as DataRow); {
_leftGroupSelectedNode.Selected = false;
}
_leftGroupSelectedNode = hitInfo.Node;
_leftGroupHotNode = hitInfo.Node;
_leftGroupSelectedNode.Selected = true;
treeList.FocusedNode = _leftGroupSelectedNode;
treeList.Invalidate();
if (hitInfo.Node.HasChildren && hitInfo.HitInfoType != HitInfoType.Button)
{
hitInfo.Node.Expanded = !hitInfo.Node.Expanded;
}
OnLeftGroupTreeRowClick(hitInfo.Node.Tag as DataRow);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -950,11 +1092,11 @@ namespace Lskj.Main.Control
string expandNode = GetLeftGroupTreeDefaultNode(treeTable, defaultParentMenu); string expandNode = GetLeftGroupTreeDefaultNode(treeTable, defaultParentMenu);
this.pl_center_left.Controls.Clear(); this.pl_center_left.Controls.Clear();
this.pl_center_left.Padding = Padding.Empty; 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.Padding = Padding.Empty;
this.pl_center_main.BackColor = Color.FromArgb(240, 240, 240); this.pl_center_main.BackColor = Color.FromArgb(240, 240, 240);
SetLeftGroupSeparatorVisible(true); SetLeftGroupSeparatorVisible(true);
TreeView treeView = GetLeftGroupTreeView(); TreeList treeView = GetLeftGroupTreeView();
this.pl_center_left.Controls.Add(treeView); this.pl_center_left.Controls.Add(treeView);
BindLeftGroupTreeView(treeTable, expandNode); BindLeftGroupTreeView(treeTable, expandNode);
+4 -1
View File
@@ -73,6 +73,9 @@
<Reference Include="DevExpress.XtraGrid.v15.2, Version=15.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL"> <Reference Include="DevExpress.XtraGrid.v15.2, Version=15.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
</Reference> </Reference>
<Reference Include="DevExpress.XtraTreeList.v15.2, Version=15.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="libzkfpcsharp, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="libzkfpcsharp, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\引用DLL\libzkfpcsharp.dll</HintPath> <HintPath>..\..\引用DLL\libzkfpcsharp.dll</HintPath>
@@ -584,4 +587,4 @@
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
--> -->
</Project> </Project>