From 90ba3f7fa60d4787e73c37d234062b23421385bf Mon Sep 17 00:00:00 2001 From: PrefacedCorg <1876568293@qq.com> Date: Fri, 1 May 2026 12:34:16 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=8A=A8?= =?UTF-8?q?=E7=94=BB=E9=80=BB=E8=BE=91=E5=92=8CUI=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构动画帮助类以支持自定义动画目标 简化颜色滑块更新逻辑 调整浮动工具栏显示逻辑 新增BoardMenuFrame自定义控件 --- Ink Canvas/Controls/BoardMenuFrame.cs | 141 ++++++ Ink Canvas/Helpers/AnimationsHelper.cs | 42 +- Ink Canvas/MainWindow.xaml | 412 ++++++------------ Ink Canvas/MainWindow_cs/MW_BoardIcons.cs | 50 +-- Ink Canvas/MainWindow_cs/MW_Colors.cs | 14 - .../MainWindow_cs/MW_FloatingBarIcons.cs | 18 +- Ink Canvas/Themes/Generic.xaml | 61 +++ 7 files changed, 368 insertions(+), 370 deletions(-) create mode 100644 Ink Canvas/Controls/BoardMenuFrame.cs create mode 100644 Ink Canvas/Themes/Generic.xaml diff --git a/Ink Canvas/Controls/BoardMenuFrame.cs b/Ink Canvas/Controls/BoardMenuFrame.cs new file mode 100644 index 00000000..cadefa70 --- /dev/null +++ b/Ink Canvas/Controls/BoardMenuFrame.cs @@ -0,0 +1,141 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Media; + +namespace Ink_Canvas.Controls +{ + [TemplatePart(Name = PartCloseImage, Type = typeof(UIElement))] + [TemplatePart(Name = PartAnimationRoot, Type = typeof(UIElement))] + public class BoardMenuFrame : ContentControl + { + private const string PartCloseImage = "PART_CloseImage"; + private const string PartAnimationRoot = "PART_AnimationRoot"; + + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register(nameof(Title), typeof(object), typeof(BoardMenuFrame), new PropertyMetadata(null)); + + public static readonly DependencyProperty TitleFontSizeProperty = + DependencyProperty.Register(nameof(TitleFontSize), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(11d)); + + public static readonly DependencyProperty HeaderHeightProperty = + DependencyProperty.Register(nameof(HeaderHeight), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(48d)); + + public static readonly DependencyProperty PanelCornerRadiusProperty = + DependencyProperty.Register(nameof(PanelCornerRadius), typeof(CornerRadius), typeof(BoardMenuFrame), new PropertyMetadata(new CornerRadius(5))); + + public static readonly DependencyProperty HeaderCornerRadiusProperty = + DependencyProperty.Register(nameof(HeaderCornerRadius), typeof(CornerRadius), typeof(BoardMenuFrame), new PropertyMetadata(new CornerRadius(6, 6, 0, 0))); + + public static readonly DependencyProperty PanelBackgroundProperty = + DependencyProperty.Register(nameof(PanelBackground), typeof(Brush), typeof(BoardMenuFrame), new PropertyMetadata(null)); + + public static readonly DependencyProperty HeaderBackgroundProperty = + DependencyProperty.Register(nameof(HeaderBackground), typeof(Brush), typeof(BoardMenuFrame), + new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#2563eb")))); + + public static readonly DependencyProperty HeaderBorderBrushProperty = + DependencyProperty.Register(nameof(HeaderBorderBrush), typeof(Brush), typeof(BoardMenuFrame), + new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#1e3a8a")))); + + public static readonly DependencyProperty IsOpenProperty = + DependencyProperty.Register(nameof(IsOpen), typeof(bool), typeof(BoardMenuFrame), new PropertyMetadata(false)); + + public static readonly DependencyProperty PlacementTargetProperty = + DependencyProperty.Register(nameof(PlacementTarget), typeof(UIElement), typeof(BoardMenuFrame), new PropertyMetadata(null)); + + public static readonly DependencyProperty PlacementProperty = + DependencyProperty.Register(nameof(Placement), typeof(PlacementMode), typeof(BoardMenuFrame), new PropertyMetadata(PlacementMode.Custom)); + + public static readonly DependencyProperty CustomPopupPlacementCallbackProperty = + DependencyProperty.Register(nameof(CustomPopupPlacementCallback), typeof(CustomPopupPlacementCallback), typeof(BoardMenuFrame), + new PropertyMetadata((CustomPopupPlacementCallback)PlaceCenteredAbove)); + + private static CustomPopupPlacement[] PlaceCenteredAbove(Size popupSize, Size targetSize, Point offset) + { + return new[] + { + new CustomPopupPlacement( + new Point((targetSize.Width - popupSize.Width) / 2 + offset.X, + -popupSize.Height + offset.Y), + PopupPrimaryAxis.Horizontal), + new CustomPopupPlacement( + new Point((targetSize.Width - popupSize.Width) / 2 + offset.X, + targetSize.Height - offset.Y), + PopupPrimaryAxis.Horizontal) + }; + } + + public static readonly DependencyProperty PopupHorizontalOffsetProperty = + DependencyProperty.Register(nameof(PopupHorizontalOffset), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(0d)); + + public static readonly DependencyProperty PopupVerticalOffsetProperty = + DependencyProperty.Register(nameof(PopupVerticalOffset), typeof(double), typeof(BoardMenuFrame), new PropertyMetadata(-4d)); + + public object Title { get => GetValue(TitleProperty); set => SetValue(TitleProperty, value); } + public double TitleFontSize { get => (double)GetValue(TitleFontSizeProperty); set => SetValue(TitleFontSizeProperty, value); } + public double HeaderHeight { get => (double)GetValue(HeaderHeightProperty); set => SetValue(HeaderHeightProperty, value); } + public CornerRadius PanelCornerRadius { get => (CornerRadius)GetValue(PanelCornerRadiusProperty); set => SetValue(PanelCornerRadiusProperty, value); } + public CornerRadius HeaderCornerRadius { get => (CornerRadius)GetValue(HeaderCornerRadiusProperty); set => SetValue(HeaderCornerRadiusProperty, value); } + public Brush PanelBackground { get => (Brush)GetValue(PanelBackgroundProperty); set => SetValue(PanelBackgroundProperty, value); } + public Brush HeaderBackground { get => (Brush)GetValue(HeaderBackgroundProperty); set => SetValue(HeaderBackgroundProperty, value); } + public Brush HeaderBorderBrush { get => (Brush)GetValue(HeaderBorderBrushProperty); set => SetValue(HeaderBorderBrushProperty, value); } + public bool IsOpen { get => (bool)GetValue(IsOpenProperty); set => SetValue(IsOpenProperty, value); } + public UIElement PlacementTarget { get => (UIElement)GetValue(PlacementTargetProperty); set => SetValue(PlacementTargetProperty, value); } + public PlacementMode Placement { get => (PlacementMode)GetValue(PlacementProperty); set => SetValue(PlacementProperty, value); } + public CustomPopupPlacementCallback CustomPopupPlacementCallback + { + get => (CustomPopupPlacementCallback)GetValue(CustomPopupPlacementCallbackProperty); + set => SetValue(CustomPopupPlacementCallbackProperty, value); + } + public double PopupHorizontalOffset { get => (double)GetValue(PopupHorizontalOffsetProperty); set => SetValue(PopupHorizontalOffsetProperty, value); } + public double PopupVerticalOffset { get => (double)GetValue(PopupVerticalOffsetProperty); set => SetValue(PopupVerticalOffsetProperty, value); } + + public event MouseButtonEventHandler CloseMouseDown; + public event MouseButtonEventHandler CloseMouseUp; + + public UIElement AnimationTarget { get; private set; } + + private UIElement _closeImage; + + static BoardMenuFrame() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(BoardMenuFrame), new FrameworkPropertyMetadata(typeof(BoardMenuFrame))); + VisibilityProperty.OverrideMetadata(typeof(BoardMenuFrame), + new FrameworkPropertyMetadata(Visibility.Collapsed, OnVisibilityChanged)); + } + + private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((BoardMenuFrame)d).IsOpen = (Visibility)e.NewValue == Visibility.Visible; + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + if (_closeImage != null) + { + _closeImage.MouseDown -= CloseImage_MouseDown; + _closeImage.MouseUp -= CloseImage_MouseUp; + } + _closeImage = GetTemplateChild(PartCloseImage) as UIElement; + if (_closeImage != null) + { + _closeImage.MouseDown += CloseImage_MouseDown; + _closeImage.MouseUp += CloseImage_MouseUp; + } + AnimationTarget = GetTemplateChild(PartAnimationRoot) as UIElement; + } + + private void CloseImage_MouseDown(object sender, MouseButtonEventArgs e) + { + CloseMouseDown?.Invoke(sender, e); + } + + private void CloseImage_MouseUp(object sender, MouseButtonEventArgs e) + { + CloseMouseUp?.Invoke(sender, e); + } + } +} \ No newline at end of file diff --git a/Ink Canvas/Helpers/AnimationsHelper.cs b/Ink Canvas/Helpers/AnimationsHelper.cs index dbc1c030..305682b0 100644 --- a/Ink Canvas/Helpers/AnimationsHelper.cs +++ b/Ink Canvas/Helpers/AnimationsHelper.cs @@ -2,11 +2,22 @@ using System; using System.Windows; using System.Windows.Media; using System.Windows.Media.Animation; +using Ink_Canvas.Controls; namespace Ink_Canvas.Helpers { internal class AnimationsHelper { + private static UIElement ResolveAnimationTarget(UIElement element) + { + if (element is BoardMenuFrame frame) + { + frame.ApplyTemplate(); + return frame.AnimationTarget ?? element; + } + return element; + } + public static void ShowWithFadeIn(UIElement element, double duration = 0.15) { if (element.Visibility == Visibility.Visible) return; @@ -36,14 +47,17 @@ namespace Ink_Canvas.Helpers { try { - if (element.Visibility == Visibility.Visible) return; - if (element == null) throw new ArgumentNullException(nameof(element)); + if (element.Visibility == Visibility.Visible) return; + + element.Visibility = Visibility.Visible; + + var target = ResolveAnimationTarget(element); + var sb = new Storyboard(); - // 渐变动画 var fadeInAnimation = new DoubleAnimation { From = 0.5, @@ -54,10 +68,9 @@ namespace Ink_Canvas.Helpers Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath(UIElement.OpacityProperty)); - // 滑动动画 var slideAnimation = new DoubleAnimation { - From = element.RenderTransform.Value.OffsetY + 10, // 滑动距离 + From = 10, To = 0, Duration = TimeSpan.FromSeconds(duration) }; @@ -68,10 +81,9 @@ namespace Ink_Canvas.Helpers sb.Children.Add(fadeInAnimation); sb.Children.Add(slideAnimation); - element.Visibility = Visibility.Visible; - element.RenderTransform = new TranslateTransform(); + target.RenderTransform = new TranslateTransform(); - sb.Begin((FrameworkElement)element); + sb.Begin((FrameworkElement)target); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); } } @@ -207,14 +219,15 @@ namespace Ink_Canvas.Helpers { try { - if (element.Visibility == Visibility.Collapsed) return; - if (element == null) throw new ArgumentNullException(nameof(element)); + if (element.Visibility == Visibility.Collapsed) return; + + var target = ResolveAnimationTarget(element); + var sb = new Storyboard(); - // 渐变动画 var fadeOutAnimation = new DoubleAnimation { From = 1, @@ -224,11 +237,10 @@ namespace Ink_Canvas.Helpers fadeOutAnimation.EasingFunction = new CubicEase(); Storyboard.SetTargetProperty(fadeOutAnimation, new PropertyPath(UIElement.OpacityProperty)); - // 滑动动画 var slideAnimation = new DoubleAnimation { From = 0, - To = element.RenderTransform.Value.OffsetY + 10, // 滑动距离 + To = 10, Duration = TimeSpan.FromSeconds(duration) }; slideAnimation.EasingFunction = new CubicEase(); @@ -243,8 +255,8 @@ namespace Ink_Canvas.Helpers element.Visibility = Visibility.Collapsed; }; - element.RenderTransform = new TranslateTransform(); - sb.Begin((FrameworkElement)element); + target.RenderTransform = new TranslateTransform(); + sb.Begin((FrameworkElement)target); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); } } diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml index 31b93e50..54130c3e 100644 --- a/Ink Canvas/MainWindow.xaml +++ b/Ink Canvas/MainWindow.xaml @@ -927,31 +927,17 @@ Label="{i18n:I18n Key=Board_Gesture}" IconGeometry="F0 M24,24z M0,0z M7.82154,10.0753L7.82154,3.74613C7.82154,3.06603 8.08946,2.40655 8.57377,1.92224 9.05808,1.43793 9.70726,1.17001 10.3977,1.17001 11.0881,1.17001 11.7372,1.43793 12.2216,1.92224 12.7059,2.40655 12.9738,3.05573 12.9738,3.74613L12.9738,6.37308C13.1415,6.33947 13.3139,6.32225 13.489,6.32225 14.1794,6.32225 14.8286,6.59016 15.3129,7.07447 15.4484,7.21001 15.567,7.35845 15.6675,7.5171 15.9551,7.40916 16.2634,7.35269 16.5803,7.35269 17.2707,7.35269 17.9199,7.62061 18.4042,8.10492 18.5461,8.24683 18.6695,8.4029 18.7729,8.57001 19.6856,8.26338 20.7674,8.45871 21.4647,9.15599 21.949,9.6403 22.2169,10.2998 22.2169,10.9799L22.2169,15.6169C22.2169,17.5438 21.4647,19.3574 20.1045,20.7176 18.7443,22.0778 16.9307,22.83 15.0038,22.83L13.149,22.83 13.1799,22.8094 12.8398,22.8094C11.7682,22.7579 10.7068,22.4694 9.75878,21.9541 8.70773,21.3874 7.81124,20.563 7.15175,19.5738L6.94566,19.2647C6.60562,18.7494 5.49273,16.8019 3.52458,13.3087 3.19484,12.7213 3.1021,12.0412 3.27727,11.3818 3.45245,10.7326 3.86463,10.1761 4.44168,9.83608 5.00842,9.49604 5.66791,9.35177 6.31709,9.43421 6.86548,9.50385 7.39181,9.7279 7.82154,10.0753z M10.037,3.38547C10.1297,3.28243 10.2637,3.23091 10.3977,3.23091 10.5316,3.23091 10.6656,3.29273 10.7583,3.38547 10.8614,3.47821 10.9129,3.61217 10.9129,3.74613L10.9129,11.4745C10.9129,12.0412 11.3766,12.5049 11.9433,12.5049 12.5101,12.5049 12.9738,12.0412 12.9738,11.4745L12.9738,8.89836C12.9738,8.7644 13.0356,8.63045 13.1283,8.53771 13.2211,8.43466 13.355,8.38314 13.489,8.38314 13.623,8.38314 13.7569,8.44497 13.8497,8.53771 13.9527,8.63045 14.0042,8.7644 14.0042,8.89836L14.0042,11.4745C14.0042,12.0412 14.4679,12.5049 15.0347,12.5049 15.6014,12.5049 16.0651,12.0412 16.0651,11.4745L16.0651,9.92881C16.0651,9.79485 16.1269,9.66089 16.2197,9.56815 16.3124,9.46511 16.4464,9.41359 16.5803,9.41359 16.7143,9.41359 16.8483,9.47541 16.941,9.56815 17.044,9.66089 17.0956,9.79485 17.0956,9.92881L17.0956,10.5869C17.0752,10.7163 17.0646,10.8477 17.0646,10.9799 17.0646,11.0661 17.0754,11.1499 17.0956,11.2301L17.0956,11.4745C17.0956,12.0412 17.5593,12.5049 18.126,12.5049 18.6928,12.5049 19.1565,12.0412 19.1565,11.4745L19.1565,10.8128C19.1834,10.7399 19.2266,10.6727 19.2801,10.6192 19.4759,10.4234 19.8159,10.4234 20.0117,10.6192 20.1148,10.712 20.1663,10.8459 20.1663,10.9799L20.1663,15.6169C20.1663,16.9977 19.6408,18.296 18.6618,19.2647 17.6829,20.2333 16.3949,20.7691 15.0141,20.7691L13.1593,20.7691C12.3143,20.7691 11.4796,20.5527 10.7274,20.1509 9.98548,19.749 9.3363,19.1616 8.8726,18.4506L8.66651,18.1415C8.35737,17.6675 7.23419,15.7096 5.31756,12.2988 5.24543,12.1752 5.23512,12.0412 5.26604,11.9073 5.30725,11.7733 5.38969,11.6703 5.50304,11.5981 5.66791,11.4951 5.874,11.4539 6.06978,11.4745 6.26557,11.5054 6.45105,11.5878 6.59531,11.7321L8.11007,13.2469C8.49419,13.631 9.10425,13.648 9.50833,13.2978 9.73651,13.1084 9.88244,12.8229 9.88244,12.5049L9.88244,3.74613C9.88244,3.61217,9.94426,3.47821,10.037,3.38547z M2.99905,6.31195L1.78313,4.65293 2.61779,4.04497C3.46275,3.4267,4.37985,2.89087,5.33817,2.46838L6.27587,2.0459 7.12084,3.93162 6.18313,4.3541C5.35878,4.72506,4.56533,5.17846,3.83372,5.71429L2.99905,6.32225 2.99905,6.31195z M18.2806,5.20935L19.1565,5.75549 20.259,4.01404 19.3831,3.4679C18.1157,2.67446,16.7452,2.0768,15.3026,1.68523L14.303,1.41731 13.7672,3.40607 14.7667,3.67399C16.0033,4.00373,17.1883,4.51895,18.2806,5.20935z" ButtonMouseUp="TwoFingerGestureBorder_MouseUp" /> - - - - - - - - - - - + + - - - - + - - - - - - - - - - - - + - - - - - - - - - - + @@ -1244,119 +1197,74 @@ Label="{i18n:I18n Key=Board_Pen}" IconGeometry="F1 M24,24z M0,0z M20.4786,1.42438C19.9985,1.23743 19.4847,1.15194 18.9698,1.17319 18.4549,1.19444 17.9499,1.32197 17.4869,1.54789 17.0368,1.76752 16.6358,2.07554 16.3083,2.45361L3.85516,14.9067 9.08243,20.134 21.5311,7.68529C21.9113,7.36382 22.223,6.96912 22.447,6.52438 22.6786,6.06462 22.8113,5.56167 22.8365,5.04763 22.8616,4.5336 22.7787,4.02012 22.593,3.54002 22.4073,3.05994 22.1232,2.62403 21.759,2.25988 21.3949,1.89574 20.9587,1.61132 20.4786,1.42438z M7.28056,21.1605L2.8286,16.7086 1.15912,22.83 7.28056,21.1605z" ButtonMouseUp="PenIcon_Click" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + - - - - - + - - - - - - - - - - - + CloseMouseDown="Border_MouseDown" + CloseMouseUp="CloseBordertools_MouseUp"> - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - + + @@ -1991,7 +1861,7 @@ - @@ -2026,10 +1896,7 @@ - - - - + - - - - - - - - - - - - - - - - - - - - + + + \ No newline at end of file