fix(UI): 优化弹出菜单位置和层级管理

修复弹出菜单在移动时位置不更新的问题,添加节流机制避免频繁刷新
使用Win32 API强制刷新弹出菜单位置并提升到最顶层
调整浮动工具栏和弹出菜单的样式和位置
移除未使用的字体样式定义
This commit is contained in:
PrefacedCorg
2026-05-02 17:06:08 +08:00
parent f825211987
commit c8e3bceab2
5 changed files with 235 additions and 28 deletions
@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Forms;
using System.Windows.Ink;
using System.Windows.Input;
@@ -205,6 +206,7 @@ namespace Ink_Canvas
/// </summary>
private Point pointPPT = new Point(-1, -1);
private DispatcherTimer _floatingBarScreenFollowTimer;
private DispatcherTimer _popupRefreshTimer; // Popup 位置刷新节流定时器
private string _lastFloatingBarScreenDeviceName;
private string _lastCanvasScreenDeviceName;
private bool _isRebuildingCanvasForScreen;
@@ -227,6 +229,95 @@ namespace Ink_Canvas
pointPPT = new Point(xPos, yPos);
else
pointDesktop = new Point(xPos, yPos);
// 刷新 Popup 菜单位置(带节流)
RefreshPopupPositionThrottled();
}
}
/// <summary>
/// 刷新 Popup 菜单位置(带节流,避免频繁调用)
/// </summary>
private void RefreshPopupPositionThrottled()
{
try
{
// 如果没有打开的 Popup,直接返回
if (!BorderTools.IsOpen && !BoardBorderToolsPopup.IsOpen) return;
// 如果定时器不存在,创建一个(16ms ≈ 60fps)
if (_popupRefreshTimer == null)
{
_popupRefreshTimer = new DispatcherTimer();
_popupRefreshTimer.Interval = TimeSpan.FromMilliseconds(16);
_popupRefreshTimer.Tick += (s, e) =>
{
_popupRefreshTimer?.Stop();
RefreshPopupPositionInternal();
};
}
// 重启定时器(如果已经在运行,会重新计时)
_popupRefreshTimer.Stop();
_popupRefreshTimer.Start();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"RefreshPopupPositionThrottled error: {ex.Message}");
}
}
/// <summary>
/// 实际执行 Popup 位置刷新(强力版本)
/// </summary>
private void RefreshPopupPositionInternal()
{
try
{
RefreshPopupForcefully(BorderTools);
RefreshPopupForcefully(BoardBorderToolsPopup);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"RefreshPopupPositionInternal error: {ex.Message}");
}
}
/// <summary>
/// 强制刷新单个 Popup 的位置
/// 使用多种策略确保位置更新生效
/// </summary>
private void RefreshPopupForcefully(Popup popup)
{
if (popup == null || !popup.IsOpen || popup.PlacementTarget == null) return;
try
{
// 策略1:强制失效测量和布局
popup.InvalidateMeasure();
popup.InvalidateArrange();
// 策略2:修改 Offset 触发重新定位
var originalHorizontalOffset = popup.HorizontalOffset;
var originalVerticalOffset = popup.VerticalOffset;
popup.HorizontalOffset = originalHorizontalOffset + 0.001;
popup.VerticalOffset = originalVerticalOffset + 0.001;
popup.HorizontalOffset = originalHorizontalOffset;
popup.VerticalOffset = originalVerticalOffset;
// 策略3:强制更新布局
popup.UpdateLayout();
// 策略4:使用 Win32 API 强制刷新窗口位置(终极方案)
AnimationsHelper.ForceRefreshPopupPosition(popup);
System.Diagnostics.Debug.WriteLine($"[PopupRefresh] Forcefully refreshed popup position");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[PopupRefresh] Error: {ex.Message}");
}
}