WPF RingShape
//cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfApp116 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class RingShape : Shape { Rect _rect; static RingShape() { StretchProperty.OverrideMetadata(typeof(RingShape), new FrameworkPropertyMetadata(Stretch.Uniform, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender)); } public double RingWidth { get { return (double)GetValue(RingWidthProperty); } set { SetValue(RingWidthProperty, value); } } // Using a DependencyProperty as the backing store for RingWidth. This enables animation, styling, binding, etc... public static readonly DependencyProperty RingWidthProperty = DependencyProperty.Register("RingWidth", typeof(double), typeof(RingShape), new FrameworkPropertyMetadata(0.1, FrameworkPropertyMetadataOptions.AffectsRender)); protected override Geometry DefiningGeometry { get { if (_rect.IsEmpty) { return Geometry.Empty; } var rc = _rect; rc.Inflate(-RingWidth * _rect.Width, -RingWidth * _rect.Height); return new CombinedGeometry(GeometryCombineMode.Exclude, new EllipseGeometry(_rect), new EllipseGeometry(rc)); } } protected override Size MeasureOverride(Size constraint) { if (double.IsInfinity(constraint.Width) || double.IsInfinity(constraint.Height)) { _rect = Rect.Empty; return Size.Empty; } double size; switch (Stretch) { case Stretch.Fill: _rect = new Rect(constraint); break; case Stretch.Uniform: size = Math.Min(constraint.Width, constraint.Height); _rect = new Rect(new Size(size, size)); break; case Stretch.UniformToFill: size = Math.Max(constraint.Width, constraint.Height); _rect = new Rect(new Size(size, size)); break; case Stretch.None: _rect = double.IsNaN(Width) || double.IsNaN(Height) ? Rect.Empty : new Rect(new Size(Width, Height)); break; } return _rect.Size; } } } //xaml <Window x:Class="WpfApp116.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp116" mc:Ignorable="d" WindowState="Maximized" Title="MainWindow" Height="450" Width="800"> <Grid> <local:RingShape Fill="Red" Stroke="Black" StrokeThickness="4" RingWidth="0.15"/> </Grid> </Window>