From 2d40b03334e65d337a7cedbf41af112bdf32ab8e Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Wed, 25 Mar 2020 23:14:55 +0800 Subject: [PATCH 1/6] add SimpleText --- src/HandyControl.sln | 2 + .../Controls/Text/OutlineText.cs | 37 +-- .../Controls/Text/SimpleText.cs | 248 ++++++++++++++++++ .../HandyControl_Shared.projitems | 1 + 4 files changed, 273 insertions(+), 15 deletions(-) create mode 100644 src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs diff --git a/src/HandyControl.sln b/src/HandyControl.sln index 1154962f..5040fb3e 100644 --- a/src/HandyControl.sln +++ b/src/HandyControl.sln @@ -34,7 +34,9 @@ Global Shared\HandyControl_Shared\HandyControl_Shared.projitems*{32204503-2ef0-4681-ae13-aa1feb6c658a}*SharedItemsImports = 4 Shared\HandyControlDemo_Shared\HandyControlDemo_Shared.projitems*{9a7b52e6-94bb-4e7e-bb6a-7cf6761b79a7}*SharedItemsImports = 4 Shared\HandyControl_Shared\HandyControl_Shared.projitems*{aac11083-faca-405d-9197-5c1212d65656}*SharedItemsImports = 13 + Shared\HandyControl_Shared\HandyControl_Shared.projitems*{be4a567d-b6e0-413e-8f64-e1a53b4f9366}*SharedItemsImports = 5 Shared\HandyControlDemo_Shared\HandyControlDemo_Shared.projitems*{c4694269-c9b8-45d5-87f8-d0088c532510}*SharedItemsImports = 13 + Shared\HandyControlDemo_Shared\HandyControlDemo_Shared.projitems*{d7107690-8592-4f9f-9379-9b82c1c15d2a}*SharedItemsImports = 5 Shared\HandyControlDemo_Shared\HandyControlDemo_Shared.projitems*{d8ae88f8-c36b-4d10-a7f9-22ffcfba5231}*SharedItemsImports = 4 Shared\HandyControl_Shared\HandyControl_Shared.projitems*{dc966e3d-bcff-4652-98cf-070e5494749a}*SharedItemsImports = 4 EndGlobalSection diff --git a/src/Shared/HandyControl_Shared/Controls/Text/OutlineText.cs b/src/Shared/HandyControl_Shared/Controls/Text/OutlineText.cs index 038480de..abc6a971 100644 --- a/src/Shared/HandyControl_Shared/Controls/Text/OutlineText.cs +++ b/src/Shared/HandyControl_Shared/Controls/Text/OutlineText.cs @@ -155,24 +155,31 @@ namespace HandyControl.Controls protected override void OnRender(DrawingContext drawingContext) { - EnsureGeometry(); - - drawingContext.DrawGeometry(Fill, null, _textGeometry); - - if (StrokePosition == StrokePosition.Outside) + if (StrokeThickness > 0) { - drawingContext.PushClip(_clipGeometry); + EnsureGeometry(); + + drawingContext.DrawGeometry(Fill, null, _textGeometry); + + if (StrokePosition == StrokePosition.Outside) + { + drawingContext.PushClip(_clipGeometry); + } + else if (StrokePosition == StrokePosition.Inside) + { + drawingContext.PushClip(_textGeometry); + } + + drawingContext.DrawGeometry(null, _pen, _textGeometry); + + if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside) + { + drawingContext.Pop(); + } } - else if (StrokePosition == StrokePosition.Inside) + else { - drawingContext.PushClip(_textGeometry); - } - - drawingContext.DrawGeometry(null, _pen, _textGeometry); - - if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside) - { - drawingContext.Pop(); + drawingContext.DrawText(_formattedText, new Point()); } } diff --git a/src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs b/src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs new file mode 100644 index 00000000..f8f873ba --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs @@ -0,0 +1,248 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Media; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + public class SimpleText : FrameworkElement + { + private Pen _pen; + + private FormattedText _formattedText; + + static SimpleText() + { + SnapsToDevicePixelsProperty.OverrideMetadata(typeof(SimpleText), new FrameworkPropertyMetadata(ValueBoxes.TrueBox)); + UseLayoutRoundingProperty.OverrideMetadata(typeof(SimpleText), new FrameworkPropertyMetadata(ValueBoxes.TrueBox)); + } + + public static readonly DependencyProperty StrokePositionProperty = DependencyProperty.Register( + "StrokePosition", typeof(StrokePosition), typeof(SimpleText), new PropertyMetadata(default(StrokePosition))); + + public StrokePosition StrokePosition + { + get => (StrokePosition)GetValue(StrokePositionProperty); + set => SetValue(StrokePositionProperty, value); + } + + public static readonly DependencyProperty TextProperty = DependencyProperty.Register( + "Text", typeof(string), typeof(SimpleText), new FrameworkPropertyMetadata( + string.Empty, + FrameworkPropertyMetadataOptions.AffectsMeasure | + FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated)); + + public string Text + { + get => (string)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register( + "TextAlignment", typeof(TextAlignment), typeof(SimpleText), + new PropertyMetadata(default(TextAlignment), OnFormattedTextUpdated)); + + public TextAlignment TextAlignment + { + get => (TextAlignment)GetValue(TextAlignmentProperty); + set => SetValue(TextAlignmentProperty, value); + } + + public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register( + "TextTrimming", typeof(TextTrimming), typeof(SimpleText), + new PropertyMetadata(default(TextTrimming), OnFormattedTextInvalidated)); + + public TextTrimming TextTrimming + { + get => (TextTrimming)GetValue(TextTrimmingProperty); + set => SetValue(TextTrimmingProperty, value); + } + + public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register( + "TextWrapping", typeof(TextWrapping), typeof(SimpleText), + new PropertyMetadata(TextWrapping.NoWrap, OnFormattedTextInvalidated)); + + public TextWrapping TextWrapping + { + get => (TextWrapping)GetValue(TextWrappingProperty); + set => SetValue(TextWrappingProperty, value); + } + + public static readonly DependencyProperty FillProperty = DependencyProperty.Register( + "Fill", typeof(Brush), typeof(SimpleText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated)); + + public Brush Fill + { + get => (Brush)GetValue(FillProperty); + set => SetValue(FillProperty, value); + } + + public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register( + "Stroke", typeof(Brush), typeof(SimpleText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated)); + + public Brush Stroke + { + get => (Brush)GetValue(StrokeProperty); + set => SetValue(StrokeProperty, value); + } + + public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( + "StrokeThickness", typeof(double), typeof(SimpleText), new PropertyMetadata(ValueBoxes.Double0Box, OnFormattedTextUpdated)); + + public double StrokeThickness + { + get => (double)GetValue(StrokeThicknessProperty); + set => SetValue(StrokeThicknessProperty, value); + } + + public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner( + typeof(SimpleText), + new FrameworkPropertyMetadata(OnFormattedTextUpdated)); + + public FontFamily FontFamily + { + get => (FontFamily)GetValue(FontFamilyProperty); + set => SetValue(FontFamilyProperty, value); + } + + public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner( + typeof(SimpleText), + new FrameworkPropertyMetadata(OnFormattedTextUpdated)); + + [TypeConverter(typeof(FontSizeConverter))] + public double FontSize + { + get => (double)GetValue(FontSizeProperty); + set => SetValue(FontSizeProperty, value); + } + + public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner( + typeof(SimpleText), + new FrameworkPropertyMetadata(OnFormattedTextUpdated)); + + public FontStretch FontStretch + { + get => (FontStretch)GetValue(FontStretchProperty); + set => SetValue(FontStretchProperty, value); + } + + public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner( + typeof(SimpleText), + new FrameworkPropertyMetadata(OnFormattedTextUpdated)); + + public FontStyle FontStyle + { + get => (FontStyle)GetValue(FontStyleProperty); + set => SetValue(FontStyleProperty, value); + } + + public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner( + typeof(SimpleText), + new FrameworkPropertyMetadata(OnFormattedTextUpdated)); + + public FontWeight FontWeight + { + get => (FontWeight)GetValue(FontWeightProperty); + set => SetValue(FontWeightProperty, value); + } + + protected override void OnRender(DrawingContext drawingContext) => drawingContext.DrawText(_formattedText, new Point()); + + private void UpdatePen() + { + _pen = new Pen(Stroke, StrokeThickness); + + if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside) + { + _pen.Thickness = StrokeThickness * 2; + } + } + + private void EnsureFormattedText() + { + if (_formattedText != null || Text == null) + { + return; + } + +#if netle45 + _formattedText = new FormattedText( + Text, + CultureInfo.CurrentUICulture, + FlowDirection, + new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), + FontSize, Fill); +#else + var source = PresentationSource.FromVisual(this); + var dpi = 1.0; + if (source?.CompositionTarget != null) + { + dpi = 96.0 * source.CompositionTarget.TransformToDevice.M11 / 96.0; + } + _formattedText = new FormattedText( + Text, + CultureInfo.CurrentUICulture, + FlowDirection, + new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), + FontSize, Fill, dpi); +#endif + + UpdateFormattedText(); + } + + private void UpdateFormattedText() + { + if (_formattedText == null) + { + return; + } + + _formattedText.MaxLineCount = TextWrapping == TextWrapping.NoWrap ? 1 : int.MaxValue; + _formattedText.TextAlignment = TextAlignment; + _formattedText.Trimming = TextTrimming; + + _formattedText.SetFontSize(FontSize); + _formattedText.SetFontStyle(FontStyle); + _formattedText.SetFontWeight(FontWeight); + _formattedText.SetFontFamily(FontFamily); + _formattedText.SetFontStretch(FontStretch); + } + + private static void OnFormattedTextUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var outlinedTextBlock = (SimpleText)d; + outlinedTextBlock.UpdateFormattedText(); + + outlinedTextBlock.InvalidateMeasure(); + outlinedTextBlock.InvalidateVisual(); + } + + private static void OnFormattedTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var outlinedTextBlock = (SimpleText)d; + outlinedTextBlock._formattedText = null; + + outlinedTextBlock.InvalidateMeasure(); + outlinedTextBlock.InvalidateVisual(); + } + + protected override Size MeasureOverride(Size availableSize) + { + EnsureFormattedText(); + + // constrain the formatted text according to the available size + // the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions + // the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw + _formattedText.MaxTextWidth = Math.Min(3579139, availableSize.Width); + _formattedText.MaxTextHeight = Math.Max(0.0001d, availableSize.Height); + + UpdatePen(); + + // return the desired size + return new Size(_formattedText.Width, _formattedText.Height); + } + } +} \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index a78fba08..1ec85042 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -44,6 +44,7 @@ + From 008fa6689ed7c4b2d7539709b54f827ce487dcd4 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Thu, 26 Mar 2020 23:50:02 +0800 Subject: [PATCH 2/6] fixed a bug of TabControl --- src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs b/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs index c001fb30..c0aa5600 100644 --- a/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs +++ b/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs @@ -251,6 +251,8 @@ namespace HandyControl.Controls protected override void OnMouseRightButtonDown(MouseButtonEventArgs e) { base.OnMouseRightButtonDown(e); + + if (VisualTreeHelper.HitTest(this, e.GetPosition(this)) == null) return; IsSelected = true; Focus(); } @@ -293,6 +295,7 @@ namespace HandyControl.Controls { base.OnMouseLeftButtonDown(e); + if (VisualTreeHelper.HitTest(this, e.GetPosition(this)) == null) return; var parent = TabControlParent; if (parent == null) return; From 31ee8e91f2f0faf77db8dd0108d4aa0e973c41df Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Fri, 27 Mar 2020 00:37:25 +0800 Subject: [PATCH 3/6] update SimpleText --- src/HandyControl.sln | 20 ------- .../Controls/Text/SimpleText.cs | 59 +++---------------- 2 files changed, 7 insertions(+), 72 deletions(-) diff --git a/src/HandyControl.sln b/src/HandyControl.sln index 5040fb3e..45fa85fc 100644 --- a/src/HandyControl.sln +++ b/src/HandyControl.sln @@ -106,57 +106,37 @@ Global {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Core31|Any CPU.ActiveCfg = Debug-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Core31|Any CPU.Build.0 = Debug-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net40|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net40|Any CPU.Build.0 = Debug-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net45|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net45|Any CPU.Build.0 = Debug-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net462|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net462|Any CPU.Build.0 = Debug-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net47|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net47|Any CPU.Build.0 = Debug-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net48|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Debug-Net48|Any CPU.Build.0 = Debug-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Core30|Any CPU.ActiveCfg = Release-Core30|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Core30|Any CPU.Build.0 = Release-Core30|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Core31|Any CPU.ActiveCfg = Release-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Core31|Any CPU.Build.0 = Release-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net40|Any CPU.ActiveCfg = Release-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net40|Any CPU.Build.0 = Release-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net45|Any CPU.ActiveCfg = Release-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net45|Any CPU.Build.0 = Release-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net462|Any CPU.ActiveCfg = Release-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net462|Any CPU.Build.0 = Release-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net47|Any CPU.ActiveCfg = Release-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net47|Any CPU.Build.0 = Release-Core31|Any CPU {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net48|Any CPU.ActiveCfg = Release-Core31|Any CPU - {BE4A567D-B6E0-413E-8F64-E1A53B4F9366}.Release-Net48|Any CPU.Build.0 = Release-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Core30|Any CPU.ActiveCfg = Debug-Core30|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Core30|Any CPU.Build.0 = Debug-Core30|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Core31|Any CPU.ActiveCfg = Debug-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Core31|Any CPU.Build.0 = Debug-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net40|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net40|Any CPU.Build.0 = Debug-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net45|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net45|Any CPU.Build.0 = Debug-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net462|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net462|Any CPU.Build.0 = Debug-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net47|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net47|Any CPU.Build.0 = Debug-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net48|Any CPU.ActiveCfg = Debug-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Debug-Net48|Any CPU.Build.0 = Debug-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Core30|Any CPU.ActiveCfg = Release-Core30|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Core30|Any CPU.Build.0 = Release-Core30|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Core31|Any CPU.ActiveCfg = Release-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Core31|Any CPU.Build.0 = Release-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net40|Any CPU.ActiveCfg = Release-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net40|Any CPU.Build.0 = Release-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net45|Any CPU.ActiveCfg = Release-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net45|Any CPU.Build.0 = Release-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net462|Any CPU.ActiveCfg = Release-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net462|Any CPU.Build.0 = Release-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net47|Any CPU.ActiveCfg = Release-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net47|Any CPU.Build.0 = Release-Core31|Any CPU {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net48|Any CPU.ActiveCfg = Release-Core31|Any CPU - {D7107690-8592-4F9F-9379-9B82C1C15D2A}.Release-Net48|Any CPU.Build.0 = Release-Core31|Any CPU {32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Core30|Any CPU.ActiveCfg = Debug|Any CPU {32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Core31|Any CPU.ActiveCfg = Debug|Any CPU {32204503-2EF0-4681-AE13-AA1FEB6C658A}.Debug-Net40|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs b/src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs index f8f873ba..84830748 100644 --- a/src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs +++ b/src/Shared/HandyControl_Shared/Controls/Text/SimpleText.cs @@ -10,8 +10,6 @@ namespace HandyControl.Controls { public class SimpleText : FrameworkElement { - private Pen _pen; - private FormattedText _formattedText; static SimpleText() @@ -20,15 +18,6 @@ namespace HandyControl.Controls UseLayoutRoundingProperty.OverrideMetadata(typeof(SimpleText), new FrameworkPropertyMetadata(ValueBoxes.TrueBox)); } - public static readonly DependencyProperty StrokePositionProperty = DependencyProperty.Register( - "StrokePosition", typeof(StrokePosition), typeof(SimpleText), new PropertyMetadata(default(StrokePosition))); - - public StrokePosition StrokePosition - { - get => (StrokePosition)GetValue(StrokePositionProperty); - set => SetValue(StrokePositionProperty, value); - } - public static readonly DependencyProperty TextProperty = DependencyProperty.Register( "Text", typeof(string), typeof(SimpleText), new FrameworkPropertyMetadata( string.Empty, @@ -71,31 +60,13 @@ namespace HandyControl.Controls set => SetValue(TextWrappingProperty, value); } - public static readonly DependencyProperty FillProperty = DependencyProperty.Register( - "Fill", typeof(Brush), typeof(SimpleText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated)); + public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register( + "Foreground", typeof(Brush), typeof(SimpleText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated)); - public Brush Fill + public Brush Foreground { - get => (Brush)GetValue(FillProperty); - set => SetValue(FillProperty, value); - } - - public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register( - "Stroke", typeof(Brush), typeof(SimpleText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated)); - - public Brush Stroke - { - get => (Brush)GetValue(StrokeProperty); - set => SetValue(StrokeProperty, value); - } - - public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( - "StrokeThickness", typeof(double), typeof(SimpleText), new PropertyMetadata(ValueBoxes.Double0Box, OnFormattedTextUpdated)); - - public double StrokeThickness - { - get => (double)GetValue(StrokeThicknessProperty); - set => SetValue(StrokeThicknessProperty, value); + get => (Brush) GetValue(ForegroundProperty); + set => SetValue(ForegroundProperty, value); } public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner( @@ -151,16 +122,6 @@ namespace HandyControl.Controls protected override void OnRender(DrawingContext drawingContext) => drawingContext.DrawText(_formattedText, new Point()); - private void UpdatePen() - { - _pen = new Pen(Stroke, StrokeThickness); - - if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside) - { - _pen.Thickness = StrokeThickness * 2; - } - } - private void EnsureFormattedText() { if (_formattedText != null || Text == null) @@ -174,7 +135,7 @@ namespace HandyControl.Controls CultureInfo.CurrentUICulture, FlowDirection, new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), - FontSize, Fill); + FontSize, Foreground); #else var source = PresentationSource.FromVisual(this); var dpi = 1.0; @@ -187,7 +148,7 @@ namespace HandyControl.Controls CultureInfo.CurrentUICulture, FlowDirection, new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), - FontSize, Fill, dpi); + FontSize, Foreground, dpi); #endif UpdateFormattedText(); @@ -233,15 +194,9 @@ namespace HandyControl.Controls { EnsureFormattedText(); - // constrain the formatted text according to the available size - // the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions - // the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw _formattedText.MaxTextWidth = Math.Min(3579139, availableSize.Width); _formattedText.MaxTextHeight = Math.Max(0.0001d, availableSize.Height); - UpdatePen(); - - // return the desired size return new Size(_formattedText.Width, _formattedText.Height); } } From b7222be265a47d817189e1c2178879b6c524944d Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sat, 28 Mar 2020 14:27:13 +0800 Subject: [PATCH 4/6] update StepBar & readme --- README.md | 3 +- .../UserControl/Controls/StepBarDemoCtl.xaml | 2 +- .../Controls/StepBarDemoViewModel.cs | 12 ++ .../Controls/StepBar/StepBar.cs | 117 ++++++++++-------- 4 files changed, 81 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index ff539909..02b72924 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ [https://handyorg.github.io/handycontrol/](https://handyorg.github.io/handycontrol/) ### 赞助 -如果您觉得HandyControl还不错,并且刚好有些闲钱,那么可以选择以下两种方式来赞助: +如果您觉得HandyControl还不错,并且刚好有些闲钱,那么可以选择以下两种方式来赞助(记得入群联系我们呀~~): * [以HandyControl的名义为慈善事业做贡献](http://www.chinacharityfederation.org/ConfirmDonation/0.html?zhijie=3) @@ -54,6 +54,7 @@ + ## Special thanks to diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/StepBarDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/StepBarDemoCtl.xaml index dbce1495..0c230a0b 100644 --- a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/StepBarDemoCtl.xaml +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/StepBarDemoCtl.xaml @@ -18,7 +18,7 @@ - + diff --git a/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/StepBarDemoViewModel.cs b/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/StepBarDemoViewModel.cs index 8c2032c1..49d03a53 100644 --- a/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/StepBarDemoViewModel.cs +++ b/src/Shared/HandyControlDemo_Shared/ViewModel/Controls/StepBarDemoViewModel.cs @@ -16,6 +16,18 @@ namespace HandyControlDemo.ViewModel { public StepBarDemoViewModel(DataService dataService) => DataList = dataService.GetStepBarDemoDataList(); + private int _stepIndex; + + public int StepIndex + { + get => _stepIndex; +#if netle40 + set => Set(nameof(StepIndex), ref _stepIndex, value); +#else + set => Set(ref _stepIndex, value); +#endif + } + /// /// 下一步 /// diff --git a/src/Shared/HandyControl_Shared/Controls/StepBar/StepBar.cs b/src/Shared/HandyControl_Shared/Controls/StepBar/StepBar.cs index 4a085542..e4f7396c 100644 --- a/src/Shared/HandyControl_Shared/Controls/StepBar/StepBar.cs +++ b/src/Shared/HandyControl_Shared/Controls/StepBar/StepBar.cs @@ -18,6 +18,8 @@ namespace HandyControl.Controls { private ProgressBar _progressBarBack; + private int _oriStepIndex = -1; + #region Constants private const string ElementProgressBarBack = "PART_ProgressBarBack"; @@ -46,19 +48,14 @@ namespace HandyControl.Controls } } - if (StepIndex < count) + if (_oriStepIndex > 0) { - for (var i = 0; i < StepIndex; i++) - { - if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepBarItem) - { - stepBarItem.Status = StepStatus.Complete; - } - } - if (ItemContainerGenerator.ContainerFromIndex(StepIndex) is StepBarItem item) - { - item.Status = StepStatus.UnderWay; - } + StepIndex = _oriStepIndex; + _oriStepIndex = -1; + } + else + { + OnStepIndexChanged(StepIndex); } } } @@ -85,12 +82,64 @@ namespace HandyControl.Controls } public static readonly DependencyProperty StepIndexProperty = DependencyProperty.Register( - "StepIndex", typeof(int), typeof(StepBar), new PropertyMetadata(ValueBoxes.Int0Box)); + "StepIndex", typeof(int), typeof(StepBar), new FrameworkPropertyMetadata(ValueBoxes.Int0Box, + FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnStepIndexChanged, CoerceStepIndex)); + + private static object CoerceStepIndex(DependencyObject d, object basevalue) + { + var ctl = (StepBar)d; + var stepIndex = (int) basevalue; + if (ctl.Items.Count == 0 && stepIndex > 0) + { + ctl._oriStepIndex = stepIndex; + return ValueBoxes.Int0Box; + } + + return stepIndex < 0 + ? ValueBoxes.Int0Box + : stepIndex >= ctl.Items.Count + ? ctl.Items.Count == 0 ? 0 : ctl.Items.Count - 1 + : basevalue; + } + + private static void OnStepIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ctl = (StepBar) d; + ctl.OnStepIndexChanged((int)e.NewValue); + } + + private void OnStepIndexChanged(int stepIndex) + { + for (var i = 0; i < stepIndex; i++) + { + if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepItemFinished) + { + stepItemFinished.Status = StepStatus.Complete; + } + } + + for (var i = stepIndex + 1; i < Items.Count; i++) + { + if (ItemContainerGenerator.ContainerFromIndex(i) is StepBarItem stepItemFinished) + { + stepItemFinished.Status = StepStatus.Waiting; + } + } + + if (ItemContainerGenerator.ContainerFromIndex(stepIndex) is StepBarItem stepItemSelected) + stepItemSelected.Status = StepStatus.UnderWay; + _progressBarBack?.BeginAnimation(RangeBase.ValueProperty, AnimationHelper.CreateAnimation(stepIndex)); + + RaiseEvent(new FunctionEventArgs(StepChangedEvent, this) + { + Info = stepIndex + }); + } public int StepIndex { - get => (int)GetValue(StepIndexProperty); - protected set => SetValue(StepIndexProperty, value); + get => (int)GetValue(StepIndexProperty); + set => SetValue(StepIndexProperty, value); } public static readonly DependencyProperty DockProperty = DependencyProperty.Register( @@ -128,42 +177,8 @@ namespace HandyControl.Controls } } - public void Next() - { - StepIndex++; - if (StepIndex >= Items.Count) - { - StepIndex = Items.Count - 1; - return; - } - RaiseEvent(new FunctionEventArgs(StepChangedEvent, this) - { - Info = StepIndex - }); - if (ItemContainerGenerator.ContainerFromIndex(StepIndex - 1) is StepBarItem stepItemFinished) - stepItemFinished.Status = StepStatus.Complete; - if (ItemContainerGenerator.ContainerFromIndex(StepIndex) is StepBarItem stepItemSelected) - stepItemSelected.Status = StepStatus.UnderWay; - _progressBarBack?.BeginAnimation(RangeBase.ValueProperty, AnimationHelper.CreateAnimation(StepIndex)); - } + public void Next() => StepIndex++; - public void Prev() - { - StepIndex--; - if (StepIndex < 0) - { - StepIndex = 0; - return; - } - RaiseEvent(new FunctionEventArgs(StepChangedEvent, this) - { - Info = StepIndex - }); - if (ItemContainerGenerator.ContainerFromIndex(StepIndex + 1) is StepBarItem stepItemWaiting) - stepItemWaiting.Status = StepStatus.Waiting; - if (ItemContainerGenerator.ContainerFromIndex(StepIndex) is StepBarItem stepItemSelected) - stepItemSelected.Status = StepStatus.UnderWay; - _progressBarBack?.BeginAnimation(RangeBase.ValueProperty, AnimationHelper.CreateAnimation(StepIndex)); - } + public void Prev() => StepIndex--; } } \ No newline at end of file From aec26ea5bec407e99bff74c402fccd71200b510f Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sun, 29 Mar 2020 00:54:44 +0800 Subject: [PATCH 5/6] optimized menu style --- .../Controls/Attach/MenuTopLineAttach.cs | 99 +++++++++++++++++++ .../HandyControl_Shared.projitems | 1 + .../Themes/Styles/Base/MenuBaseStyle.xaml | 5 +- .../Converter/TreeViewItemMarginConverter.cs | 1 - .../Tools/Helper/VisualHelper.cs | 25 ++--- 5 files changed, 116 insertions(+), 15 deletions(-) create mode 100644 src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs diff --git a/src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs b/src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs new file mode 100644 index 00000000..81be40a2 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs @@ -0,0 +1,99 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using HandyControl.Tools; +using HandyControl.Tools.Interop; + +namespace HandyControl.Controls +{ + public class MenuTopLineAttach + { + public static readonly DependencyProperty PopupProperty = DependencyProperty.RegisterAttached( + "Popup", typeof(Popup), typeof(MenuTopLineAttach), new PropertyMetadata(default(Popup), OnPopupChanged)); + + private static void OnPopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var topLine = (FrameworkElement) d; + + if (e.NewValue is Popup popup) + { + if (popup.TemplatedParent is MenuItem menuItem) + { + SetTopLine(menuItem, topLine); + menuItem.Unloaded += MenuItem_Unloaded; + } + popup.Opened += Popup_Opened; + } + } + + private static void MenuItem_Unloaded(object sender, RoutedEventArgs e) + { + var menuItem = (FrameworkElement)sender; + menuItem.Unloaded -= MenuItem_Unloaded; + var topLine = GetTopLine(menuItem); + var popup = GetPopup(topLine); + if (popup != null) + { + popup.Opened -= Popup_Opened; + } + } + + private static void Popup_Opened(object sender, EventArgs e) + { + var popup = (Popup) sender; + if (popup.TemplatedParent is MenuItem menuItem) + { + var topLine = GetTopLine(menuItem); + if (topLine == null) return; + + topLine.HorizontalAlignment = HorizontalAlignment.Left; + topLine.Width = menuItem.ActualWidth; + topLine.Margin = new Thickness(); + + var positionLeftTop = menuItem.PointToScreen(new Point()); + var positionRightBottom = menuItem.PointToScreen(new Point(menuItem.ActualWidth, menuItem.ActualHeight)); + ScreenHelper.FindMonitorRectsFromPoint(InteropMethods.GetCursorPos(), out _, out var workAreaRect); + var panel = VisualHelper.GetParent(topLine); + + if (positionLeftTop.X < 0) + { + + topLine.Margin = new Thickness(positionLeftTop.X - panel.Margin.Left, 0, 0, 0); + } + else if (positionLeftTop.X + panel.ActualWidth > workAreaRect.Right) + { + var overflowWidth = positionRightBottom.X - workAreaRect.Right; + if (overflowWidth > 0) + { + topLine.Width -= overflowWidth + panel.Margin.Right; + } + topLine.HorizontalAlignment = HorizontalAlignment.Left; + topLine.Margin = new Thickness(positionLeftTop.X + panel.ActualWidth - workAreaRect.Right + panel.Margin.Right, 0, 0, 0); + } + + if (positionRightBottom.Y > workAreaRect.Bottom) + { + topLine.Width = 0; + topLine.HorizontalAlignment = HorizontalAlignment.Stretch; + topLine.Margin = new Thickness(); + } + } + } + + public static void SetPopup(DependencyObject element, Popup value) + => element.SetValue(PopupProperty, value); + + public static Popup GetPopup(DependencyObject element) + => (Popup) element.GetValue(PopupProperty); + + internal static readonly DependencyProperty TopLineProperty = DependencyProperty.RegisterAttached( + "TopLine", typeof(FrameworkElement), typeof(MenuTopLineAttach), new PropertyMetadata(default(FrameworkElement))); + + internal static void SetTopLine(DependencyObject element, FrameworkElement value) + => element.SetValue(TopLineProperty, value); + + internal static FrameworkElement GetTopLine(DependencyObject element) + => (FrameworkElement) element.GetValue(TopLineProperty); + } +} diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 1ec85042..cf7a8042 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -17,6 +17,7 @@ + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml index bd7b0652..4bc5ed76 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml @@ -3,6 +3,7 @@ xmlns:controls="clr-namespace:HandyControl.Controls"> + @@ -64,13 +65,13 @@ - + - + diff --git a/src/Shared/HandyControl_Shared/Tools/Converter/TreeViewItemMarginConverter.cs b/src/Shared/HandyControl_Shared/Tools/Converter/TreeViewItemMarginConverter.cs index b8872602..a6bbd3e7 100644 --- a/src/Shared/HandyControl_Shared/Tools/Converter/TreeViewItemMarginConverter.cs +++ b/src/Shared/HandyControl_Shared/Tools/Converter/TreeViewItemMarginConverter.cs @@ -8,7 +8,6 @@ namespace HandyControl.Tools.Converter { public class TreeViewItemMarginConverter: IValueConverter { - public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var left = 0.0; diff --git a/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs b/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs index b6351478..84a088e1 100644 --- a/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs +++ b/src/Shared/HandyControl_Shared/Tools/Helper/VisualHelper.cs @@ -20,12 +20,10 @@ namespace HandyControl.Tools .FirstOrDefault(group => string.CompareOrdinal(groupName, group.Name) == 0); } - internal static FrameworkElement GetImplementationRoot(DependencyObject d) - { - return 1 == VisualTreeHelper.GetChildrenCount(d) + internal static FrameworkElement GetImplementationRoot(DependencyObject d) => + 1 == VisualTreeHelper.GetChildrenCount(d) ? VisualTreeHelper.GetChild(d, 0) as FrameworkElement : null; - } public static T GetChild(DependencyObject d) where T : DependencyObject { @@ -42,16 +40,19 @@ namespace HandyControl.Tools return default; } - public static IntPtr GetHandle(this Visual visual) - { - return (PresentationSource.FromVisual(visual) as HwndSource)?.Handle ?? IntPtr.Zero; - } + public static T GetParent(DependencyObject d) where T : DependencyObject => + d switch + { + null => default, + T t => t, + Window _ => null, + _ => GetParent(VisualTreeHelper.GetParent(d)) + }; - internal static void HitTestVisibleElements(Visual visual, HitTestResultCallback resultCallback, - HitTestParameters parameters) - { + public static IntPtr GetHandle(this Visual visual) => (PresentationSource.FromVisual(visual) as HwndSource)?.Handle ?? IntPtr.Zero; + + internal static void HitTestVisibleElements(Visual visual, HitTestResultCallback resultCallback, HitTestParameters parameters) => VisualTreeHelper.HitTest(visual, ExcludeNonVisualElements, resultCallback, parameters); - } private static HitTestFilterBehavior ExcludeNonVisualElements(DependencyObject potentialHitTestTarget) { From efa05191dac9eb9c97e9adeca385a327f5180533 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sun, 29 Mar 2020 20:02:42 +0800 Subject: [PATCH 6/6] completed the missing code --- src/Shared/HandyControlDemo_Shared/App.xaml.cs | 2 ++ .../Controls/Attach/MenuTopLineAttach.cs | 15 +++++++++++++-- .../Themes/Styles/Base/ContextMenuBaseStyle.xaml | 3 ++- .../Themes/Styles/Base/MenuBaseStyle.xaml | 4 ++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Shared/HandyControlDemo_Shared/App.xaml.cs b/src/Shared/HandyControlDemo_Shared/App.xaml.cs index 05d65336..1eb7fa4f 100644 --- a/src/Shared/HandyControlDemo_Shared/App.xaml.cs +++ b/src/Shared/HandyControlDemo_Shared/App.xaml.cs @@ -71,6 +71,8 @@ namespace HandyControlDemo } ConfigHelper.Instance.SetSystemVersionInfo(CommonHelper.GetSystemVersionInfo()); + ConfigHelper.Instance.SetWindowDefaultStyle(); + ConfigHelper.Instance.SetNavigationWindowDefaultStyle(); ServicePointManager.SecurityProtocol = (SecurityProtocolType)(SslProtocols)0x00000C00; } diff --git a/src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs b/src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs index 81be40a2..5d6cd18f 100644 --- a/src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs +++ b/src/Shared/HandyControl_Shared/Controls/Attach/MenuTopLineAttach.cs @@ -21,8 +21,19 @@ namespace HandyControl.Controls if (popup.TemplatedParent is MenuItem menuItem) { SetTopLine(menuItem, topLine); - menuItem.Unloaded += MenuItem_Unloaded; - } + menuItem.Loaded += MenuItem_Loaded; + } + } + } + + private static void MenuItem_Loaded(object sender, RoutedEventArgs e) + { + var menuItem = (FrameworkElement)sender; + menuItem.Unloaded += MenuItem_Unloaded; + var topLine = GetTopLine(menuItem); + var popup = GetPopup(topLine); + if (popup != null) + { popup.Opened += Popup_Opened; } } diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/ContextMenuBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/ContextMenuBaseStyle.xaml index 367c0b7f..85f1d0e6 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Base/ContextMenuBaseStyle.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/ContextMenuBaseStyle.xaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + @@ -11,7 +12,7 @@ - + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml index 4bc5ed76..d9d3be29 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/MenuBaseStyle.xaml @@ -167,7 +167,7 @@ - + @@ -185,7 +185,7 @@ - +