Files
community/Ink Canvas/Windows/SettingsViews/SettingsWindow.xaml.cs
T
PrefacedCorg 4f015fb155 refactor(设置): 重构设置窗口为独立窗口并移除旧设置面板
移除旧的内置设置面板及相关代码,将设置功能迁移至独立的设置窗口
优化设置窗口的主题同步功能,调整自动化页面布局
2026-04-27 09:40:24 +08:00

522 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Ink_Canvas.Windows.SettingsViews.Pages;
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Navigation;
using System.Windows.Media;
using MessageBox = System.Windows.MessageBox;
using Screen = System.Windows.Forms.Screen;
namespace Ink_Canvas.Windows.SettingsViews
{
public partial class SettingsWindow : Window
{
private Dictionary<string, Type> _pageTypes;
private readonly Dictionary<string, object> _pages = new Dictionary<string, object>();
private readonly Dictionary<string, Ink_Canvas.Plugins.PluginInfo> _pluginPages = new Dictionary<string, Ink_Canvas.Plugins.PluginInfo>();
// 保存窗口原始位置和大小
private double _originalLeft;
private double _originalTop;
private double _originalWidth;
private double _originalHeight;
// 标记窗口是否曾经最大化过
private bool _wasMaximized = false;
private bool _isNavigating = false;
public SettingsWindow()
{
InitializeComponent();
ApplyCurrentTheme();
// 初始化内置页面映射
_pageTypes = new Dictionary<string, Type>
{
{ "HomePage", typeof(HomePage) },
{ "StartupPage", typeof(StartupPage) },
{ "PrivacyPage", typeof(PrivacyPage) },
{ "WindowPage", typeof(WindowPage) },
{ "AppearancePage", typeof(AppearancePage) },
{ "UpdatePage", typeof(UpdatePage) },
{ "ExperimentalPage", typeof(ExperimentalPage) },
{ "AdvancedPage", typeof(AdvancedPage) },
{ "AutomationPage", typeof(AutomationPage) },
{ "PowerPointPage", typeof(PowerPointPage) },
{ "RandomDrawPage", typeof(RandomDrawPage) },
{ "CanvasPage", typeof(CanvasPage) },
{ "InkRecognitionPage", typeof(InkRecognitionPage) },
{ "DebugPage", typeof(IconographyPage) },
{ "AboutPage", typeof(AboutPage) },
{ "Settings", typeof(SettingsPage) },
{ "PluginPage", typeof(PluginPage) },
{ "PluginSettingsPage", typeof(PluginSettingsPage) }
};
// 默认选中首页
if (NavigationViewControl.MenuItems.Count > 0)
{
NavigateToPage("HomePage");
NavigationViewControl.SelectedItem = NavigationViewControl.MenuItems[0];
NavigationViewControl.Header = "首页";
}
UpdateAppTitleBarMargin();
// 窗口生命周期事件
this.Loaded += (sender, e) =>
{
SetMaxSizeAndCenter();
RegisterDpiChangedListener();
LoadPluginSettingsPages();
};
this.Closed += (sender, e) =>
{
UnregisterDpiChangedListener();
_pages.Clear();
_pageTypes.Clear();
};
// 修复触摸屏操作后鼠标指针消失的问题
this.TouchUp += (s, e) => ShowCursor(true);
this.MouseEnter += (s, e) => ShowCursor(true);
this.Activated += (s, e) => ShowCursor(true);
// 窗口状态改变时调整大小限制
this.StateChanged += (sender, e) =>
{
if (this.WindowState == WindowState.Maximized)
{
_originalLeft = this.Left;
_originalTop = this.Top;
_originalWidth = this.Width;
_originalHeight = this.Height;
_wasMaximized = true;
this.MaxWidth = double.PositiveInfinity;
this.MaxHeight = double.PositiveInfinity;
}
else if (this.WindowState == WindowState.Normal && _wasMaximized)
{
this.Left = _originalLeft;
this.Top = _originalTop;
this.Width = _originalWidth;
this.Height = _originalHeight;
_wasMaximized = false;
SetMaxSizeOnly();
}
else if (this.WindowState == WindowState.Normal)
{
SetMaxSizeOnly();
}
UpdateAppTitleBarMargin();
};
this.SizeChanged += (sender, e) =>
{
if (NavigationViewControl.DisplayMode == NavigationViewDisplayMode.Minimal)
{
UpdateAppTitleBarMargin();
}
};
}
public void RefreshTheme()
{
ApplyCurrentTheme();
}
private void ApplyCurrentTheme()
{
try
{
int themeIndex = Helpers.SettingsManager.Settings.Appearance.Theme;
var elementTheme = themeIndex switch
{
0 => iNKORE.UI.WPF.Modern.ElementTheme.Light,
1 => iNKORE.UI.WPF.Modern.ElementTheme.Dark,
_ => iNKORE.UI.WPF.Modern.ElementTheme.Default,
};
iNKORE.UI.WPF.Modern.ThemeManager.SetRequestedTheme(this, elementTheme);
}
catch { }
}
#region
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int ShowCursor(bool bShow);
#endregion
#region DPI/
/// <summary>
/// 获取当前窗口所在屏幕的工作区尺寸(DIP单位)
/// </summary>
private void GetWorkAreaSize(out double workAreaWidthDip, out double workAreaHeightDip, out double screenLeftDip, out double screenTopDip)
{
// 1. 获取窗口当前所在屏幕
var windowHandle = new WindowInteropHelper(this).Handle;
var currentScreen = Screen.FromHandle(windowHandle);
var workingArea = currentScreen.WorkingArea;
var screenBounds = currentScreen.Bounds;
// 2. 获取当前窗口的DPI缩放因子
var source = PresentationSource.FromVisual(this);
double dpiScaleX = 1.0;
double dpiScaleY = 1.0;
if (source?.CompositionTarget != null)
{
dpiScaleX = source.CompositionTarget.TransformToDevice.M11;
dpiScaleY = source.CompositionTarget.TransformToDevice.M22;
}
// 3. 物理像素 → WPF设备无关像素(DIP)转换
workAreaWidthDip = workingArea.Width / dpiScaleX;
workAreaHeightDip = workingArea.Height / dpiScaleY;
screenLeftDip = screenBounds.Left / dpiScaleX;
screenTopDip = screenBounds.Top / dpiScaleY;
}
private void SetMaxSizeAndCenter()
{
if (!this.IsLoaded) return;
GetWorkAreaSize(out double workAreaWidthDip, out double workAreaHeightDip, out double screenLeftDip, out double screenTopDip);
// 设置窗口最大尺寸
this.MaxWidth = workAreaWidthDip;
this.MaxHeight = workAreaHeightDip;
// 窗口在当前屏幕居中(解决副屏居中跑偏问题)
this.Left = screenLeftDip + (workAreaWidthDip - this.ActualWidth) / 2;
this.Top = screenTopDip + (workAreaHeightDip - this.ActualHeight) / 2;
}
private void SetMaxSizeOnly()
{
if (!this.IsLoaded) return;
GetWorkAreaSize(out double workAreaWidthDip, out double workAreaHeightDip, out _, out _);
// 只设置窗口最大尺寸,不改变窗口位置
this.MaxWidth = workAreaWidthDip;
this.MaxHeight = workAreaHeightDip;
}
#region DPI/
private HwndSource _hwndSource;
private void RegisterDpiChangedListener()
{
_hwndSource = PresentationSource.FromVisual(this) as HwndSource;
_hwndSource?.AddHook(DpiChangedWndProc);
}
private void UnregisterDpiChangedListener()
{
_hwndSource?.RemoveHook(DpiChangedWndProc);
_hwndSource = null;
}
private IntPtr DpiChangedWndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_DPICHANGED = 0x02E0;
// 系统DPI/缩放变化时自动重新计算窗口参数
if (msg == WM_DPICHANGED)
{
SetMaxSizeAndCenter();
handled = true;
}
return IntPtr.Zero;
}
#endregion
#endregion
#region
private void OnNavigationViewSelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
if (_isNavigating)
{
return;
}
if (args.IsSettingsSelected)
{
NavigateToPage("Settings");
NavigationViewControl.Header = "设置";
return;
}
// 处理普通导航项
if (args.SelectedItem is NavigationViewItem selectedItem)
{
string tag = selectedItem.Tag as string;
if (!string.IsNullOrEmpty(tag) && _pageTypes.ContainsKey(tag))
{
// 如果是插件设置页面,设置当前插件
if (_pluginPages.TryGetValue(tag, out var plugin))
{
PluginSettingsPage.CurrentPlugin = plugin;
}
// 避免重复导航到当前页面
if (rootFrame.SourcePageType != _pageTypes[tag])
{
NavigateToPage(tag);
}
NavigationViewControl.Header = selectedItem.Content;
}
}
}
public void NavigateToPage(string pageTag)
{
if (!_pageTypes.TryGetValue(pageTag, out Type pageType)) return;
try
{
_isNavigating = true;
if (!_pages.TryGetValue(pageTag, out var cachedPage))
{
cachedPage = Activator.CreateInstance(pageType);
_pages.Add(pageTag, cachedPage);
}
rootFrame.Navigate(cachedPage.GetType(), cachedPage);
}
catch (Exception ex)
{
MessageBox.Show($"导航到页面时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
_isNavigating = false;
}
}
private void OnNavigationViewBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
{
if (rootFrame.CanGoBack) rootFrame.GoBack();
}
private void OnRootFrameNavigated(object sender, NavigationEventArgs e)
{
if (_isNavigating)
{
return;
}
Type currentPageType = rootFrame.SourcePageType;
// 处理设置项的选中状态
if (currentPageType == typeof(SettingsPage))
{
NavigationViewControl.SelectedItem = NavigationViewControl.SettingsItem;
NavigationViewControl.Header = "设置";
return;
}
// 同步其他页面的选中状态
foreach (var kvp in _pageTypes)
{
if (kvp.Value == currentPageType)
{
var targetItem = FindNavigationViewItemByTag(kvp.Key);
if (targetItem != null && NavigationViewControl.SelectedItem != targetItem)
{
NavigationViewControl.SelectedItem = targetItem;
NavigationViewControl.Header = targetItem.Content;
}
break;
}
}
}
private void NavigationViewControl_DisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args)
{
UpdateAppTitleBarMargin(sender);
}
private void UpdateAppTitleBarMargin()
{
UpdateAppTitleBarMargin(NavigationViewControl);
}
private void UpdateAppTitleBarMargin(NavigationView sender)
{
Thickness currMargin = AppTitleBar.Margin;
if (sender.DisplayMode == NavigationViewDisplayMode.Minimal)
{
AppTitleBar.Margin = new Thickness((sender.CompactPaneLength * 2), currMargin.Top, currMargin.Right, currMargin.Bottom);
// 当窗口宽度非常小时,隐藏图标和应用设置文字
if (this.ActualWidth < 400)
{
AppTitle.Visibility = Visibility.Collapsed;
}
else
{
AppTitle.Visibility = Visibility.Visible;
}
}
else
{
AppTitleBar.Margin = new Thickness(sender.CompactPaneLength, currMargin.Top, currMargin.Right, currMargin.Bottom);
AppTitle.Visibility = Visibility.Visible;
}
AppTitleBar.Visibility = sender.PaneDisplayMode == NavigationViewPaneDisplayMode.Top ? Visibility.Collapsed : Visibility.Visible;
}
private NavigationViewItem FindNavigationViewItemByTag(string tag)
{
// 遍历主菜单
foreach (var item in NavigationViewControl.MenuItems)
{
if (item is NavigationViewItem navItem)
{
if (navItem.Tag as string == tag)
return navItem;
// 遍历子菜单,自动展开父项
foreach (var childItem in navItem.MenuItems)
{
if (childItem is NavigationViewItem childNavItem && childNavItem.Tag as string == tag)
{
navItem.IsExpanded = true;
return childNavItem;
}
}
}
}
// 遍历底部菜单
foreach (var item in NavigationViewControl.FooterMenuItems)
{
if (item is NavigationViewItem navItem && navItem.Tag as string == tag)
{
return navItem;
}
}
return null;
}
#endregion
#region
private void OnControlsSearchBoxQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (string.IsNullOrWhiteSpace(args.QueryText)) return;
string query = args.QueryText.Trim().ToLower();
var allNavItems = GetAllNavigationItems();
var targetItem = allNavItems.FirstOrDefault(item =>
item.Content?.ToString().ToLower().Contains(query) == true);
if (targetItem != null)
{
NavigationViewControl.SelectedItem = targetItem;
}
}
private void OnControlsSearchBoxTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (args.Reason != AutoSuggestionBoxTextChangeReason.UserInput) return;
string query = sender.Text.Trim().ToLower();
var suggestions = new List<string>();
if (!string.IsNullOrEmpty(query))
{
var allNavItems = GetAllNavigationItems();
suggestions = allNavItems
.Where(item => item.Content?.ToString().ToLower().Contains(query) == true)
.Select(item => item.Content.ToString())
.ToList();
}
sender.ItemsSource = suggestions;
}
// 统一获取所有导航项(主菜单+子菜单+底部菜单)
private List<NavigationViewItem> GetAllNavigationItems()
{
var items = new List<NavigationViewItem>();
// 主菜单+子菜单
foreach (var item in NavigationViewControl.MenuItems)
{
if (item is NavigationViewItem navItem)
{
items.Add(navItem);
foreach (var child in navItem.MenuItems)
{
if (child is NavigationViewItem childNavItem)
items.Add(childNavItem);
}
}
}
// 底部菜单
foreach (var item in NavigationViewControl.FooterMenuItems)
{
if (item is NavigationViewItem navItem)
items.Add(navItem);
}
return items;
}
private void LoadPluginSettingsPages()
{
try
{
var pluginManager = Ink_Canvas.Plugins.PluginManager.Instance;
var plugins = pluginManager.Plugins;
foreach (var plugin in plugins)
{
var settingsView = plugin.Instance.GetSettingsView();
if (settingsView != null)
{
var pageTag = string.Format("PluginSettings_{0}", plugin.Id);
_pageTypes[pageTag] = typeof(PluginSettingsPage);
_pluginPages[pageTag] = plugin;
var navItem = new NavigationViewItem
{
Content = string.Format("{0} 设置", plugin.Name),
Tag = pageTag
};
navItem.Icon = new FontIcon
{
Glyph = "\uE713"
};
NavigationViewControl.MenuItems.Add(navItem);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(string.Format("加载插件设置页面时出错: {0}", ex.Message));
}
}
#endregion
public NavigationView GetNavigationView()
{
return NavigationViewControl;
}
}
}