using Lskj.Control; using System; using System.ComponentModel; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Windows.Forms; namespace Lskj.Main { public partial class FrmPersonalSetting : BaseForm { private MainAppearanceSettings _settings; public FrmPersonalSetting() { InitializeComponent(); BuildDesignerControls(); // 设计器只需要静态控件,不访问本地配置文件或运行时状态。 if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) return; _settings = MainAppearanceSettingsStore.Load(); LoadSettingsToControls(); } private void LoadSettingsToControls() { txtTopColor.Text = _settings.TopMenuBackground; txtLeftColor.Text = _settings.SidebarBackground; txtLeftSelectColor.Text = _settings.SidebarSelectedBackground; numTopFont.Value = Clamp(_settings.TopMenuFontSize, numTopFont.Minimum, numTopFont.Maximum); numLeftFont.Value = Clamp(_settings.LeftMenuFontSize, numLeftFont.Minimum, numLeftFont.Maximum); // An empty value means "use the program default". Keep the editor // visually empty while MainPanelControlEx2 still uses its fallback. if (!_settings.TopMenuFontConfigured) numTopFont.Text = string.Empty; if (!_settings.LeftMenuFontConfigured) numLeftFont.Text = string.Empty; UpdateColorPreview(txtTopColor, pnlTopPreview); UpdateColorPreview(txtLeftColor, pnlLeftPreview); UpdateColorPreview(txtLeftSelectColor, pnlLeftSelectPreview); } private void SaveSettings() { int ignoredTopFont; int ignoredLeftFont; MainAppearanceSettingsStore.Save(new MainAppearanceSettings { TopMenuBackground = MainAppearanceSettingsStore.NormalizeColor(txtTopColor.Text, _settings.TopMenuBackground), SidebarBackground = MainAppearanceSettingsStore.NormalizeColor(txtLeftColor.Text, _settings.SidebarBackground), SidebarSelectedBackground = MainAppearanceSettingsStore.NormalizeColor(txtLeftSelectColor.Text, _settings.SidebarSelectedBackground), TopMenuFontSize = ParseFontEditorValue(numTopFont, MainAppearanceSettingsStore.DefaultTopMenuFontSize), LeftMenuFontSize = ParseFontEditorValue(numLeftFont, MainAppearanceSettingsStore.DefaultLeftMenuFontSize), TopMenuFontConfigured = TryParseFontEditorValue(numTopFont, out ignoredTopFont), LeftMenuFontConfigured = TryParseFontEditorValue(numLeftFont, out ignoredLeftFont) }); DialogResult = DialogResult.OK; Close(); } private void ChooseColor(TextBox textBox, Panel preview) { Color current = MainAppearanceSettingsStore.ParseColor(textBox.Text, Color.White); using (ColorDialog dialog = new ColorDialog { Color = current, FullOpen = true }) { if (dialog.ShowDialog(this) != DialogResult.OK) return; textBox.Text = MainAppearanceSettingsStore.FormatColor(dialog.Color); UpdateColorPreview(textBox, preview); } } private static void UpdateColorPreview(TextBox textBox, Panel preview) { if (preview != null) preview.BackColor = MainAppearanceSettingsStore.ParseColor(textBox.Text, Color.White); } private static decimal Clamp(int value, decimal min, decimal max) { return Math.Min(max, Math.Max(min, value)); } private static bool TryParseFontEditorValue(NumericUpDown editor, out int value) { value = 0; int parsed; if (!int.TryParse((editor == null ? string.Empty : editor.Text ?? string.Empty).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out parsed)) return false; if (parsed < MainAppearanceSettingsStore.MinimumFontSize || parsed > MainAppearanceSettingsStore.MaximumFontSize) return false; value = parsed; return true; } private static int ParseFontEditorValue(NumericUpDown editor, int fallback) { int value; return TryParseFontEditorValue(editor, out value) ? value : fallback; } private void txtColor_TextChanged(object sender, EventArgs e) { if (sender == txtTopColor) UpdateColorPreview(txtTopColor, pnlTopPreview); else if (sender == txtLeftColor) UpdateColorPreview(txtLeftColor, pnlLeftPreview); else if (sender == txtLeftSelectColor) UpdateColorPreview(txtLeftSelectColor, pnlLeftSelectPreview); } private void btnTopColor_Click(object sender, EventArgs e) { ChooseColor(txtTopColor, pnlTopPreview); } private void btnLeftColor_Click(object sender, EventArgs e) { ChooseColor(txtLeftColor, pnlLeftPreview); } private void btnLeftSelectColor_Click(object sender, EventArgs e) { ChooseColor(txtLeftSelectColor, pnlLeftSelectPreview); } private void btnSave_Click(object sender, EventArgs e) { SaveSettings(); } private void btnCancel_Click(object sender, EventArgs e) { DialogResult = DialogResult.Cancel; Close(); } private void btnReset_Click(object sender, EventArgs e) { _settings = MainAppearanceSettingsStore.Defaults(); LoadSettingsToControls(); } private void navAppearance_Click(object sender, EventArgs e) { ShowPage(pnlAppearance); } private void navFonts_Click(object sender, EventArgs e) { ShowPage(pnlFonts); } } internal sealed class MainAppearanceSettings { public string TopMenuBackground; public string SidebarBackground; public string SidebarSelectedBackground; public int TopMenuFontSize; public int LeftMenuFontSize; public bool TopMenuFontConfigured; public bool LeftMenuFontConfigured; } internal static class MainAppearanceSettingsStore { internal const int DefaultTopMenuFontSize = 9; internal const int DefaultLeftMenuFontSize = 12; internal const int MinimumFontSize = 8; internal const int MaximumFontSize = 24; // WinForms uses a separate file so changing the WPF shell settings does not // unexpectedly alter the transitional WinForms main panel. private const string FileName = "WinFromShellAppearance.ini"; private const string TopColorKey = "TopMenuBackground="; private const string LeftColorKey = "SidebarBackground="; private const string LeftSelectedColorKey = "SidebarSelectedBackground="; private const string TopFontKey = "TopMenuFontSize="; private const string LeftFontKey = "LeftMenuFontSize="; public static MainAppearanceSettings Defaults() { return new MainAppearanceSettings { TopMenuBackground = "#1F4B99", SidebarBackground = "#272D51", SidebarSelectedBackground = "#348ED8", TopMenuFontSize = DefaultTopMenuFontSize, LeftMenuFontSize = DefaultLeftMenuFontSize, TopMenuFontConfigured = false, LeftMenuFontConfigured = false }; } public static MainAppearanceSettings Load() { MainAppearanceSettings result = Defaults(); try { string path = GetPath(); if (!File.Exists(path)) { // Create the WinForms-specific file on first run so the active // values are visible and editable from the Debug\Config folder. Save(result); return result; } foreach (string raw in File.ReadAllLines(path)) { string line = (raw ?? string.Empty).Trim(); if (line.StartsWith(TopColorKey, StringComparison.OrdinalIgnoreCase)) result.TopMenuBackground = NormalizeColor(line.Substring(TopColorKey.Length), result.TopMenuBackground); else if (line.StartsWith(LeftColorKey, StringComparison.OrdinalIgnoreCase)) result.SidebarBackground = NormalizeColor(line.Substring(LeftColorKey.Length), result.SidebarBackground); else if (line.StartsWith(LeftSelectedColorKey, StringComparison.OrdinalIgnoreCase)) result.SidebarSelectedBackground = NormalizeColor(line.Substring(LeftSelectedColorKey.Length), result.SidebarSelectedBackground); else if (line.StartsWith(TopFontKey, StringComparison.OrdinalIgnoreCase)) { int value; if (TryParseFont(line.Substring(TopFontKey.Length), out value)) { result.TopMenuFontSize = value; result.TopMenuFontConfigured = true; } } else if (line.StartsWith(LeftFontKey, StringComparison.OrdinalIgnoreCase)) { int value; if (TryParseFont(line.Substring(LeftFontKey.Length), out value)) { result.LeftMenuFontSize = value; result.LeftMenuFontConfigured = true; } } } } catch (Exception) { } return result; } public static void Save(MainAppearanceSettings settings) { if (settings == null) return; string path = GetPath(); string[] oldLines = new string[0]; try { if (File.Exists(path)) oldLines = File.ReadAllLines(path); } catch (Exception) { } string[] replacements = { TopColorKey + NormalizeColor(settings.TopMenuBackground, "#1F4B99"), LeftColorKey + NormalizeColor(settings.SidebarBackground, "#272D51"), LeftSelectedColorKey + NormalizeColor(settings.SidebarSelectedBackground, "#348ED8"), TopFontKey + (settings.TopMenuFontConfigured ? settings.TopMenuFontSize.ToString(CultureInfo.InvariantCulture) : string.Empty), LeftFontKey + (settings.LeftMenuFontConfigured ? settings.LeftMenuFontSize.ToString(CultureInfo.InvariantCulture) : string.Empty) }; string[] keys = { TopColorKey, LeftColorKey, LeftSelectedColorKey, TopFontKey, LeftFontKey }; var output = oldLines.ToList(); for (int i = 0; i < keys.Length; i++) { int index = output.FindIndex(x => (x ?? string.Empty).Trim().StartsWith(keys[i], StringComparison.OrdinalIgnoreCase)); if (index >= 0) output[index] = replacements[i]; else output.Add(replacements[i]); } try { string dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); File.WriteAllLines(path, output.ToArray()); } catch (Exception) { } } public static string NormalizeColor(string value, string fallback) { return FormatColor(ParseColor(value, ParseColor(fallback, Color.Black))); } public static Color ParseColor(string value, Color fallback) { if (string.IsNullOrWhiteSpace(value)) return fallback; string text = value.Trim(); if (!text.StartsWith("#", StringComparison.Ordinal) || text.Length != 7) return fallback; byte r, g, b; if (!byte.TryParse(text.Substring(1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out r) || !byte.TryParse(text.Substring(3, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out g) || !byte.TryParse(text.Substring(5, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out b)) return fallback; return Color.FromArgb(r, g, b); } public static string FormatColor(Color color) { return string.Format(CultureInfo.InvariantCulture, "#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B); } private static bool TryParseFont(string value, out int result) { result = 0; return int.TryParse((value ?? string.Empty).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result) && result >= MinimumFontSize && result <= MaximumFontSize; } private static string GetPath() { return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config", FileName); } } }