feat: 完善个人设置及表格功能
This commit is contained in:
+305
-62
@@ -5,6 +5,7 @@ using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -12,6 +13,7 @@ using System.Windows.Forms;
|
||||
using DevExpress.XtraTab;
|
||||
using DevExpress.XtraTreeList;
|
||||
using Lskj.Business;
|
||||
using Lskj.Main;
|
||||
using Lskj.Model;
|
||||
using WinFormsControl = System.Windows.Forms.Control;
|
||||
|
||||
@@ -26,10 +28,15 @@ namespace Lskj.Main.Control
|
||||
private static readonly Color ShortcutBorderColor = Color.FromArgb(221, 227, 234);
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
private MainPanelControlEx _legacyPanel;
|
||||
private MainTabsNativeWindow _mainTabsNativeWindow;
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null)) components.Dispose();
|
||||
if (disposing)
|
||||
{
|
||||
if (_mainTabsNativeWindow != null) _mainTabsNativeWindow.Dispose();
|
||||
if (components != null) components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
@@ -62,35 +69,37 @@ namespace Lskj.Main.Control
|
||||
#region 新版主界面外观
|
||||
private void ApplyWpfShellStyle()
|
||||
{
|
||||
MainAppearanceSettings appearance = MainAppearanceSettingsStore.Load();
|
||||
Color headerColor = GetConfiguredColor(appearance.TopMenuBackground, HeaderColor);
|
||||
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 (header != null) { header.Height = 50; header.BackColor = headerColor; }
|
||||
if (headerLeft != null)
|
||||
{
|
||||
headerLeft.Width = 176;
|
||||
headerLeft.BackColor = HeaderColor;
|
||||
headerLeft.BackColor = headerColor;
|
||||
headerLeft.BackgroundImage = null;
|
||||
AddBrandVisual(headerLeft);
|
||||
}
|
||||
if (headerCenter != null) { headerCenter.BackColor = HeaderColor; headerCenter.Padding = new Padding(0, 9, 0, 0); }
|
||||
if (headerCenter != null) { headerCenter.BackColor = headerColor; headerCenter.Padding = new Padding(0, 9, 0, 0); }
|
||||
// 右上角继续使用旧版控件、按钮和位置,仅统一顶部背景色。
|
||||
if (headerRight != null) { headerRight.BackColor = HeaderColor; headerRight.BackgroundImage = null; }
|
||||
if (headerRight != null) { headerRight.BackColor = headerColor; headerRight.BackgroundImage = null; }
|
||||
// 旧版 Logo 与菜单之间有 19px 的装饰分隔面板;WPF 顶部栏是连续布局,
|
||||
// 保留该控件会在两块蓝色之间形成突兀的深色竖条。
|
||||
if (headerSeparator != null)
|
||||
{
|
||||
headerSeparator.Width = 0;
|
||||
headerSeparator.BackColor = HeaderColor;
|
||||
headerSeparator.BackColor = headerColor;
|
||||
headerSeparator.BackgroundImage = null;
|
||||
}
|
||||
StyleSearchControls();
|
||||
if (topMenu != null) StyleTopNavigation(topMenu);
|
||||
if (topMenu != null) StyleTopNavigation(topMenu, headerColor, appearance.TopMenuFontSize);
|
||||
StyleMainTabs();
|
||||
StyleSidebar();
|
||||
StyleSidebar(appearance);
|
||||
StyleWorkspaceAndShortcuts();
|
||||
RememberStyledNavigation();
|
||||
}
|
||||
@@ -147,8 +156,13 @@ namespace Lskj.Main.Control
|
||||
Color tabHover = Color.White;
|
||||
Color tabBorder = Color.FromArgb(199, 211, 228);
|
||||
tabs.PaintStyleName = "Flat";
|
||||
tabs.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
|
||||
tabs.BorderStylePage = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
|
||||
tabs.HeaderLocation = DevExpress.XtraTab.TabHeaderLocation.Top;
|
||||
tabs.HeaderAutoFill = DevExpress.Utils.DefaultBoolean.False;
|
||||
tabs.MultiLine = DevExpress.Utils.DefaultBoolean.False;
|
||||
tabs.ShowHeaderFocus = DevExpress.Utils.DefaultBoolean.False;
|
||||
tabs.MaxTabPageWidth = 220;
|
||||
tabs.TabPageWidth = 0;
|
||||
tabs.BackColor = tabStrip;
|
||||
tabs.Appearance.BackColor = tabStrip;
|
||||
@@ -162,18 +176,69 @@ namespace Lskj.Main.Control
|
||||
tabs.AppearancePage.HeaderHotTracked.Font = tabs.AppearancePage.Header.Font;
|
||||
tabs.AppearancePage.HeaderDisabled.Font = tabs.AppearancePage.Header.Font;
|
||||
tabs.Paint -= MainTabs_Paint;
|
||||
tabs.Paint += MainTabs_Paint;
|
||||
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
|
||||
tabs.Paint += MainTabs_Paint;
|
||||
else
|
||||
AttachMainTabsNativePainter(tabs);
|
||||
tabs.ControlAdded -= MainTabs_ControlAdded;
|
||||
tabs.ControlAdded += MainTabs_ControlAdded;
|
||||
|
||||
// 功能导航页签要与左侧 176px 目录栏严格对齐。DevExpress 旧版
|
||||
// 页签宽度按文本自适应,因此用不可见的全角空格补足首个页签宽度,
|
||||
// 其它页签仍保持按内容自适应,并通过边框清晰分隔。
|
||||
// WPF 首页页签固定 176px,其余页签为 92~220px。直接使用每页的
|
||||
// TabPageWidth,避免用全角空格补宽后在不同字体/DPI 下发生偏移。
|
||||
XtraTabPage first = tabs.TabPages.Cast<XtraTabPage>().FirstOrDefault(p => p.Name == "xtpFirst");
|
||||
if (first != null) first.Text = "功能导航" + new string('\u3000', 10);
|
||||
if (first != null) first.Text = "功能导航";
|
||||
ApplyWpfTabWidths(tabs);
|
||||
}
|
||||
|
||||
private void MainTabs_ControlAdded(object sender, ControlEventArgs e)
|
||||
{
|
||||
XtraTabControl tabs = sender as XtraTabControl;
|
||||
if (tabs == null || !(e.Control is XtraTabPage)) return;
|
||||
ApplyWpfTabWidths(tabs);
|
||||
tabs.Invalidate();
|
||||
}
|
||||
|
||||
private void AttachMainTabsNativePainter(XtraTabControl tabs)
|
||||
{
|
||||
if (_mainTabsNativeWindow == null)
|
||||
_mainTabsNativeWindow = new MainTabsNativeWindow();
|
||||
_mainTabsNativeWindow.Attach(tabs);
|
||||
}
|
||||
|
||||
private static void ApplyWpfTabWidths(XtraTabControl tabs)
|
||||
{
|
||||
Font font = tabs.AppearancePage.Header.Font ?? tabs.Font;
|
||||
foreach (XtraTabPage page in tabs.TabPages)
|
||||
{
|
||||
if (page.Name == "xtpFirst")
|
||||
{
|
||||
page.TabPageWidth = 167;
|
||||
continue;
|
||||
}
|
||||
if (page.Name == "xtpWorktop" || page.Name == "xtpDesktop")
|
||||
{
|
||||
page.TabPageWidth = 83;
|
||||
continue;
|
||||
}
|
||||
|
||||
int textWidth = TextRenderer.MeasureText(page.Text ?? string.Empty, font,
|
||||
Size.Empty, TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width;
|
||||
// WPF:左右文字留白 20px,关闭按钮及间隔 20px。
|
||||
// DevExpress 15.2 会在 TabPageWidth 外再增加 9px 头部外框;
|
||||
// 预先扣除该值,使最终可见宽度与 WPF 的 92~220px 一致。
|
||||
int visualWidth = Math.Max(92, Math.Min(220, textWidth + 40));
|
||||
page.TabPageWidth = Math.Max(1, visualWidth - 9);
|
||||
}
|
||||
}
|
||||
|
||||
private void MainTabs_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
XtraTabControl tabs = sender as XtraTabControl;
|
||||
if (tabs != null) DrawMainTabs(tabs, e.Graphics);
|
||||
}
|
||||
|
||||
private static void DrawMainTabs(XtraTabControl tabs, Graphics graphics)
|
||||
{
|
||||
DevExpress.XtraTab.IXtraTab tabInterface = tabs as DevExpress.XtraTab.IXtraTab;
|
||||
DevExpress.XtraTab.ViewInfo.BaseTabControlViewInfo viewInfo =
|
||||
tabInterface == null ? null : tabInterface.ViewInfo;
|
||||
@@ -181,47 +246,85 @@ namespace Lskj.Main.Control
|
||||
|
||||
Rectangle header = viewInfo.HeaderInfo.Bounds;
|
||||
if (header.Width <= 0 || header.Height <= 0) return;
|
||||
Color stripColor = Color.FromArgb(243, 245, 248);
|
||||
Color borderColor = Color.FromArgb(199, 211, 228);
|
||||
int lastRight = header.Left;
|
||||
Color stripColor = Color.FromArgb(243, 245, 248); // #F3F5F8
|
||||
Color normalColor = Color.FromArgb(248, 250, 252); // #F8FAFC
|
||||
Color normalBorder = Color.FromArgb(199, 211, 228); // #C7D3E4
|
||||
Color selectedBorder = Color.FromArgb(199, 211, 228); // #C7D3E4
|
||||
Color normalText = Color.FromArgb(79, 95, 120); // #4F5F78
|
||||
Color selectedText = Color.FromArgb(7, 88, 255); // #0758FF
|
||||
int dividerY = viewInfo.PageClientBounds.Top > 0
|
||||
? viewInfo.PageClientBounds.Top - 1
|
||||
: header.Bottom - 1;
|
||||
dividerY = Math.Max(header.Top, Math.Min(tabs.ClientSize.Height - 1, dividerY));
|
||||
|
||||
// 先覆盖整个页签带,彻底消除 DevExpress 当前皮肤留下的渐变、圆角和焦点边框。
|
||||
using (Brush stripBrush = new SolidBrush(stripColor))
|
||||
graphics.FillRectangle(stripBrush, 0, header.Top,
|
||||
tabs.ClientSize.Width, Math.Max(1, dividerY - header.Top + 1));
|
||||
|
||||
foreach (DevExpress.XtraTab.ViewInfo.BaseTabPageViewInfo page in viewInfo.HeaderInfo.VisiblePages)
|
||||
{
|
||||
Rectangle bounds = page.Bounds;
|
||||
if (bounds.Width <= 0 || bounds.Height <= 0) continue;
|
||||
lastRight = Math.Max(lastRight, bounds.Right);
|
||||
XtraTabPage tabPage = page.Page as XtraTabPage;
|
||||
bool home = tabPage != null && tabPage.Name == "xtpFirst";
|
||||
bool selected = page.Page == viewInfo.SelectedTabPage;
|
||||
bool hover = page.IsHotState && !selected;
|
||||
Color backColor = home
|
||||
? (hover ? Color.White : stripColor)
|
||||
: (selected || hover ? Color.White : normalColor);
|
||||
Color borderColor = selected ? selectedBorder : normalBorder;
|
||||
|
||||
// 相邻页签首尾紧贴,不再保留页签栏底色间隔;每个页签仍然
|
||||
// 单独绘制完整矩形边框,因此无间距时也能保持清晰边界。
|
||||
int surfaceLeft = bounds.Left;
|
||||
int surfaceRight = bounds.Right;
|
||||
int surfaceTop = header.Top + 1;
|
||||
int surfaceBottom = Math.Max(surfaceTop, dividerY - 1);
|
||||
Rectangle surface = Rectangle.FromLTRB(surfaceLeft, surfaceTop,
|
||||
Math.Max(surfaceLeft + 1, surfaceRight), surfaceBottom + 1);
|
||||
using (Brush brush = new SolidBrush(backColor))
|
||||
graphics.FillRectangle(brush, surface);
|
||||
using (Pen pen = new Pen(borderColor))
|
||||
{
|
||||
// 明确绘制页签左右分隔及顶部边线,避免 DevExpress 不同皮肤
|
||||
// 忽略 Appearance.BorderColor 后多个白色页签连成一片。
|
||||
e.Graphics.DrawLine(pen, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom - 1);
|
||||
e.Graphics.DrawLine(pen, bounds.Right - 1, bounds.Top, bounds.Right - 1, bounds.Bottom - 1);
|
||||
e.Graphics.DrawLine(pen, bounds.Left, bounds.Top, bounds.Right - 1, bounds.Top);
|
||||
// 为每个页签单独绘制完整矩形。WPF 通过相邻边框、页签间距
|
||||
// 和底部 Divider 共同形成矩形;WinForms 直接绘制四边可避免
|
||||
// DevExpress 皮肤把多个未选中页签合并成一个整体。
|
||||
graphics.DrawRectangle(pen, surface.Left, surface.Top,
|
||||
Math.Max(0, surface.Width - 1), Math.Max(0, surface.Height - 1));
|
||||
}
|
||||
|
||||
Rectangle closeBounds = page.ControlBox;
|
||||
int textLeft = surface.Left + (home ? 34 : 12);
|
||||
int textRight = closeBounds.Width > 0 ? closeBounds.Left - 6 : surface.Right - 8;
|
||||
Rectangle textBounds = new Rectangle(textLeft, surface.Top,
|
||||
Math.Max(1, textRight - textLeft), surface.Height);
|
||||
Color textColor = !home && selected ? selectedText : normalText;
|
||||
TextRenderer.DrawText(graphics, page.Page.Text, tabs.AppearancePage.Header.Font,
|
||||
textBounds, textColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter |
|
||||
TextFormatFlags.SingleLine | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix);
|
||||
|
||||
if (closeBounds.Width > 0 && closeBounds.Height > 0)
|
||||
{
|
||||
bool closeHot = closeBounds.Contains(tabs.PointToClient(WinFormsControl.MousePosition));
|
||||
if (closeHot)
|
||||
{
|
||||
using (Brush brush = new SolidBrush(Color.FromArgb(234, 242, 251)))
|
||||
graphics.FillRectangle(brush, closeBounds);
|
||||
}
|
||||
int cx = closeBounds.Left + closeBounds.Width / 2;
|
||||
int cy = closeBounds.Top + closeBounds.Height / 2;
|
||||
using (Pen pen = new Pen(Color.FromArgb(127, 143, 163)))
|
||||
{
|
||||
graphics.DrawLine(pen, cx - 3, cy - 3, cx + 3, cy + 3);
|
||||
graphics.DrawLine(pen, cx + 3, cy - 3, cx - 3, cy + 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WPF 页签后方是浅灰色页签带,而不是与内容区相同的纯白色。
|
||||
Rectangle buttons = viewInfo.HeaderInfo.ButtonsBounds;
|
||||
int emptyRight = buttons.Width > 0 ? buttons.Left : header.Right;
|
||||
if (lastRight < emptyRight)
|
||||
{
|
||||
using (Brush brush = new SolidBrush(stripColor))
|
||||
e.Graphics.FillRectangle(brush, lastRight, header.Top, emptyRight - lastRight, header.Height);
|
||||
}
|
||||
// WPF 在整个 WorkspaceTabStrip 底部单独覆盖一条 1px 的 #C7D3E4
|
||||
// 分隔线。不能沿用 HeaderInfo.Bounds.Bottom:旧版 DevExpress 中该位置
|
||||
// 仍可能属于页签头内部,线条会与页签背景混在一起。这里按内容区顶部定位,
|
||||
// 横跨控件全宽,并增加一条极浅下沿,使 WinForms 在不同 DPI 下仍有边界感。
|
||||
Rectangle pageClient = tabs.PageClientBounds;
|
||||
int dividerY = pageClient.Top > 0 ? pageClient.Top - 1 : header.Bottom - 1;
|
||||
dividerY = Math.Max(0, Math.Min(tabs.ClientSize.Height - 1, dividerY));
|
||||
using (Pen pen = new Pen(borderColor))
|
||||
e.Graphics.DrawLine(pen, 0, dividerY, tabs.ClientSize.Width - 1, dividerY);
|
||||
if (dividerY + 1 < tabs.ClientSize.Height)
|
||||
{
|
||||
using (Pen pen = new Pen(Color.FromArgb(237, 242, 247)))
|
||||
e.Graphics.DrawLine(pen, 0, dividerY + 1, tabs.ClientSize.Width - 1, dividerY + 1);
|
||||
}
|
||||
// 与 WPF WorkspaceTabStripDivider 一致,最上层覆盖 1px #C7D3E4。
|
||||
using (Pen pen = new Pen(selectedBorder))
|
||||
graphics.DrawLine(pen, 0, dividerY, tabs.ClientSize.Width - 1, dividerY);
|
||||
}
|
||||
|
||||
private static void ConfigureTabAppearance(DevExpress.Utils.AppearanceObject appearance, Color backColor, Color foreColor, Color borderColor)
|
||||
@@ -253,16 +356,16 @@ namespace Lskj.Main.Control
|
||||
}
|
||||
}
|
||||
|
||||
private void StyleTopNavigation(MenuStrip menu)
|
||||
private void StyleTopNavigation(MenuStrip menu, Color headerColor, int topFontSize)
|
||||
{
|
||||
menu.Renderer = new WpfMenuRenderer(HeaderColor, () =>
|
||||
menu.Renderer = new WpfMenuRenderer(headerColor, () =>
|
||||
{
|
||||
// 每次绘制都重新读取当前导航,支持旧版双击或其它入口切换目录。
|
||||
return FindCurrentTopMenu(menu) ?? _selectedTopMenu;
|
||||
});
|
||||
menu.BackColor = HeaderColor;
|
||||
menu.BackColor = headerColor;
|
||||
menu.ForeColor = Color.FromArgb(242, 246, 255);
|
||||
menu.Font = new Font("微软雅黑", 10F);
|
||||
menu.Font = new Font("微软雅黑", GetConfiguredFontSize(topFontSize, 9F));
|
||||
menu.Dock = DockStyle.Fill;
|
||||
menu.Location = Point.Empty;
|
||||
menu.Padding = new Padding(4, 0, 4, 0);
|
||||
@@ -416,34 +519,38 @@ namespace Lskj.Main.Control
|
||||
if (oldTitle != null) oldTitle.Visible = false;
|
||||
}
|
||||
|
||||
private void StyleSidebar()
|
||||
private void StyleSidebar(MainAppearanceSettings appearance)
|
||||
{
|
||||
Panel sidebar = FindControl<Panel>("pl_center_left");
|
||||
if (sidebar == null) return;
|
||||
Color sidebarColor = GetConfiguredColor(appearance.SidebarBackground, SidebarColor);
|
||||
Color sidebarSelectedColor = GetConfiguredColor(appearance.SidebarSelectedBackground, SidebarSelectedColor);
|
||||
Color sidebarHoverColor = GetHoverColor(sidebarColor);
|
||||
float sidebarFontSize = GetConfiguredFontSize(appearance.LeftMenuFontSize, 12F);
|
||||
// 新版侧栏对应旧程序的 MainLeftShowMode=1(分组树菜单)配置。
|
||||
bool useGroupedSidebar = IsGroupedSidebarMode();
|
||||
sidebar.Width = 176; sidebar.Padding = Padding.Empty; sidebar.BackColor = SidebarColor; sidebar.AutoScroll = true;
|
||||
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.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("微软雅黑", sidebarFontSize); 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.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.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 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.FlatAppearance.MouseOverBackColor = sidebarHoverColor; button.FlatAppearance.MouseDownBackColor = sidebarSelectedColor;
|
||||
button.ForeColor = Color.FromArgb(235, 255, 255, 255); button.Font = new Font("微软雅黑", sidebarFontSize);
|
||||
button.TextAlign = ContentAlignment.MiddleLeft; button.Padding = new Padding(20, 0, 12, 0);
|
||||
button.Click -= SidebarButton_Click;
|
||||
button.Click += SidebarButton_Click;
|
||||
@@ -454,11 +561,14 @@ namespace Lskj.Main.Control
|
||||
{
|
||||
Button selected = sender as Button;
|
||||
if (selected == null) return;
|
||||
MainAppearanceSettings appearance = MainAppearanceSettingsStore.Load();
|
||||
Color sidebarColor = GetConfiguredColor(appearance.SidebarBackground, SidebarColor);
|
||||
Color sidebarSelectedColor = GetConfiguredColor(appearance.SidebarSelectedBackground, SidebarSelectedColor);
|
||||
Panel sidebar = FindControl<Panel>("pl_center_left");
|
||||
foreach (Button button in FindControls<Button>(sidebar))
|
||||
{
|
||||
button.BackgroundImage = null;
|
||||
button.BackColor = button == selected ? SidebarSelectedColor : SidebarColor;
|
||||
button.BackColor = button == selected ? sidebarSelectedColor : sidebarColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,6 +811,63 @@ namespace Lskj.Main.Control
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSystemInfoText(string memberName)
|
||||
{
|
||||
try
|
||||
{
|
||||
object systemInfo = SystemInfo.Instance;
|
||||
Type type = systemInfo.GetType();
|
||||
FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public);
|
||||
if (field != null) return Convert.ToString(field.GetValue(systemInfo), CultureInfo.InvariantCulture);
|
||||
PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public);
|
||||
if (property != null) return Convert.ToString(property.GetValue(systemInfo, null), CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 配置成员不存在或读取失败时继续使用默认选中颜色。
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static Color GetConfiguredColor(string configuredValue, Color defaultColor)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(configuredValue)) return defaultColor;
|
||||
string hex = configuredValue.Trim();
|
||||
if (hex.StartsWith("#", StringComparison.Ordinal)) hex = hex.Substring(1);
|
||||
|
||||
uint value;
|
||||
if (!uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value))
|
||||
return defaultColor;
|
||||
if (hex.Length == 6)
|
||||
return Color.FromArgb((int)((value >> 16) & 0xFF), (int)((value >> 8) & 0xFF), (int)(value & 0xFF));
|
||||
if (hex.Length == 8)
|
||||
return Color.FromArgb((int)((value >> 24) & 0xFF), (int)((value >> 16) & 0xFF),
|
||||
(int)((value >> 8) & 0xFF), (int)(value & 0xFF));
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
private static float GetConfiguredFontSize(object configuredValue, float defaultSize)
|
||||
{
|
||||
// SystemInfo 在数据库字段为空时写入 0;Font 不接受 0,因此正数才是有效配置。
|
||||
float configuredSize;
|
||||
string text = Convert.ToString(configuredValue, CultureInfo.InvariantCulture);
|
||||
return float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out configuredSize)
|
||||
&& configuredSize > 0
|
||||
? configuredSize
|
||||
: defaultSize;
|
||||
}
|
||||
|
||||
private static Color GetHoverColor(Color baseColor)
|
||||
{
|
||||
// 悬浮色跟随配置背景轻微提亮,避免自定义为橙色、红色等颜色后
|
||||
// 仍出现旧版固定蓝灰色块。
|
||||
const int percent = 8;
|
||||
return Color.FromArgb(baseColor.A,
|
||||
baseColor.R + (255 - baseColor.R) * percent / 100,
|
||||
baseColor.G + (255 - baseColor.G) * percent / 100,
|
||||
baseColor.B + (255 - baseColor.B) * percent / 100);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -713,13 +880,89 @@ namespace Lskj.Main.Control
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DevExpress 15.2 在触发普通 Paint 事件后还会继续绘制页签头,导致自定义
|
||||
/// 矩形被覆盖。NativeWindow 在 WM_PAINT 完成后绘制,既保留原页签的命中
|
||||
/// 测试、切换和关闭逻辑,又能保证最终显示的是 WPF 风格页签。
|
||||
/// </summary>
|
||||
private sealed class MainTabsNativeWindow : NativeWindow, IDisposable
|
||||
{
|
||||
private const int WmPaint = 0x000F;
|
||||
private XtraTabControl _tabs;
|
||||
private bool _drawing;
|
||||
|
||||
public void Attach(XtraTabControl tabs)
|
||||
{
|
||||
if (_tabs == tabs)
|
||||
{
|
||||
if (Handle == IntPtr.Zero && tabs != null && tabs.IsHandleCreated)
|
||||
AssignHandle(tabs.Handle);
|
||||
return;
|
||||
}
|
||||
|
||||
Detach();
|
||||
_tabs = tabs;
|
||||
if (_tabs == null) return;
|
||||
_tabs.HandleCreated += Tabs_HandleCreated;
|
||||
_tabs.HandleDestroyed += Tabs_HandleDestroyed;
|
||||
if (_tabs.IsHandleCreated) AssignHandle(_tabs.Handle);
|
||||
}
|
||||
|
||||
private void Tabs_HandleCreated(object sender, EventArgs e)
|
||||
{
|
||||
if (Handle == IntPtr.Zero && _tabs != null && _tabs.IsHandleCreated)
|
||||
AssignHandle(_tabs.Handle);
|
||||
}
|
||||
|
||||
private void Tabs_HandleDestroyed(object sender, EventArgs e)
|
||||
{
|
||||
if (Handle != IntPtr.Zero) ReleaseHandle();
|
||||
}
|
||||
|
||||
protected override void WndProc(ref Message m)
|
||||
{
|
||||
base.WndProc(ref m);
|
||||
if (m.Msg != WmPaint || _drawing || _tabs == null ||
|
||||
_tabs.IsDisposed || !_tabs.IsHandleCreated) return;
|
||||
|
||||
_drawing = true;
|
||||
try
|
||||
{
|
||||
using (Graphics graphics = Graphics.FromHwnd(_tabs.Handle))
|
||||
DrawMainTabs(_tabs, graphics);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_drawing = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Detach()
|
||||
{
|
||||
if (_tabs != null)
|
||||
{
|
||||
_tabs.HandleCreated -= Tabs_HandleCreated;
|
||||
_tabs.HandleDestroyed -= Tabs_HandleDestroyed;
|
||||
}
|
||||
if (Handle != IntPtr.Zero) ReleaseHandle();
|
||||
_tabs = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Detach();
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class WpfMenuRenderer : ToolStripProfessionalRenderer
|
||||
{
|
||||
private readonly Color _header;
|
||||
private readonly Color _hover;
|
||||
private readonly Func<ToolStripMenuItem> _activeMenuProvider;
|
||||
public WpfMenuRenderer(Color header, Func<ToolStripMenuItem> activeMenuProvider)
|
||||
{
|
||||
_header = header;
|
||||
_hover = GetHoverColor(header);
|
||||
_activeMenuProvider = activeMenuProvider;
|
||||
}
|
||||
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
|
||||
@@ -755,7 +998,7 @@ namespace Lskj.Main.Control
|
||||
Rectangle r = new Rectangle(Point.Empty, item.Size);
|
||||
if (hover)
|
||||
{
|
||||
using (Brush brush = new SolidBrush(Color.FromArgb(42, 88, 164)))
|
||||
using (Brush brush = new SolidBrush(_hover))
|
||||
e.Graphics.FillRectangle(brush, r);
|
||||
}
|
||||
if (current)
|
||||
|
||||
Reference in New Issue
Block a user