From c8e3bceab2b222eae80b63d9480327952285e2a7 Mon Sep 17 00:00:00 2001 From: PrefacedCorg <1876568293@qq.com> Date: Sat, 2 May 2026 17:06:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(UI):=20=E4=BC=98=E5=8C=96=E5=BC=B9=E5=87=BA?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E4=BD=8D=E7=BD=AE=E5=92=8C=E5=B1=82=E7=BA=A7?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复弹出菜单在移动时位置不更新的问题,添加节流机制避免频繁刷新 使用Win32 API强制刷新弹出菜单位置并提升到最顶层 调整浮动工具栏和弹出菜单的样式和位置 移除未使用的字体样式定义 --- Ink Canvas/App.xaml | 18 --- Ink Canvas/Helpers/AnimationsHelper.cs | 133 ++++++++++++++++++ Ink Canvas/MainWindow.xaml | 18 +-- Ink Canvas/MainWindow.xaml.cs | 3 +- .../MainWindow_cs/MW_FloatingBarIcons.cs | 91 ++++++++++++ 5 files changed, 235 insertions(+), 28 deletions(-) diff --git a/Ink Canvas/App.xaml b/Ink Canvas/App.xaml index 3029e2d3..9ac047f0 100644 --- a/Ink Canvas/App.xaml +++ b/Ink Canvas/App.xaml @@ -10,24 +10,6 @@ ./Resources/Fonts/#HarmonyOS Sans SC - - - - - - diff --git a/Ink Canvas/Helpers/AnimationsHelper.cs b/Ink Canvas/Helpers/AnimationsHelper.cs index 76fa7cf5..bac2f293 100644 --- a/Ink Canvas/Helpers/AnimationsHelper.cs +++ b/Ink Canvas/Helpers/AnimationsHelper.cs @@ -1,6 +1,8 @@ using System; +using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls.Primitives; +using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Animation; @@ -8,6 +10,133 @@ namespace Ink_Canvas.Helpers { internal class AnimationsHelper { + #region Win32 API - 用于提升 Popup 层级和刷新位置 + + [DllImport("user32.dll")] + private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); + + [DllImport("user32.dll")] + private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); + + [DllImport("user32.dll")] + private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); + + [StructLayout(LayoutKind.Sequential)] + private struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + private const uint GW_HWNDPREV = 3; + private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); + private static readonly IntPtr HWND_TOP = new IntPtr(0); + private const uint SWP_NOMOVE = 0x0002; + private const uint SWP_NOSIZE = 0x0001; + private const uint SWP_NOACTIVATE = 0x0010; + private const uint SWP_SHOWWINDOW = 0x0040; + + /// + /// 强制刷新 Popup 的实际窗口位置(终极方案) + /// 通过 Win32 API 直接操作窗口句柄 + /// + public static void ForceRefreshPopupPosition(Popup popup) + { + if (popup?.Child == null || !popup.IsOpen) return; + + try + { + Application.Current.Dispatcher.BeginInvoke(new Action(() => + { + try + { + var source = PresentationSource.FromVisual(popup.Child) as HwndSource; + if (source?.Handle == null) return; + + var hwnd = source.Handle; + + // 获取当前窗口位置 + if (GetWindowRect(hwnd, out RECT rect)) + { + // 使用相同的参数调用 SetWindowPos,但加上 SWP_SHOWWINDOW + // 这会强制窗口管理器重新评估并更新窗口位置 + SetWindowPos( + hwnd, + HWND_TOP, + rect.Left, rect.Top, + rect.Right - rect.Left, + rect.Bottom - rect.Top, + SWP_NOACTIVATE | SWP_SHOWWINDOW); + + System.Diagnostics.Debug.WriteLine($"[PopupZOrder] Force refreshed position: ({rect.Left}, {rect.Top})"); + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[PopupZOrder] ForceRefreshPopupPosition failed: {ex.Message}"); + } + }), System.Windows.Threading.DispatcherPriority.Render); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[PopupZOrder] ForceRefreshPopupPosition error: {ex.Message}"); + } + } + + /// + /// 将 Popup 窗口提升到最顶层,确保不被其他控件遮挡 + /// 采用多重策略确保置顶生效 + /// + private static void BringPopupToFront(Popup popup) + { + try + { + if (popup?.Child == null) return; + + Action bringToTopAction = () => + { + try + { + var source = PresentationSource.FromVisual(popup.Child) as HwndSource; + if (source?.Handle == null) return; + + var hwnd = source.Handle; + + // 策略1:直接设置为 TOPMOST(最高优先级) + SetWindowPos(hwnd, HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW); + + System.Diagnostics.Debug.WriteLine($"[PopupZOrder] Set TOPMOST for popup"); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[PopupZOrder] BringPopupToFront failed: {ex.Message}"); + } + }; + + // 立即执行第一次 + Application.Current.Dispatcher.BeginInvoke(bringToTopAction, + System.Windows.Threading.DispatcherPriority.Render); + + // 延迟 50ms 后再次执行(确保在其他窗口操作之后) + Application.Current.Dispatcher.BeginInvoke(bringToTopAction, + System.Windows.Threading.DispatcherPriority.Normal); + + // 延迟 100ms 后第三次执行(最终确认) + Application.Current.Dispatcher.BeginInvoke(bringToTopAction, + System.Windows.Threading.DispatcherPriority.Background); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[PopupZOrder] BringPopupToFront error: {ex.Message}"); + } + } + + #endregion + private static UIElement ResolveAnimationTarget(UIElement element) { return element; @@ -296,6 +425,7 @@ namespace Ink_Canvas.Helpers if (child == null) { popup.IsOpen = true; + BringPopupToFront(popup); return; } @@ -304,6 +434,9 @@ namespace Ink_Canvas.Helpers popup.IsOpen = true; + // 提升 Popup 到最顶层 + BringPopupToFront(popup); + var sb = new Storyboard(); var fadeInAnimation = new DoubleAnimation diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index b291a5ca..88ad72df 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -2363,8 +2363,8 @@ HorizontalAlignment="Right" VerticalAlignment="Center"/> - @@ -2990,24 +2990,24 @@ AllowsTransparency="True" StaysOpen="True" IsOpen="False"> - + - + - - +