feat: 新增主界面模块功能

This commit is contained in:
cyf
2026-08-28 23:32:47 +08:00
parent b33c847b27
commit 98a119ed25
10 changed files with 942 additions and 30 deletions
@@ -0,0 +1,584 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using DevExpress.XtraTab;
using DevExpress.XtraTreeList;
using Lskj.Business;
using Lskj.Model;
using WinFormsControl = System.Windows.Forms.Control;
namespace Lskj.Main.Control
{
partial class MainPanelControlEx2
{
private static readonly Color HeaderColor = Color.FromArgb(31, 75, 153);
private static readonly Color SidebarColor = Color.FromArgb(39, 45, 81);
private static readonly Color SidebarSelectedColor = Color.FromArgb(52, 142, 216);
private static readonly Color WorkspaceColor = Color.FromArgb(247, 249, 252);
private static readonly Color ShortcutBorderColor = Color.FromArgb(221, 227, 234);
private System.ComponentModel.IContainer components = null;
private MainPanelControlEx _legacyPanel;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
#region
private void InitializeComponent()
{
this._legacyPanel = new Lskj.Main.Control.MainPanelControlEx();
this.SuspendLayout();
//
// _legacyPanel
//
this._legacyPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this._legacyPanel.Location = new System.Drawing.Point(0, 0);
this._legacyPanel.Name = "_legacyPanel";
this._legacyPanel.Size = new System.Drawing.Size(1275, 696);
this._legacyPanel.TabIndex = 0;
//
// MainPanelControlEx2
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this._legacyPanel);
this.Name = "MainPanelControlEx2";
this.Size = new System.Drawing.Size(1275, 696);
this.ResumeLayout(false);
}
#endregion
#region
private void ApplyWpfShellStyle()
{
Panel header = FindControl<Panel>("plTop");
Panel headerLeft = FindControl<Panel>("pl_top_left");
Panel headerCenter = FindControl<Panel>("pl_top_center");
Panel headerRight = FindControl<Panel>("pl_top_right");
Panel headerSeparator = FindControl<Panel>("panel3");
MenuStrip topMenu = FindControl<MenuStrip>("menuMain");
if (header != null) { header.Height = 50; header.BackColor = HeaderColor; }
if (headerLeft != null)
{
headerLeft.Width = 176;
headerLeft.BackColor = HeaderColor;
headerLeft.BackgroundImage = null;
AddBrandVisual(headerLeft);
}
if (headerCenter != null) { headerCenter.BackColor = HeaderColor; headerCenter.Padding = new Padding(0, 9, 0, 0); }
// 右上角继续使用旧版控件、按钮和位置,仅统一顶部背景色。
if (headerRight != null) { headerRight.BackColor = HeaderColor; headerRight.BackgroundImage = null; }
// 旧版 Logo 与菜单之间有 19px 的装饰分隔面板;WPF 顶部栏是连续布局,
// 保留该控件会在两块蓝色之间形成突兀的深色竖条。
if (headerSeparator != null)
{
headerSeparator.Width = 0;
headerSeparator.BackColor = HeaderColor;
headerSeparator.BackgroundImage = null;
}
StyleSearchControls();
if (topMenu != null) StyleTopNavigation(topMenu);
StyleMainTabs();
StyleSidebar();
StyleWorkspaceAndShortcuts();
RememberStyledNavigation();
}
private void AddBrandVisual(WinFormsControl host)
{
if (host.Controls.Find("wpfBrandVisual", false).Length > 0) return;
PictureBox logo = new PictureBox
{
Name = "wpfBrandVisual", BackColor = Color.Transparent,
Size = new Size(150, 32), Location = new Point(12, 9),
SizeMode = PictureBoxSizeMode.Zoom
};
Image image = LoadWpfHeaderLogo();
if (image != null)
{
logo.Image = image;
host.Controls.Add(logo);
logo.BringToFront();
}
WinFormsControl oldTitle = host.Controls.Find("lblSubTitle", true).FirstOrDefault();
if (oldTitle != null) oldTitle.Visible = false;
}
private static Image LoadWpfHeaderLogo()
{
// 客户部署时只从程序目录下的 Images\Main 查找 Logo
// 文件不存在则不显示图片,不再回退到开发机或 SVG 资源。
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images", "Main", "logoNew.png");
try
{
if (!File.Exists(path)) return null;
// 克隆后释放文件句柄,避免程序运行期间锁定更新包中的图片。
using (Image source = Image.FromFile(path)) return new Bitmap(source);
}
catch (Exception)
{
return null;
}
}
private void StyleMainTabs()
{
XtraTabControl tabs = FindControl<XtraTabControl>("tabMain");
if (tabs == null) return;
// 旧版 DevExpress 皮肤会把相邻页签绘成深浅不一的灰块,
// 在新版蓝色顶部栏下显得突兀;统一为 WPF 主界面的浅灰页签带,
// 当前页签保持白色,边界与左侧导航自然衔接。
Color tabStrip = Color.FromArgb(245, 247, 251);
Color tabHover = Color.FromArgb(232, 239, 249);
Color tabBorder = Color.FromArgb(214, 222, 233);
tabs.PaintStyleName = "Flat";
tabs.HeaderLocation = DevExpress.XtraTab.TabHeaderLocation.Top;
tabs.HeaderAutoFill = DevExpress.Utils.DefaultBoolean.False;
tabs.TabPageWidth = 0;
tabs.BackColor = tabStrip;
tabs.Appearance.BackColor = tabStrip;
tabs.Appearance.Options.UseBackColor = true;
ConfigureTabAppearance(tabs.AppearancePage.Header, Color.White, Color.FromArgb(74, 86, 105), tabBorder);
ConfigureTabAppearance(tabs.AppearancePage.HeaderActive, Color.White, Color.FromArgb(31, 119, 201), tabBorder);
ConfigureTabAppearance(tabs.AppearancePage.HeaderHotTracked, tabHover, Color.FromArgb(31, 119, 201), tabBorder);
ConfigureTabAppearance(tabs.AppearancePage.HeaderDisabled, tabStrip, Color.FromArgb(160, 169, 182), tabBorder);
tabs.AppearancePage.Header.Font = new Font("微软雅黑", 9F);
tabs.AppearancePage.HeaderActive.Font = tabs.AppearancePage.Header.Font;
tabs.AppearancePage.HeaderHotTracked.Font = tabs.AppearancePage.Header.Font;
tabs.AppearancePage.HeaderDisabled.Font = tabs.AppearancePage.Header.Font;
// 功能导航页签要与左侧 176px 目录栏严格对齐。DevExpress 旧版
// 页签宽度按文本自适应,因此用不可见的全角空格补足首个页签宽度,
// 其它页签仍保持按内容自适应,并通过边框清晰分隔。
XtraTabPage first = tabs.TabPages.Cast<XtraTabPage>().FirstOrDefault(p => p.Name == "xtpFirst");
if (first != null) first.Text = "功能导航" + new string('\u3000', 10);
}
private static void ConfigureTabAppearance(DevExpress.Utils.AppearanceObject appearance, Color backColor, Color foreColor, Color borderColor)
{
appearance.BackColor = backColor;
appearance.ForeColor = foreColor;
appearance.BorderColor = borderColor;
appearance.Options.UseBackColor = true;
appearance.Options.UseForeColor = true;
appearance.Options.UseBorderColor = true;
}
private void StyleSearchControls()
{
// 旧版搜索框和按钮原本位于 y=27、高度 25/26,顶部栏改为 50px 后
// 底部会被裁掉约 2~3px。仅上移 2px 并缩短 1~2px,保留足够的
// 输入高度和按钮点击区域,避免控件显得过小。
WinFormsControl searchBox = FindControl<WinFormsControl>("lueUserName");
if (searchBox != null)
{
searchBox.Top = 25;
searchBox.Height = 24;
}
PictureBox searchButton = FindControl<PictureBox>("pic_search");
if (searchButton != null)
{
searchButton.Top = 25;
searchButton.Height = 24;
}
}
private void StyleTopNavigation(MenuStrip menu)
{
menu.Renderer = new WpfMenuRenderer(HeaderColor, () =>
{
// 每次绘制都重新读取当前导航,支持旧版双击或其它入口切换目录。
return FindCurrentTopMenu(menu) ?? _selectedTopMenu;
});
menu.BackColor = HeaderColor;
menu.ForeColor = Color.FromArgb(242, 246, 255);
menu.Font = new Font("微软雅黑", 10F);
menu.Dock = DockStyle.Fill;
menu.Location = Point.Empty;
menu.Padding = new Padding(4, 0, 4, 0);
menu.AutoSize = false;
menu.Height = 32;
foreach (ToolStripMenuItem item in menu.Items.OfType<ToolStripMenuItem>())
{
item.BackColor = Color.Transparent;
item.ForeColor = Color.FromArgb(242, 246, 255);
item.Font = menu.Font;
item.Padding = new Padding(8, 0, 8, 0);
item.Margin = Padding.Empty;
item.AutoSize = true;
item.Click -= TopMenuItem_Click;
item.Click += TopMenuItem_Click;
item.DropDownOpened -= TopMenuDropDownOpened;
item.DropDownOpened += TopMenuDropDownOpened;
item.DropDownClosed -= TopMenuDropDownClosed;
item.DropDownClosed += TopMenuDropDownClosed;
HookDropDownClicks(item);
}
// 当前功能导航是唯一权威状态。旧版在双击切换目录时会更新
// ERPInfo.Instance.SubSysName;这里每次重新套用样式都优先按该值查找,
// 避免上一次点击留下的菜单项一直保持高亮。
ToolStripMenuItem current = FindCurrentTopMenu(menu);
if (current == null)
current = _selectedTopMenu;
if (current == null || !menu.Items.Contains(current))
current = null;
if (current == null)
current = menu.Items.OfType<ToolStripMenuItem>().FirstOrDefault();
SelectTopMenu(current);
}
private void HookDropDownClicks(ToolStripMenuItem root)
{
foreach (ToolStripMenuItem child in root.DropDownItems.OfType<ToolStripMenuItem>())
{
child.Click -= LegacyDropDownItem_Click;
child.Click += LegacyDropDownItem_Click;
HookDropDownClicks(child);
}
}
private void LegacyDropDownItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem item = sender as ToolStripMenuItem;
if (item == null) return;
// 普通二级模块点击不会改变当前功能导航,不要因此重做右侧布局。
if (!IsNavigationChangedSinceLastStyle()) return;
_selectedTopMenu = null;
RequestApplyWpfShellStyle();
}
private void TopMenuDropDownOpened(object sender, EventArgs e)
{
// 下拉菜单展开及二级目录移动期间,旧版会触发父容器重绘;
// 暂停右侧快捷通道的 WM_PAINT,避免看到中间清空状态。
SetShortcutRedraw(false);
}
private void TopMenuDropDownClosed(object sender, EventArgs e)
{
// 若目录切换已经排队,保持暂停到统一样式刷新完成,避免先显示中间状态。
if (_styleUpdatePending) return;
SetShortcutRedraw(true);
}
private void SetShortcutRedraw(bool enabled)
{
_shortcutRedrawSuppressed = !enabled;
Panel right = FindControl<Panel>("pl_center_main_right");
Panel container = FindControl<Panel>("pl_center_main_right_container");
SendRedrawMessage(right, enabled);
if (container != right) SendRedrawMessage(container, enabled);
if (enabled && !_styleUpdatePending)
{
if (right != null) right.Invalidate(true);
if (container != null) container.Invalidate(true);
}
}
private static void SendRedrawMessage(WinFormsControl control, bool enabled)
{
if (control == null || !control.IsHandleCreated) return;
SendMessage(control.Handle, 0x000B, new IntPtr(enabled ? 1 : 0), IntPtr.Zero);
}
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private static ToolStripMenuItem FindCurrentTopMenu(MenuStrip menu)
{
// 设计器中旧控件尚未加载业务数据,不能触发 ERPInfo 的运行时初始化。
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) return null;
string currentName = (ERPInfo.Instance.SubSysName ?? string.Empty).Trim();
string currentId = (ERPInfo.Instance.SubSysId ?? string.Empty).Trim();
if (string.IsNullOrWhiteSpace(currentName) && string.IsNullOrWhiteSpace(currentId)) return null;
foreach (ToolStripMenuItem item in menu.Items.OfType<ToolStripMenuItem>())
{
if (MenuItemMatchesCurrent(item, currentName, currentId)) return item;
// “更多”中的目录仍属于顶部一级导航,命中子项时返回其顶层父项,
// 这样当前目录无论是否被收进下拉框都能保持顶部高亮。
foreach (ToolStripMenuItem child in item.DropDownItems.OfType<ToolStripMenuItem>())
{
if (MenuItemTreeMatchesCurrent(child, currentName, currentId)) return item;
}
}
return null;
}
private static bool MenuItemTreeMatchesCurrent(ToolStripMenuItem item, string currentName, string currentId)
{
if (MenuItemMatchesCurrent(item, currentName, currentId)) return true;
foreach (ToolStripMenuItem child in item.DropDownItems.OfType<ToolStripMenuItem>())
if (MenuItemTreeMatchesCurrent(child, currentName, currentId)) return true;
return false;
}
private static bool MenuItemMatchesCurrent(ToolStripMenuItem item, string currentName, string currentId)
{
if (!string.IsNullOrWhiteSpace(currentName)
&& string.Equals((item.Text ?? string.Empty).Trim(), currentName, StringComparison.OrdinalIgnoreCase))
return true;
DataRow row = item.Tag as DataRow;
string itemId = row != null && row.Table.Columns.Contains("subsysid")
? row["subsysid"] + ""
: item.Tag + "";
return !string.IsNullOrWhiteSpace(currentId)
&& string.Equals(itemId, currentId, StringComparison.OrdinalIgnoreCase);
}
private void SelectTopMenu(ToolStripMenuItem item)
{
if (item == null) return;
_selectedTopMenu = item;
MenuStrip menu = FindControl<MenuStrip>("menuMain");
if (menu == null) return;
foreach (ToolStripMenuItem top in menu.Items.OfType<ToolStripMenuItem>())
{
top.ForeColor = top == item ? Color.FromArgb(255, 214, 102) : Color.FromArgb(242, 246, 255);
top.Invalidate();
}
}
private void ResetBrandArea()
{
Panel brandArea = FindControl<Panel>("pl_top_left");
if (brandArea != null) brandArea.Width = 176;
WinFormsControl oldTitle = FindControl<WinFormsControl>("lblSubTitle");
if (oldTitle != null) oldTitle.Visible = false;
}
private void StyleSidebar()
{
Panel sidebar = FindControl<Panel>("pl_center_left");
if (sidebar == null) return;
// 新版侧栏对应旧程序的 MainLeftShowMode=1(分组树菜单)配置。
bool useGroupedSidebar = IsGroupedSidebarMode();
sidebar.Width = 176; sidebar.Padding = Padding.Empty; sidebar.BackColor = SidebarColor; sidebar.AutoScroll = true;
if (!useGroupedSidebar) return;
foreach (TreeList tree in FindControls<TreeList>(sidebar))
{
tree.Dock = DockStyle.Fill; tree.RowHeight = 44; tree.BackColor = SidebarColor;
tree.Appearance.Empty.BackColor = SidebarColor; tree.Appearance.Empty.Options.UseBackColor = true;
tree.Appearance.Row.BackColor = SidebarColor; tree.Appearance.Row.ForeColor = Color.FromArgb(235, 255, 255, 255);
tree.Appearance.Row.Font = new Font("微软雅黑", 10F); tree.Appearance.Row.Options.UseBackColor = true;
tree.Appearance.Row.Options.UseForeColor = true; tree.Appearance.Row.Options.UseFont = true;
tree.Appearance.FocusedRow.BackColor = SidebarSelectedColor; tree.Appearance.FocusedRow.ForeColor = Color.White;
tree.Appearance.FocusedRow.Options.UseBackColor = true; tree.Appearance.FocusedRow.Options.UseForeColor = true;
tree.Appearance.HideSelectionRow.BackColor = SidebarSelectedColor; tree.Appearance.HideSelectionRow.ForeColor = Color.White;
tree.Appearance.HideSelectionRow.Options.UseBackColor = true; tree.Appearance.HideSelectionRow.Options.UseForeColor = true;
tree.OptionsView.ShowColumns = false; tree.OptionsView.ShowIndicator = false; tree.OptionsView.ShowHorzLines = false; tree.OptionsView.ShowVertLines = false;
}
foreach (MenuBar menuBar in FindControls<MenuBar>(sidebar))
{
Button button = menuBar.GetButton(); menuBar.BackColor = SidebarColor; menuBar.Height = 44;
button.Dock = DockStyle.Fill; button.BackColor = SidebarColor; button.BackgroundImage = null;
button.FlatStyle = FlatStyle.Flat; button.FlatAppearance.BorderSize = 0;
button.FlatAppearance.MouseOverBackColor = Color.FromArgb(74, 80, 108); button.FlatAppearance.MouseDownBackColor = SidebarSelectedColor;
button.ForeColor = Color.FromArgb(235, 255, 255, 255); button.Font = new Font("微软雅黑", 10F);
button.TextAlign = ContentAlignment.MiddleLeft; button.Padding = new Padding(20, 0, 12, 0);
button.Click -= SidebarButton_Click;
button.Click += SidebarButton_Click;
}
}
private void SidebarButton_Click(object sender, EventArgs e)
{
Button selected = sender as Button;
if (selected == null) return;
Panel sidebar = FindControl<Panel>("pl_center_left");
foreach (Button button in FindControls<Button>(sidebar))
{
button.BackgroundImage = null;
button.BackColor = button == selected ? SidebarSelectedColor : SidebarColor;
}
}
private void StyleWorkspaceAndShortcuts()
{
Panel center = FindControl<Panel>("pl_center_main"); if (center != null) center.BackColor = WorkspaceColor;
Panel middle = FindControl<Panel>("pl_center_main_middle");
if (middle != null) { middle.BackColor = Color.White; middle.Padding = new Padding(20, 18, 20, 22); }
Panel right = FindControl<Panel>("pl_center_main_right");
Panel rightContainer = FindControl<Panel>("pl_center_main_right_container");
EnableDoubleBuffer(right);
EnableDoubleBuffer(rightContainer);
if (rightContainer != null) { rightContainer.BackColor = Color.White; rightContainer.Padding = Padding.Empty; }
if (right != null) { right.BackColor = Color.White; right.Padding = new Padding(12); }
SplitContainer split = FindControl<SplitContainer>("splitMainControl");
if (split != null)
{
split.BackColor = WorkspaceColor;
split.SplitterWidth = 1;
if (split.Width > 177) split.SplitterDistance = Math.Max(176, split.Width - 240);
}
StyleShortcutSection("panel6", "lblShortcutset", "其它功能");
StyleShortcutSection("pl_center_main_bottom_right", "lblReportcutset", "最近使用");
foreach (SimpleControl shortcut in FindControls<SimpleControl>(this)) StyleShortcut(shortcut);
foreach (TableLayoutPanel table in FindControls<TableLayoutPanel>(rightContainer)) EnableDoubleBuffer(table);
ResizeShortcutSections();
}
private static void EnableDoubleBuffer(WinFormsControl control)
{
if (control == null) return;
try
{
PropertyInfo property = typeof(WinFormsControl).GetProperty(
"DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
if (property != null && property.CanWrite) property.SetValue(control, true, null);
}
catch (Exception)
{
// 某些旧版控件不允许修改 DoubleBuffered,不影响正常显示。
}
}
private void ResizeShortcutSections()
{
Panel first = FindControl<Panel>("pl_center_main_bottom_left");
Panel firstContent = FindControl<Panel>("pl_center_main_bottom_right_main");
Panel second = FindControl<Panel>("pl_center_main_bottom_right");
Panel secondContent = FindControl<Panel>("pl_center_main_bottom_left_main");
if (firstContent != null)
{
EnableDoubleBuffer(firstContent);
firstContent.BackColor = Color.White;
firstContent.Padding = new Padding(0, 4, 0, 0);
TableLayoutPanel table = firstContent.Controls.OfType<TableLayoutPanel>().FirstOrDefault();
if (table != null && first != null) first.Height = Math.Max(84, table.Height + 46);
}
if (secondContent != null)
{
EnableDoubleBuffer(secondContent);
secondContent.BackColor = Color.White;
secondContent.Padding = new Padding(0, 4, 0, 0);
TableLayoutPanel table = secondContent.Controls.OfType<TableLayoutPanel>().FirstOrDefault();
if (table != null && second != null) second.Height = Math.Max(84, table.Height + 46);
}
}
private void StyleShortcutSection(string panelName, string titleName, string title)
{
Panel panel = FindControl<Panel>(panelName); Label label = FindControl<Label>(titleName);
if (panel != null) { panel.BackColor = Color.White; panel.Height = 42; panel.Padding = new Padding(4, 0, 0, 0); }
if (label != null) { label.Text = title; label.Tag = title; label.BackColor = Color.White; label.ForeColor = Color.FromArgb(36, 136, 223); label.Font = new Font("微软雅黑", 10F, FontStyle.Bold); label.TextAlign = ContentAlignment.MiddleLeft; label.Padding = new Padding(4, 0, 0, 0); }
}
private void StyleShortcut(SimpleControl shortcut)
{
shortcut.Height = 56; shortcut.Margin = Padding.Empty; shortcut.BackColor = Color.White; shortcut.Padding = new Padding(4, 1, 0, 1); shortcut.Cursor = Cursors.Hand;
shortcut.PicBox.Width = 34; shortcut.PicBox.BackColor = Color.White; shortcut.PicBox.BackgroundImageLayout = ImageLayout.Center;
shortcut.Label.Font = new Font("微软雅黑", 9F); shortcut.Label.ForeColor = Color.FromArgb(55, 68, 84); shortcut.Label.BackColor = Color.White;
shortcut.Label.TextAlign = ContentAlignment.MiddleLeft; shortcut.Label.Padding = new Padding(7, 0, 18, 0); shortcut.Label.AutoEllipsis = true;
DataRow row = shortcut.Label.Tag as DataRow;
if (row != null)
{
string caption = row.Table.Columns.Contains("menucaption") ? row["menucaption"] + "" : shortcut.Label.Text;
string group = row.Table.Columns.Contains("groupcaption") ? row["groupcaption"] + "" : string.Empty;
if (string.IsNullOrWhiteSpace(group)) group = "常用功能";
shortcut.Label.Text = caption + Environment.NewLine + group;
}
TableLayoutPanel table = shortcut.Parent as TableLayoutPanel;
if (table != null)
{
table.AutoSize = true;
table.AutoSizeMode = AutoSizeMode.GrowAndShrink;
table.Dock = DockStyle.Top;
int rowIndex = table.GetRow(shortcut);
if (rowIndex >= 0 && rowIndex < table.RowStyles.Count)
{
table.RowStyles[rowIndex].SizeType = SizeType.Absolute;
table.RowStyles[rowIndex].Height = shortcut.Height;
}
table.BackColor = Color.White;
}
shortcut.Paint -= Shortcut_Paint; shortcut.Paint += Shortcut_Paint;
}
private void Shortcut_Paint(object sender, PaintEventArgs e)
{
SimpleControl shortcut = sender as SimpleControl; if (shortcut == null) return;
using (Pen pen = new Pen(ShortcutBorderColor)) e.Graphics.DrawLine(pen, 0, shortcut.Height - 1, shortcut.Width, shortcut.Height - 1);
using (Pen pen = new Pen(Color.FromArgb(150, 137, 164, 197), 1.5F))
{
int x = Math.Max(0, shortcut.Width - 9), y = shortcut.Height / 2;
e.Graphics.DrawLine(pen, x - 3, y - 4, x + 1, y); e.Graphics.DrawLine(pen, x + 1, y, x - 3, y + 4);
}
}
private T FindControl<T>(string name) where T : WinFormsControl { return Controls.Find(name, true).OfType<T>().FirstOrDefault(); }
private static IEnumerable<T> FindControls<T>(WinFormsControl root) where T : WinFormsControl
{
if (root == null) yield break;
foreach (WinFormsControl child in root.Controls)
{
T typed = child as T; if (typed != null) yield return typed;
foreach (T nested in FindControls<T>(child)) yield return nested;
}
}
private sealed class WpfMenuRenderer : ToolStripProfessionalRenderer
{
private readonly Color _header;
private readonly Func<ToolStripMenuItem> _activeMenuProvider;
public WpfMenuRenderer(Color header, Func<ToolStripMenuItem> activeMenuProvider)
{
_header = header;
_activeMenuProvider = activeMenuProvider;
}
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
// 只改变顶层 MenuStrip 的背景;下拉菜单交回 WinForms 默认渲染。
if (e.ToolStrip is MenuStrip) e.Graphics.Clear(_header);
else base.OnRenderToolStripBackground(e);
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
ToolStripMenuItem item = e.Item as ToolStripMenuItem; if (item == null) return;
// 下拉框恢复旧版默认效果,不使用 WPF 顶部导航的高亮绘制。
if (!(e.ToolStrip is MenuStrip))
{
base.OnRenderMenuItemBackground(e);
return;
}
// Selected/Pressed 只表示鼠标状态,鼠标移开后会被 WinForms 清除。
// 高亮必须跟随当前功能导航(ERPInfo.SubSysName)持续显示。
string currentName = LicenseManager.UsageMode == LicenseUsageMode.Designtime
? string.Empty
: (ERPInfo.Instance.SubSysName ?? string.Empty).Trim();
bool current = _activeMenuProvider != null && item == _activeMenuProvider();
if (!current)
current = !string.IsNullOrWhiteSpace(currentName)
&& string.Equals((item.Text ?? string.Empty).Trim(), currentName, StringComparison.OrdinalIgnoreCase);
bool hover = item.Selected || item.Pressed;
bool drawBackground = current || hover;
// 当前目录使用黄色文字;鼠标悬浮只显示背景,不改变文字颜色和下划线。
item.ForeColor = current
? Color.FromArgb(255, 214, 102)
: Color.FromArgb(242, 246, 255);
if (!drawBackground) return;
Rectangle r = new Rectangle(Point.Empty, item.Size);
using (Brush brush = new SolidBrush(current
? Color.FromArgb(49, 90, 166)
: Color.FromArgb(42, 88, 164))) e.Graphics.FillRectangle(brush, r);
if (current)
{
using (Brush brush = new SolidBrush(Color.FromArgb(255, 214, 102)))
e.Graphics.FillRectangle(brush, 2, r.Bottom - 3, Math.Max(1, r.Width - 4), 2);
}
}
}
#endregion
}
}