improve:墨迹渐隐
This commit is contained in:
@@ -833,12 +833,8 @@ namespace Ink_Canvas.Helpers
|
||||
// 归一化方向向量
|
||||
direction.Normalize();
|
||||
|
||||
// 使用OpacityMask创建更自然的擦除效果
|
||||
var maskBrush = CreateEraseMaskBrush(stroke, strokeStart, strokeEnd, 1.0);
|
||||
visual.OpacityMask = maskBrush;
|
||||
|
||||
// 创建擦除动画 - 使用定时器来更新遮罩
|
||||
StartEraseMaskAnimation(visual, stroke, strokeStart, strokeEnd, duration);
|
||||
// 创建精确的擦除动画 - 使用PathGeometry来避免变形
|
||||
CreatePreciseEraseAnimation(visual, stroke, bounds, strokeStart, strokeEnd, direction, length, duration);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -848,6 +844,58 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建精确的擦除动画 - 使用动态裁剪区域避免墨迹移动
|
||||
/// </summary>
|
||||
private void CreatePreciseEraseAnimation(UIElement visual, Stroke stroke, Rect bounds, Point strokeStart, Point strokeEnd, Vector direction, double length, int duration)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 计算擦除方向上的移动距离
|
||||
var totalDistance = Math.Sqrt(Math.Pow(strokeEnd.X - strokeStart.X, 2) + Math.Pow(strokeEnd.Y - strokeStart.Y, 2));
|
||||
|
||||
if (totalDistance == 0)
|
||||
{
|
||||
// 如果墨迹没有长度,使用简单渐隐
|
||||
StartSimpleFadeAnimation(visual, stroke, visual.Opacity, duration);
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建动态裁剪区域 - 从完整墨迹开始,逐渐缩小
|
||||
var clipGeometry = new RectangleGeometry
|
||||
{
|
||||
Rect = bounds
|
||||
};
|
||||
|
||||
visual.Clip = clipGeometry;
|
||||
|
||||
// 创建擦除动画 - 裁剪区域从起点向终点移动并缩小
|
||||
// 使用更自然的擦除效果:从起点开始,逐渐向终点移动
|
||||
var eraseAnimation = new RectAnimation
|
||||
{
|
||||
From = bounds, // 从完整边界开始
|
||||
To = new Rect(strokeEnd.X, strokeEnd.Y, 0, bounds.Height), // 到终点位置,宽度为0
|
||||
Duration = TimeSpan.FromMilliseconds(duration),
|
||||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
|
||||
// 添加动画完成事件
|
||||
eraseAnimation.Completed += (sender, e) =>
|
||||
{
|
||||
OnAnimationCompleted(visual, stroke);
|
||||
};
|
||||
|
||||
// 开始动画
|
||||
clipGeometry.BeginAnimation(RectangleGeometry.RectProperty, eraseAnimation);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"精确擦除动画失败: {ex}", LogHelper.LogType.Error);
|
||||
// 失败时回退到简单动画
|
||||
StartSimpleFadeAnimation(visual, stroke, visual.Opacity, duration);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动画完成后的统一处理
|
||||
/// </summary>
|
||||
|
||||
@@ -155,6 +155,22 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
// 更新创建时间,使其成为最新的窗口
|
||||
windowInfo.CreatedTime = DateTime.Now;
|
||||
|
||||
// 立即将窗口置顶
|
||||
var hwnd = new WindowInteropHelper(window).Handle;
|
||||
if (hwnd != IntPtr.Zero)
|
||||
{
|
||||
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
|
||||
|
||||
// 确保窗口样式正确
|
||||
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
if ((exStyle & WS_EX_TOPMOST) == 0)
|
||||
{
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyZOrder();
|
||||
}
|
||||
}
|
||||
@@ -165,64 +181,12 @@ namespace Ink_Canvas.Helpers
|
||||
/// </summary>
|
||||
private static void ApplyZOrder()
|
||||
{
|
||||
// 按创建时间排序,最新的窗口在最后
|
||||
var sortedWindows = _windowStack
|
||||
.Where(w => IsWindow(w.Handle) && IsWindowVisible(w.Handle) && !IsIconic(w.Handle))
|
||||
.OrderBy(w => w.CreatedTime)
|
||||
.ToList();
|
||||
|
||||
if (sortedWindows.Count == 0) return;
|
||||
|
||||
// 获取主窗口(第一个注册的窗口)
|
||||
var mainWindow = sortedWindows.FirstOrDefault();
|
||||
if (mainWindow == null) return;
|
||||
|
||||
// 如果主窗口需要置顶且启用了无焦点模式
|
||||
if (mainWindow.IsTopmost && mainWindow.IsNoFocusMode)
|
||||
// 简化逻辑:直接设置所有窗口为置顶,让Windows系统自然处理层级
|
||||
foreach (var windowInfo in _windowStack.ToList())
|
||||
{
|
||||
// 检查是否有子窗口在前景
|
||||
var foregroundWindow = GetForegroundWindow();
|
||||
var hasChildWindowInForeground = false;
|
||||
|
||||
if (foregroundWindow != mainWindow.Handle)
|
||||
{
|
||||
var foregroundWindowProcessId = GetWindowThreadProcessId(foregroundWindow, out uint processId);
|
||||
var currentProcessId = GetCurrentProcessId();
|
||||
|
||||
if (processId == currentProcessId)
|
||||
{
|
||||
// 检查前景窗口是否在我们的窗口列表中
|
||||
var foregroundWindowInfo = sortedWindows.FirstOrDefault(w => w.Handle == foregroundWindow);
|
||||
if (foregroundWindowInfo != null)
|
||||
{
|
||||
hasChildWindowInForeground = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasChildWindowInForeground)
|
||||
{
|
||||
// 没有子窗口在前景,主窗口置顶
|
||||
SetWindowPos(mainWindow.Handle, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
|
||||
|
||||
// 确保主窗口样式正确
|
||||
int exStyle = GetWindowLong(mainWindow.Handle, GWL_EXSTYLE);
|
||||
if ((exStyle & WS_EX_TOPMOST) == 0)
|
||||
{
|
||||
SetWindowLong(mainWindow.Handle, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理其他窗口的层级
|
||||
for (int i = 1; i < sortedWindows.Count; i++)
|
||||
{
|
||||
var windowInfo = sortedWindows[i];
|
||||
|
||||
// 子窗口应该置顶于主窗口
|
||||
if (windowInfo.IsTopmost)
|
||||
if (windowInfo.IsTopmost && IsWindow(windowInfo.Handle) && IsWindowVisible(windowInfo.Handle) && !IsIconic(windowInfo.Handle))
|
||||
{
|
||||
// 设置窗口为置顶
|
||||
SetWindowPos(windowInfo.Handle, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
|
||||
|
||||
@@ -273,5 +237,28 @@ namespace Ink_Canvas.Helpers
|
||||
return _windowStack.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制刷新所有窗口的置顶状态
|
||||
/// </summary>
|
||||
public static void ForceRefreshAllWindows()
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
foreach (var windowInfo in _windowStack.ToList())
|
||||
{
|
||||
if (windowInfo.IsTopmost && IsWindow(windowInfo.Handle))
|
||||
{
|
||||
// 强制设置窗口为置顶
|
||||
SetWindowPos(windowInfo.Handle, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
|
||||
|
||||
// 确保窗口样式正确
|
||||
int exStyle = GetWindowLong(windowInfo.Handle, GWL_EXSTYLE);
|
||||
SetWindowLong(windowInfo.Handle, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,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;
|
||||
@@ -246,6 +247,9 @@ namespace Ink_Canvas
|
||||
|
||||
// 为浮动栏按钮添加触摸事件支持
|
||||
AddTouchSupportToFloatingBarButtons();
|
||||
|
||||
// 为滑块控件添加触摸事件支持
|
||||
AddTouchSupportToSliders();
|
||||
}
|
||||
|
||||
|
||||
@@ -1755,6 +1759,9 @@ namespace Ink_Canvas
|
||||
// 先设置WPF的Topmost属性
|
||||
Topmost = true;
|
||||
|
||||
// 立即应用置顶
|
||||
WindowZOrderManager.BringToTop(this);
|
||||
|
||||
// 如果启用了无焦点模式,需要特殊处理
|
||||
if (Settings.Advanced.IsNoFocusMode)
|
||||
{
|
||||
@@ -1847,8 +1854,8 @@ namespace Ink_Canvas
|
||||
// 检查是否有子窗口在前景
|
||||
if (!WindowZOrderManager.HasChildWindowInForeground())
|
||||
{
|
||||
// 没有子窗口在前景,重新应用Z-Order
|
||||
WindowZOrderManager.SetWindowTopmost(this, true);
|
||||
// 没有子窗口在前景,强制刷新所有窗口的置顶状态
|
||||
WindowZOrderManager.ForceRefreshAllWindows();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -2227,5 +2234,288 @@ namespace Ink_Canvas
|
||||
LogHelper.WriteLogToFile($"设置工具模式时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#region 滑块触摸支持
|
||||
|
||||
/// <summary>
|
||||
/// 为所有滑块控件添加触摸和手写笔事件支持
|
||||
/// </summary>
|
||||
private void AddTouchSupportToSliders()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取所有滑块控件并添加触摸支持
|
||||
var sliders = new List<Slider>
|
||||
{
|
||||
InkFadeTimeSlider,
|
||||
AutoStraightenLineThresholdSlider,
|
||||
LineStraightenSensitivitySlider,
|
||||
LineEndpointSnappingThresholdSlider,
|
||||
ViewboxFloatingBarScaleTransformValueSlider,
|
||||
ViewboxFloatingBarOpacityValueSlider,
|
||||
ViewboxFloatingBarOpacityInPPTValueSlider,
|
||||
PPTButtonLeftPositionValueSlider,
|
||||
PPTButtonRightPositionValueSlider,
|
||||
PPTButtonLBPositionValueSlider,
|
||||
PPTButtonRBPositionValueSlider,
|
||||
TouchMultiplierSlider,
|
||||
NibModeBoundsWidthSlider,
|
||||
FingerModeBoundsWidthSlider,
|
||||
SideControlMinimumAutomationSlider,
|
||||
RandWindowOnceCloseLatencySlider,
|
||||
RandWindowOnceMaxStudentsSlider,
|
||||
BoardInkWidthSlider,
|
||||
BoardInkAlphaSlider,
|
||||
BoardHighlighterWidthSlider,
|
||||
InkWidthSlider,
|
||||
InkAlphaSlider,
|
||||
HighlighterWidthSlider
|
||||
};
|
||||
|
||||
foreach (var slider in sliders)
|
||||
{
|
||||
if (slider != null)
|
||||
{
|
||||
AddTouchSupportToSlider(slider);
|
||||
}
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile("已为所有滑块控件添加触摸支持", LogHelper.LogType.Trace);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"添加滑块触摸支持时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为单个滑块控件添加触摸和手写笔事件支持
|
||||
/// </summary>
|
||||
/// <param name="slider">要添加触摸支持的滑块控件</param>
|
||||
private void AddTouchSupportToSlider(Slider slider)
|
||||
{
|
||||
if (slider == null) return;
|
||||
|
||||
// 启用触摸和手写笔支持
|
||||
slider.IsManipulationEnabled = true;
|
||||
|
||||
// 添加触摸事件
|
||||
slider.TouchDown += Slider_TouchDown;
|
||||
slider.TouchMove += Slider_TouchMove;
|
||||
slider.TouchUp += Slider_TouchUp;
|
||||
|
||||
// 添加手写笔事件
|
||||
slider.StylusDown += Slider_StylusDown;
|
||||
slider.StylusMove += Slider_StylusMove;
|
||||
slider.StylusUp += Slider_StylusUp;
|
||||
|
||||
// 添加操作事件(用于更精确的触摸控制)
|
||||
slider.ManipulationStarted += Slider_ManipulationStarted;
|
||||
slider.ManipulationDelta += Slider_ManipulationDelta;
|
||||
slider.ManipulationCompleted += Slider_ManipulationCompleted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块触摸按下事件处理
|
||||
/// </summary>
|
||||
private void Slider_TouchDown(object sender, TouchEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
// 捕获触摸设备
|
||||
slider.CaptureTouch(e.TouchDevice);
|
||||
|
||||
// 计算触摸位置对应的滑块值
|
||||
var touchPoint = e.GetTouchPoint(slider);
|
||||
UpdateSliderValueFromPosition(slider, touchPoint.Position);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块触摸移动事件处理
|
||||
/// </summary>
|
||||
private void Slider_TouchMove(object sender, TouchEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
// 计算触摸位置对应的滑块值
|
||||
var touchPoint = e.GetTouchPoint(slider);
|
||||
UpdateSliderValueFromPosition(slider, touchPoint.Position);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块触摸释放事件处理
|
||||
/// </summary>
|
||||
private void Slider_TouchUp(object sender, TouchEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
// 释放触摸捕获
|
||||
slider.ReleaseTouchCapture(e.TouchDevice);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块手写笔按下事件处理
|
||||
/// </summary>
|
||||
private void Slider_StylusDown(object sender, StylusDownEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
// 捕获手写笔设备
|
||||
slider.CaptureStylus();
|
||||
|
||||
// 计算手写笔位置对应的滑块值
|
||||
var stylusPoint = e.GetStylusPoints(slider);
|
||||
if (stylusPoint.Count > 0)
|
||||
{
|
||||
UpdateSliderValueFromPosition(slider, stylusPoint[0].ToPoint());
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块手写笔移动事件处理
|
||||
/// </summary>
|
||||
private void Slider_StylusMove(object sender, StylusEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null || !slider.IsStylusCaptured) return;
|
||||
|
||||
// 计算手写笔位置对应的滑块值
|
||||
var stylusPoint = e.GetStylusPoints(slider);
|
||||
if (stylusPoint.Count > 0)
|
||||
{
|
||||
UpdateSliderValueFromPosition(slider, stylusPoint[0].ToPoint());
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块手写笔释放事件处理
|
||||
/// </summary>
|
||||
private void Slider_StylusUp(object sender, StylusEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
// 释放手写笔捕获
|
||||
slider.ReleaseStylusCapture();
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块操作开始事件处理
|
||||
/// </summary>
|
||||
private void Slider_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块操作变化事件处理
|
||||
/// </summary>
|
||||
private void Slider_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
// 计算操作位置对应的滑块值
|
||||
var manipulationOrigin = e.ManipulationOrigin;
|
||||
UpdateSliderValueFromPosition(slider, manipulationOrigin);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块操作完成事件处理
|
||||
/// </summary>
|
||||
private void Slider_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
|
||||
{
|
||||
var slider = sender as Slider;
|
||||
if (slider == null) return;
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据触摸/手写笔位置更新滑块值
|
||||
/// </summary>
|
||||
/// <param name="slider">滑块控件</param>
|
||||
/// <param name="position">触摸/手写笔位置</param>
|
||||
private void UpdateSliderValueFromPosition(Slider slider, Point position)
|
||||
{
|
||||
if (slider == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 计算滑块轨道的位置和长度
|
||||
var track = slider.Template.FindName("PART_Track", slider) as Track;
|
||||
if (track == null) return;
|
||||
|
||||
var thumb = track.Thumb;
|
||||
if (thumb == null) return;
|
||||
|
||||
// 获取滑块轨道的实际渲染位置
|
||||
track.Arrange(new Rect(track.DesiredSize));
|
||||
thumb.Arrange(new Rect(thumb.DesiredSize));
|
||||
|
||||
// 计算相对位置(0-1之间)
|
||||
double relativePosition = 0;
|
||||
|
||||
if (slider.Orientation == System.Windows.Controls.Orientation.Horizontal)
|
||||
{
|
||||
// 水平滑块
|
||||
var trackWidth = track.ActualWidth;
|
||||
if (trackWidth > 0)
|
||||
{
|
||||
relativePosition = Math.Max(0, Math.Min(1, position.X / trackWidth));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 垂直滑块
|
||||
var trackHeight = track.ActualHeight;
|
||||
if (trackHeight > 0)
|
||||
{
|
||||
relativePosition = Math.Max(0, Math.Min(1, position.Y / trackHeight));
|
||||
}
|
||||
}
|
||||
|
||||
// 计算新的滑块值
|
||||
var newValue = slider.Minimum + relativePosition * (slider.Maximum - slider.Minimum);
|
||||
|
||||
// 如果启用了吸附到刻度,则调整到最近的刻度
|
||||
if (slider.IsSnapToTickEnabled && slider.TickFrequency > 0)
|
||||
{
|
||||
var tickCount = (int)((slider.Maximum - slider.Minimum) / slider.TickFrequency);
|
||||
var tickIndex = (int)Math.Round(relativePosition * tickCount);
|
||||
newValue = slider.Minimum + tickIndex * slider.TickFrequency;
|
||||
}
|
||||
|
||||
// 更新滑块值
|
||||
slider.Value = Math.Max(slider.Minimum, Math.Min(slider.Maximum, newValue));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"更新滑块值时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,7 +944,11 @@ namespace Ink_Canvas
|
||||
AnimationsHelper.HideWithSlideAndFade(BoardBorderTools);
|
||||
AnimationsHelper.HideWithSlideAndFade(BoardImageOptionsPanel);
|
||||
|
||||
new RandWindow(Settings).Show();
|
||||
var randWindow = new RandWindow(Settings);
|
||||
randWindow.Show();
|
||||
// 确保窗口显示后立即置顶
|
||||
randWindow.Activate();
|
||||
WindowZOrderManager.BringToTop(randWindow);
|
||||
}
|
||||
|
||||
public void CheckEraserTypeTab()
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace Ink_Canvas
|
||||
|
||||
// 添加窗口关闭事件处理
|
||||
Closed += RandWindow_Closed;
|
||||
|
||||
// 添加窗口显示事件处理
|
||||
Loaded += RandWindow_Loaded;
|
||||
}
|
||||
|
||||
private void LoadBackground(Settings settings)
|
||||
@@ -86,6 +89,9 @@ namespace Ink_Canvas
|
||||
|
||||
// 添加窗口关闭事件处理
|
||||
Closed += RandWindow_Closed;
|
||||
|
||||
// 添加窗口显示事件处理
|
||||
Loaded += RandWindow_Loaded;
|
||||
|
||||
new Thread(() =>
|
||||
{
|
||||
@@ -349,6 +355,15 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口加载事件处理
|
||||
/// </summary>
|
||||
private void RandWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// 窗口加载完成后,立即将其置顶
|
||||
WindowZOrderManager.BringToTop(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口关闭事件处理
|
||||
/// </summary>
|
||||
|
||||
@@ -218,6 +218,9 @@ namespace Ink_Canvas.Windows {
|
||||
|
||||
_selectedSidebarItemName = "CanvasAndInkItem";
|
||||
UpdateSidebarItemsSelection();
|
||||
|
||||
// 为自定义滑块控件添加触摸支持
|
||||
AddTouchSupportToCustomSliders();
|
||||
}
|
||||
|
||||
|
||||
@@ -594,5 +597,350 @@ namespace Ink_Canvas.Windows {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region 自定义滑块触摸支持
|
||||
|
||||
/// <summary>
|
||||
/// 为自定义滑块控件添加触摸和手写笔事件支持
|
||||
/// </summary>
|
||||
private void AddTouchSupportToCustomSliders()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 延迟执行,确保UI元素已加载
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
// 查找所有自定义滑块控件并添加触摸支持
|
||||
AddTouchSupportToCustomSliderInPane(CanvasAndInkPane);
|
||||
AddTouchSupportToCustomSliderInPane(ThemePane);
|
||||
AddTouchSupportToCustomSliderInPane(PowerPointPane);
|
||||
AddTouchSupportToCustomSliderInPane(AutomationPane);
|
||||
AddTouchSupportToCustomSliderInPane(LuckyRandomPane);
|
||||
AddTouchSupportToCustomSliderInPane(AdvancedPane);
|
||||
}), System.Windows.Threading.DispatcherPriority.Loaded);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录错误但不影响程序运行
|
||||
System.Diagnostics.Debug.WriteLine($"添加自定义滑块触摸支持时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为指定面板中的自定义滑块控件添加触摸支持
|
||||
/// </summary>
|
||||
/// <param name="pane">面板控件</param>
|
||||
private void AddTouchSupportToCustomSliderInPane(Grid pane)
|
||||
{
|
||||
if (pane == null) return;
|
||||
|
||||
// 查找面板中的所有自定义滑块控件
|
||||
var customSliders = FindCustomSlidersInPanel(pane);
|
||||
|
||||
foreach (var slider in customSliders)
|
||||
{
|
||||
AddTouchSupportToCustomSlider(slider);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在面板中查找自定义滑块控件
|
||||
/// </summary>
|
||||
/// <param name="panel">面板控件</param>
|
||||
/// <returns>自定义滑块控件列表</returns>
|
||||
private List<CustomSliderInfo> FindCustomSlidersInPanel(DependencyObject panel)
|
||||
{
|
||||
var customSliders = new List<CustomSliderInfo>();
|
||||
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(panel); i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(panel, i);
|
||||
|
||||
// 检查是否是自定义滑块控件(包含GnomeSliderThumb图片的Grid)
|
||||
if (child is Grid grid)
|
||||
{
|
||||
var customSlider = FindCustomSliderInGrid(grid);
|
||||
if (customSlider != null)
|
||||
{
|
||||
customSliders.Add(customSlider);
|
||||
}
|
||||
}
|
||||
|
||||
// 递归查找子元素
|
||||
customSliders.AddRange(FindCustomSlidersInPanel(child));
|
||||
}
|
||||
|
||||
return customSliders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在Grid中查找自定义滑块控件
|
||||
/// </summary>
|
||||
/// <param name="grid">Grid控件</param>
|
||||
/// <returns>自定义滑块信息</returns>
|
||||
private CustomSliderInfo FindCustomSliderInGrid(Grid grid)
|
||||
{
|
||||
// 查找包含GnomeSliderThumb图片的Grid
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(grid); i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(grid, i);
|
||||
|
||||
if (child is Image image && image.Source != null)
|
||||
{
|
||||
var sourceName = image.Source.ToString();
|
||||
if (sourceName.Contains("GnomeSliderThumb"))
|
||||
{
|
||||
// 找到滑块控件,创建自定义滑块信息
|
||||
var customSlider = new CustomSliderInfo
|
||||
{
|
||||
Container = grid,
|
||||
ThumbImage = image,
|
||||
TrackBorder = FindTrackBorderInGrid(grid),
|
||||
ValueBorder = FindValueBorderInGrid(grid)
|
||||
};
|
||||
|
||||
return customSlider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在Grid中查找轨道Border
|
||||
/// </summary>
|
||||
/// <param name="grid">Grid控件</param>
|
||||
/// <returns>轨道Border</returns>
|
||||
private Border FindTrackBorderInGrid(Grid grid)
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(grid); i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(grid, i);
|
||||
|
||||
if (child is Border border && border.Background != null)
|
||||
{
|
||||
var brush = border.Background as SolidColorBrush;
|
||||
if (brush != null && brush.Color.ToString() == "#FFDEDEDE")
|
||||
{
|
||||
return border;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在Grid中查找值显示Border
|
||||
/// </summary>
|
||||
/// <param name="grid">Grid控件</param>
|
||||
/// <returns>值显示Border</returns>
|
||||
private Border FindValueBorderInGrid(Grid grid)
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(grid); i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(grid, i);
|
||||
|
||||
if (child is Border border && border.Background != null)
|
||||
{
|
||||
var brush = border.Background as SolidColorBrush;
|
||||
if (brush != null && brush.Color.ToString() == "#FF3584E4")
|
||||
{
|
||||
return border;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为自定义滑块控件添加触摸支持
|
||||
/// </summary>
|
||||
/// <param name="customSlider">自定义滑块信息</param>
|
||||
private void AddTouchSupportToCustomSlider(CustomSliderInfo customSlider)
|
||||
{
|
||||
if (customSlider?.Container == null) return;
|
||||
|
||||
// 启用触摸和手写笔支持
|
||||
customSlider.Container.IsManipulationEnabled = true;
|
||||
|
||||
// 添加触摸事件
|
||||
customSlider.Container.TouchDown += (s, e) => CustomSlider_TouchDown(s, e, customSlider);
|
||||
customSlider.Container.TouchMove += (s, e) => CustomSlider_TouchMove(s, e, customSlider);
|
||||
customSlider.Container.TouchUp += (s, e) => CustomSlider_TouchUp(s, e, customSlider);
|
||||
|
||||
// 添加手写笔事件
|
||||
customSlider.Container.StylusDown += (s, e) => CustomSlider_StylusDown(s, e, customSlider);
|
||||
customSlider.Container.StylusMove += (s, e) => CustomSlider_StylusMove(s, e, customSlider);
|
||||
customSlider.Container.StylusUp += (s, e) => CustomSlider_StylusUp(s, e, customSlider);
|
||||
|
||||
// 添加操作事件
|
||||
customSlider.Container.ManipulationStarted += (s, e) => CustomSlider_ManipulationStarted(s, e, customSlider);
|
||||
customSlider.Container.ManipulationDelta += (s, e) => CustomSlider_ManipulationDelta(s, e, customSlider);
|
||||
customSlider.Container.ManipulationCompleted += (s, e) => CustomSlider_ManipulationCompleted(s, e, customSlider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块触摸按下事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_TouchDown(object sender, TouchEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
customSlider.Container.CaptureTouch(e.TouchDevice);
|
||||
customSlider.IsTouchCaptured = true;
|
||||
var touchPoint = e.GetTouchPoint(customSlider.Container);
|
||||
UpdateCustomSliderValueFromPosition(customSlider, touchPoint.Position);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块触摸移动事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_TouchMove(object sender, TouchEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
// 检查是否有触摸捕获
|
||||
if (!customSlider.IsTouchCaptured) return;
|
||||
var touchPoint = e.GetTouchPoint(customSlider.Container);
|
||||
UpdateCustomSliderValueFromPosition(customSlider, touchPoint.Position);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块触摸释放事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_TouchUp(object sender, TouchEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
customSlider.Container.ReleaseTouchCapture(e.TouchDevice);
|
||||
customSlider.IsTouchCaptured = false;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块手写笔按下事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_StylusDown(object sender, StylusDownEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
customSlider.Container.CaptureStylus();
|
||||
var stylusPoint = e.GetStylusPoints(customSlider.Container);
|
||||
if (stylusPoint.Count > 0)
|
||||
{
|
||||
UpdateCustomSliderValueFromPosition(customSlider, stylusPoint[0].ToPoint());
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块手写笔移动事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_StylusMove(object sender, StylusEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
if (!customSlider.Container.IsStylusCaptured) return;
|
||||
var stylusPoint = e.GetStylusPoints(customSlider.Container);
|
||||
if (stylusPoint.Count > 0)
|
||||
{
|
||||
UpdateCustomSliderValueFromPosition(customSlider, stylusPoint[0].ToPoint());
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块手写笔释放事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_StylusUp(object sender, StylusEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
customSlider.Container.ReleaseStylusCapture();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块操作开始事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_ManipulationStarted(object sender, ManipulationStartedEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块操作变化事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_ManipulationDelta(object sender, ManipulationDeltaEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
var manipulationOrigin = e.ManipulationOrigin;
|
||||
UpdateCustomSliderValueFromPosition(customSlider, manipulationOrigin);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块操作完成事件处理
|
||||
/// </summary>
|
||||
private void CustomSlider_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e, CustomSliderInfo customSlider)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据触摸/手写笔位置更新自定义滑块值
|
||||
/// </summary>
|
||||
/// <param name="customSlider">自定义滑块信息</param>
|
||||
/// <param name="position">触摸/手写笔位置</param>
|
||||
private void UpdateCustomSliderValueFromPosition(CustomSliderInfo customSlider, Point position)
|
||||
{
|
||||
if (customSlider?.TrackBorder == null || customSlider.ThumbImage == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 计算滑块轨道的实际位置和长度
|
||||
var trackWidth = customSlider.TrackBorder.ActualWidth;
|
||||
if (trackWidth <= 0) return;
|
||||
|
||||
// 计算相对位置(0-1之间)
|
||||
var relativePosition = Math.Max(0, Math.Min(1, position.X / trackWidth));
|
||||
|
||||
// 更新滑块位置
|
||||
var thumbTransform = customSlider.ThumbImage.RenderTransform as TranslateTransform;
|
||||
if (thumbTransform == null)
|
||||
{
|
||||
thumbTransform = new TranslateTransform();
|
||||
customSlider.ThumbImage.RenderTransform = thumbTransform;
|
||||
}
|
||||
|
||||
// 计算新的滑块位置
|
||||
var newX = relativePosition * trackWidth;
|
||||
thumbTransform.X = newX;
|
||||
|
||||
// 更新值显示Border的宽度
|
||||
if (customSlider.ValueBorder != null)
|
||||
{
|
||||
var valueWidth = relativePosition * trackWidth;
|
||||
customSlider.ValueBorder.Width = Math.Max(0, valueWidth);
|
||||
|
||||
// 调整值显示Border的位置
|
||||
var valueMargin = customSlider.ValueBorder.Margin;
|
||||
customSlider.ValueBorder.Margin = new Thickness(0, valueMargin.Top, trackWidth - valueWidth, valueMargin.Bottom);
|
||||
}
|
||||
|
||||
// 这里可以根据需要添加值变化事件处理
|
||||
// 例如:OnCustomSliderValueChanged(customSlider, relativePosition);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"更新自定义滑块值时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义滑块信息类
|
||||
/// </summary>
|
||||
private class CustomSliderInfo
|
||||
{
|
||||
public Grid Container { get; set; }
|
||||
public Image ThumbImage { get; set; }
|
||||
public Border TrackBorder { get; set; }
|
||||
public Border ValueBorder { get; set; }
|
||||
public bool IsTouchCaptured { get; set; } = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user