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("plTop"); Panel headerLeft = FindControl("pl_top_left"); Panel headerCenter = FindControl("pl_top_center"); Panel headerRight = FindControl("pl_top_right"); Panel headerSeparator = FindControl("panel3"); MenuStrip topMenu = FindControl("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("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().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("lueUserName"); if (searchBox != null) { searchBox.Top = 25; searchBox.Height = 24; } PictureBox searchButton = FindControl("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()) { 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().FirstOrDefault(); SelectTopMenu(current); } private void HookDropDownClicks(ToolStripMenuItem root) { foreach (ToolStripMenuItem child in root.DropDownItems.OfType()) { 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("pl_center_main_right"); Panel container = FindControl("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()) { if (MenuItemMatchesCurrent(item, currentName, currentId)) return item; // “更多”中的目录仍属于顶部一级导航,命中子项时返回其顶层父项, // 这样当前目录无论是否被收进下拉框都能保持顶部高亮。 foreach (ToolStripMenuItem child in item.DropDownItems.OfType()) { 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()) 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("menuMain"); if (menu == null) return; foreach (ToolStripMenuItem top in menu.Items.OfType()) { top.ForeColor = top == item ? Color.FromArgb(255, 214, 102) : Color.FromArgb(242, 246, 255); top.Invalidate(); } } private void ResetBrandArea() { Panel brandArea = FindControl("pl_top_left"); if (brandArea != null) brandArea.Width = 176; WinFormsControl oldTitle = FindControl("lblSubTitle"); if (oldTitle != null) oldTitle.Visible = false; } private void StyleSidebar() { Panel sidebar = FindControl("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(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(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("pl_center_left"); foreach (Button button in FindControls