فهرست منبع

Better fix for #27

Daniel Chalmers 1 سال پیش
والد
کامیت
b5a08c4771
2فایلهای تغییر یافته به همراه65 افزوده شده و 20 حذف شده
  1. 5 4
      DesktopClock/MainWindow.xaml
  2. 60 16
      DesktopClock/OutlinedTextBlock.cs

+ 5 - 4
DesktopClock/MainWindow.xaml

@@ -135,10 +135,7 @@
 				</Style>
 			</Border.Style>
 
-			<local:OutlinedTextBlock HorizontalAlignment="Center"
-			                         Text="{Binding CurrentTimeOrCountdownString}"
-			                         StrokeThickness="{Binding OutlineThickness, Source={x:Static p:Settings.Default}, Mode=OneWay}"
-			                         Margin="{Binding OutlineThickness, Source={x:Static p:Settings.Default}, Mode=OneWay}">
+			<local:OutlinedTextBlock Text="{Binding CurrentTimeOrCountdownString}" StrokeThickness="{Binding OutlineThickness, Source={x:Static p:Settings.Default}, Mode=OneWay}">
 
 				<local:OutlinedTextBlock.Fill>
 					<SolidColorBrush Color="{Binding TextColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
@@ -147,6 +144,8 @@
 				<local:OutlinedTextBlock.Style>
 					<Style TargetType="local:OutlinedTextBlock">
 						<Setter Property="Stroke" Value="Transparent" />
+						<Setter Property="Margin" Value="0" />
+
 						<Style.Triggers>
 							<DataTrigger Binding="{Binding BackgroundEnabled, Source={x:Static p:Settings.Default}, Mode=OneWay}" Value="False">
 								<DataTrigger.Setters>
@@ -155,6 +154,8 @@
 											<SolidColorBrush Color="{Binding OuterColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
 										</Setter.Value>
 									</Setter>
+
+									<Setter Property="Margin" Value="{Binding OutlineThickness, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
 								</DataTrigger.Setters>
 							</DataTrigger>
 						</Style.Triggers>

+ 60 - 16
DesktopClock/OutlinedTextBlock.cs

@@ -8,7 +8,7 @@ using System.Windows.Media;
 
 namespace DesktopClock;
 
-// https://stackoverflow.com/a/35262509
+// https://stackoverflow.com/a/49636033
 [ContentProperty("Text")]
 public class OutlinedTextBlock : FrameworkElement
 {
@@ -22,9 +22,26 @@ public class OutlinedTextBlock : FrameworkElement
             StartLineCap = PenLineCap.Round
         };
 
+        if (StrokePosition is StrokePosition.Outside or StrokePosition.Inside)
+        {
+            _Pen.Thickness = StrokeThickness * 2;
+        }
+
         InvalidateVisual();
     }
 
+    public StrokePosition StrokePosition
+    {
+        get => (StrokePosition)GetValue(StrokePositionProperty);
+        set => SetValue(StrokePositionProperty, value);
+    }
+
+    public static readonly DependencyProperty StrokePositionProperty =
+        DependencyProperty.Register("StrokePosition",
+            typeof(StrokePosition),
+            typeof(OutlinedTextBlock),
+            new FrameworkPropertyMetadata(StrokePosition.Outside, FrameworkPropertyMetadataOptions.AffectsRender));
+
     public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
       "Fill",
       typeof(Brush),
@@ -35,18 +52,13 @@ public class OutlinedTextBlock : FrameworkElement
       "Stroke",
       typeof(Brush),
       typeof(OutlinedTextBlock),
-      new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender, StrokePropertyChangedCallback));
-
-    private static void StrokePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
-    {
-        (dependencyObject as OutlinedTextBlock)?.UpdatePen();
-    }
+      new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));
 
     public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
       "StrokeThickness",
       typeof(double),
       typeof(OutlinedTextBlock),
-      new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsRender, StrokePropertyChangedCallback));
+      new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsRender));
 
     public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(
       typeof(OutlinedTextBlock),
@@ -101,6 +113,7 @@ public class OutlinedTextBlock : FrameworkElement
     private FormattedText _FormattedText;
     private Geometry _TextGeometry;
     private Pen _Pen;
+    private PathGeometry _clipGeometry;
 
     public Brush Fill
     {
@@ -184,15 +197,30 @@ public class OutlinedTextBlock : FrameworkElement
     public OutlinedTextBlock()
     {
         UpdatePen();
-        TextDecorations = new();
+        TextDecorations = [];
     }
 
     protected override void OnRender(DrawingContext drawingContext)
     {
         EnsureGeometry();
 
-        drawingContext.DrawGeometry(null, _Pen, _TextGeometry);
         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 is StrokePosition.Outside or StrokePosition.Inside)
+        {
+            drawingContext.Pop();
+        }
     }
 
     protected override Size MeasureOverride(Size availableSize)
@@ -223,6 +251,7 @@ public class OutlinedTextBlock : FrameworkElement
 
         // need to re-generate the geometry now that the dimensions have changed
         _TextGeometry = null;
+        UpdatePen();
 
         return finalSize;
     }
@@ -257,12 +286,12 @@ public class OutlinedTextBlock : FrameworkElement
 
 #pragma warning disable CS0618 // Type or member is obsolete
         _FormattedText = new FormattedText(
-            Text ?? "",
-            CultureInfo.CurrentUICulture,
-            FlowDirection,
-            new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
-            FontSize,
-            Brushes.Black);
+          Text ?? "",
+          CultureInfo.CurrentUICulture,
+          FlowDirection,
+          new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
+          FontSize,
+          Brushes.Black);
 #pragma warning restore CS0618 // Type or member is obsolete
 
         UpdateFormattedText();
@@ -296,5 +325,20 @@ public class OutlinedTextBlock : FrameworkElement
 
         EnsureFormattedText();
         _TextGeometry = _FormattedText.BuildGeometry(new Point(0, 0));
+
+        if (StrokePosition == StrokePosition.Outside)
+        {
+            // https://stackoverflow.com/questions/93650/apply-stroke-to-a-textblock-in-wpf/35262509#comment106994536_49636033.
+            //var boundsGeo = new RectangleGeometry(new Rect(0, 0, ActualWidth, ActualHeight));
+            var boundsGeo = new RectangleGeometry(new Rect(-(2 * StrokeThickness), -(2 * StrokeThickness), ActualWidth + (4 * StrokeThickness), ActualHeight + (4 * StrokeThickness)));
+            _clipGeometry = Geometry.Combine(boundsGeo, _TextGeometry, GeometryCombineMode.Exclude, null);
+        }
     }
+}
+
+public enum StrokePosition
+{
+    Center,
+    Outside,
+    Inside
 }