Created
March 27, 2025 11:08
-
-
Save CodingOctocat/466ed70eaeb5915d1a23caf706abeb33 to your computer and use it in GitHub Desktop.
WPF/DashedBorder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Data; | |
using System.Windows.Media; | |
using System.Windows.Shapes; | |
/// <summary> | |
/// <see href="https://stackoverflow.com/a/72138376/4380178">How can I achieve a dashed or dotted border in WPF?</see> | |
/// </summary> | |
public class DashedBorder : Border | |
{ | |
public static readonly DependencyProperty DashedBorderBrushProperty = | |
DependencyProperty.Register( | |
nameof(DashedBorderBrush), | |
typeof(Brush), | |
typeof(DashedBorder), | |
new FrameworkPropertyMetadata(null)); | |
public static readonly DependencyProperty StrokeDashArrayProperty = | |
DependencyProperty.Register( | |
nameof(StrokeDashArray), | |
typeof(DoubleCollection), | |
typeof(DashedBorder), | |
new FrameworkPropertyMetadata(EmptyDoubleCollection())); | |
public static readonly DependencyProperty UseDashedBorderProperty = | |
DependencyProperty.Register( | |
nameof(UseDashedBorder), | |
typeof(bool), | |
typeof(DashedBorder), | |
new FrameworkPropertyMetadata(false, OnUseDashedBorderChanged)); | |
private static DoubleCollection? _emptyDoubleCollection; | |
public Brush DashedBorderBrush | |
{ | |
get => (Brush)GetValue(DashedBorderBrushProperty); | |
set => SetValue(DashedBorderBrushProperty, value); | |
} | |
public DoubleCollection StrokeDashArray | |
{ | |
get => (DoubleCollection)GetValue(StrokeDashArrayProperty); | |
set => SetValue(StrokeDashArrayProperty, value); | |
} | |
public bool UseDashedBorder | |
{ | |
get => (bool)GetValue(UseDashedBorderProperty); | |
set => SetValue(UseDashedBorderProperty, value); | |
} | |
private static DoubleCollection EmptyDoubleCollection() | |
{ | |
if (_emptyDoubleCollection == null) | |
{ | |
DoubleCollection doubleCollection = []; | |
doubleCollection.Freeze(); | |
_emptyDoubleCollection = doubleCollection; | |
} | |
return _emptyDoubleCollection; | |
} | |
private static void OnUseDashedBorderChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) | |
{ | |
var dashedBorder = (DashedBorder)target; | |
dashedBorder.UseDashedBorderChanged(); | |
} | |
private VisualBrush CreateDashedBorderBrush() | |
{ | |
var dashedBorderBrush = new VisualBrush(); | |
var grid = new Grid(); | |
var backgroundRectangle = GetBackgroundRectangle(); | |
var dashedRectangle = GetDashedRectangle(); | |
grid.Children.Add(backgroundRectangle); | |
grid.Children.Add(dashedRectangle); | |
dashedBorderBrush.Visual = grid; | |
return dashedBorderBrush; | |
} | |
private Rectangle GetBackgroundRectangle() | |
{ | |
var rectangle = GetBoundRectangle(); | |
rectangle.SetBinding(Rectangle.StrokeProperty, new Binding() { Source = this, Path = new PropertyPath(BackgroundProperty) }); | |
return rectangle; | |
} | |
private Rectangle GetBoundRectangle() | |
{ | |
var rectangle = new Rectangle(); | |
rectangle.SetBinding(Rectangle.StrokeThicknessProperty, new Binding() { Source = this, Path = new PropertyPath("BorderThickness.Left") }); | |
rectangle.SetBinding(Rectangle.RadiusXProperty, new Binding() { Source = this, Path = new PropertyPath("CornerRadius.TopLeft") }); | |
rectangle.SetBinding(Rectangle.RadiusYProperty, new Binding() { Source = this, Path = new PropertyPath("CornerRadius.TopLeft") }); | |
rectangle.SetBinding(Rectangle.WidthProperty, new Binding() { Source = this, Path = new PropertyPath(ActualWidthProperty) }); | |
rectangle.SetBinding(Rectangle.HeightProperty, new Binding() { Source = this, Path = new PropertyPath(ActualHeightProperty) }); | |
return rectangle; | |
} | |
private Rectangle GetDashedRectangle() | |
{ | |
var rectangle = GetBoundRectangle(); | |
rectangle.SetBinding(Rectangle.StrokeDashArrayProperty, new Binding() { Source = this, Path = new PropertyPath(StrokeDashArrayProperty) }); | |
rectangle.SetBinding(Rectangle.StrokeProperty, new Binding() { Source = this, Path = new PropertyPath(DashedBorderBrushProperty) }); | |
Panel.SetZIndex(rectangle, 2); | |
return rectangle; | |
} | |
private void UseDashedBorderChanged() | |
{ | |
if (UseDashedBorder) | |
{ | |
BorderBrush = CreateDashedBorderBrush(); | |
} | |
else | |
{ | |
ClearValue(BorderBrushProperty); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment