C# WPF创建单个块的虚线椭圆
有没有简单的方法来创建由单个水平虚线组成的虚线椭圆,其中虚线大小一致,并且可以指定其数量 大概是这样的: 我希望能够单独控制每个破折号,比如更改其颜色或将其绑定到viewmodel中的动作C# WPF创建单个块的虚线椭圆,c#,wpf,xaml,geometry,ellipse,C#,Wpf,Xaml,Geometry,Ellipse,有没有简单的方法来创建由单个水平虚线组成的虚线椭圆,其中虚线大小一致,并且可以指定其数量 大概是这样的: 我希望能够单独控制每个破折号,比如更改其颜色或将其绑定到viewmodel中的动作 我能想到的实现这一点的唯一方法是创建一个自定义控件,该控件包含每个破折号的路径元素,共同组成一个椭圆形状,必须根据破折号的数量和椭圆的大小计算路径数据。我现在回到这个问题上来,并设法以非常灵活和通用的方式解决它。从那时起,需求发生了一些变化,不需要绑定,但可以轻松添加 注意,这是一个圆,这是我想要的。问题应
我能想到的实现这一点的唯一方法是创建一个自定义控件,该控件包含每个破折号的路径元素,共同组成一个椭圆形状,必须根据破折号的数量和椭圆的大小计算路径数据。我现在回到这个问题上来,并设法以非常灵活和通用的方式解决它。从那时起,需求发生了一些变化,不需要绑定,但可以轻松添加 注意,这是一个圆,这是我想要的。问题应该是圆而不是椭圆,即使圆是椭圆,但我离题了 下面是我提出的用户控件: StatusRing.xaml.cs
public partial class StatusRing
{
#region Dependency Property registrations
public static readonly DependencyProperty DashesProperty = DependencyProperty.Register("Dashes",
typeof(int), typeof(StatusRing), new PropertyMetadata(32, DashesChanged));
public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register("Diameter",
typeof(double), typeof(StatusRing), new PropertyMetadata(150.00, DiameterChanged));
public static readonly DependencyProperty DashHeightProperty = DependencyProperty.Register("DashHeight",
typeof(double), typeof(StatusRing), new PropertyMetadata(20.00, DashHeightChanged));
public static readonly DependencyProperty DashWidthProperty = DependencyProperty.Register("DashWidth",
typeof(double), typeof(StatusRing), new PropertyMetadata(5.00, DashWidthChanged));
public static readonly DependencyProperty DashFillProperty = DependencyProperty.Register("DashFill",
typeof(SolidColorBrush), typeof(StatusRing), new PropertyMetadata(Brushes.DimGray, DashFillChanged));
public static readonly DependencyProperty DashAccentFillProperty = DependencyProperty.Register("DashAccentFill",
typeof(SolidColorBrush), typeof(StatusRing), new PropertyMetadata(Brushes.White, DashAnimationFillChanged));
public static readonly DependencyProperty TailSizeProperty = DependencyProperty.Register("TailSize",
typeof(int), typeof(StatusRing), new PropertyMetadata(10, TailSizeChanged));
public static readonly DependencyProperty AnimationSpeedProperty = DependencyProperty.Register("AnimationSpeed",
typeof(double), typeof(StatusRing), new PropertyMetadata(50.00, AnimationSpeedChanged));
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register("IsPlaying",
typeof(bool), typeof(StatusRing), new PropertyMetadata(false, IsPlayingChanged));
#endregion Dependency Property registrations
private readonly Storyboard glowAnimationStoryBoard = new Storyboard();
public StatusRing()
{
Loaded += OnLoaded;
InitializeComponent();
}
#region Dependency Properties
public int Dashes
{
get => (int)GetValue(DashesProperty);
set => SetValue(DashesProperty, value);
}
public double Diameter
{
get => (double)GetValue(DiameterProperty);
set => SetValue(DiameterProperty, value);
}
public double Radius => Diameter / 2;
public double DashHeight
{
get => (double)GetValue(DashHeightProperty);
set => SetValue(DashHeightProperty, value);
}
public double DashWidth
{
get => (double)GetValue(DashWidthProperty);
set => SetValue(DashWidthProperty, value);
}
public Brush DashFill
{
get => (SolidColorBrush)GetValue(DashFillProperty);
set => SetValue(DashFillProperty, value);
}
public Brush DashAccentFill
{
get => (SolidColorBrush)GetValue(DashAccentFillProperty);
set => SetValue(DashAccentFillProperty, value);
}
public int TailSize
{
get => (int)GetValue(TailSizeProperty);
set => SetValue(TailSizeProperty, value);
}
public double AnimationSpeed
{
get => (double)GetValue(AnimationSpeedProperty);
set => SetValue(AnimationSpeedProperty, value);
}
public bool IsPlaying
{
get => (bool)GetValue(IsPlayingProperty);
set => SetValue(IsPlayingProperty, value);
}
#endregion Dependency Properties
private void OnLoaded(object sender, RoutedEventArgs e)
{
var thisControl = sender as StatusRing;
Recreate(thisControl);
}
#region Dependency Property callbacks
private static void DashesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
Recreate(thisControl);
}
private static void DiameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
Recreate(thisControl);
}
private static void DashHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
Recreate(thisControl);
}
private static void DashWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
Recreate(thisControl);
}
private static void DashFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
Recreate(thisControl);
}
private static void DashAnimationFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
Recreate(thisControl);
}
private static void TailSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
Recreate(thisControl);
}
private static void AnimationSpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
if (thisControl.IsLoaded)
{
thisControl.glowAnimationStoryBoard.Stop();
thisControl.glowAnimationStoryBoard.Children.Clear();
ApplyAnimations(thisControl);
thisControl.glowAnimationStoryBoard.Begin();
}
}
private static void IsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as StatusRing;
if (thisControl.IsLoaded)
{
var isPlaying = (bool)e.NewValue;
if (isPlaying)
{
thisControl.glowAnimationStoryBoard.Begin();
}
else
{
thisControl.glowAnimationStoryBoard.Stop();
}
}
}
#endregion Dependency Property callbacks
private static void Recreate(StatusRing thisControl)
{
if (thisControl.IsLoaded)
{
thisControl.glowAnimationStoryBoard.Stop();
thisControl.glowAnimationStoryBoard.Children.Clear();
thisControl.RootCanvas.Children.Clear();
Validate(thisControl);
BuildRing(thisControl);
ApplyAnimations(thisControl);
if (thisControl.IsPlaying)
{
thisControl.glowAnimationStoryBoard.Begin();
}
else
{
thisControl.glowAnimationStoryBoard.Stop();
}
}
}
private static void Validate(StatusRing thisControl)
{
if (thisControl.TailSize > thisControl.Dashes)
{
throw new Exception("TailSize cannot be larger than amount of dashes");
}
}
private static void BuildRing(StatusRing thisControl)
{
var angleStep = (double)360 / thisControl.Dashes;
for (double i = 0; i < 360; i = i + angleStep)
{
var rect = new Rectangle
{
Fill = thisControl.DashFill,
Height = thisControl.DashHeight,
Width = thisControl.DashWidth
};
//Rotate dash to follow circles circumference
var centerY = thisControl.Radius;
var centerX = thisControl.DashWidth / 2;
var rotateTransform = new RotateTransform(i, centerX, centerY);
rect.RenderTransform = rotateTransform;
var offset = thisControl.Radius - thisControl.DashWidth / 2;
rect.SetValue(Canvas.LeftProperty, offset);
thisControl.RootCanvas.Children.Add(rect);
}
thisControl.RootCanvas.Width = thisControl.Diameter;
thisControl.RootCanvas.Height = thisControl.Diameter;
}
private static void ApplyAnimations(StatusRing thisControl)
{
var baseColor = ((SolidColorBrush)thisControl.DashFill).Color;
var animatedColor = ((SolidColorBrush)thisControl.DashAccentFill).Color;
var dashes = thisControl.RootCanvas.Children.OfType<Rectangle>().ToList();
double animationPeriod = thisControl.AnimationSpeed;
double glowDuration = animationPeriod * thisControl.TailSize;
for (int i = 0; i < dashes.Count; i++)
{
var beginTime = TimeSpan.FromMilliseconds(animationPeriod * i);
var colorAnimation = new ColorAnimationUsingKeyFrames
{
BeginTime = beginTime,
RepeatBehavior = RepeatBehavior.Forever
};
var toFillColor = new LinearColorKeyFrame(animatedColor, TimeSpan.Zero);
colorAnimation.KeyFrames.Add(toFillColor);
var dimToBase = new LinearColorKeyFrame(baseColor, TimeSpan.FromMilliseconds(glowDuration));
colorAnimation.KeyFrames.Add(dimToBase);
var restingTime = animationPeriod * dashes.Count;
var delay = new LinearColorKeyFrame(baseColor, TimeSpan.FromMilliseconds(restingTime));
colorAnimation.KeyFrames.Add(delay);
Storyboard.SetTarget(colorAnimation, dashes[i]);
Storyboard.SetTargetProperty(colorAnimation, new PropertyPath("(Fill).(SolidColorBrush.Color)"));
thisControl.glowAnimationStoryBoard.Children.Add(colorAnimation);
}
}
}
公共部分类StatusRing
{
#地区从属财产登记
public static readonly dependencProperty dashProperty=dependencProperty.Register(“破折号”),
typeof(int)、typeof(StatusRing)、新的PropertyMetadata(32,DashesChanged));
公共静态只读DependencyProperty DiameterProperty=DependencyProperty.Register(“直径”,
typeof(双精度)、typeof(StatusRing)、新的PropertyMetadata(150.00,直径更改));
公共静态只读DependencyProperty DashHeightProperty=DependencyProperty.Register(“DashHeight”,
typeof(双精度)、typeof(StatusRing)、新的PropertyMetadata(20.00,DashHeightChanged));
公共静态只读DependencyProperty DashWidthProperty=DependencyProperty.Register(“DashWidth”,
typeof(双精度)、typeof(StatusRing)、新PropertyMetadata(5.00,DashWidthChanged));
公共静态只读DependencyProperty DashFillProperty=DependencyProperty.Register(“DashFill”,
typeof(SolidColorBrush)、typeof(StatusRing)、新属性元数据(Brush.DimGray、DashFillChanged));
公共静态只读DependencyProperty DashAccentFillProperty=DependencyProperty.Register(“DashAccentFill”,
typeof(SolidColorBrush)、typeof(StatusRing)、新属性元数据(Brush.White、DashAnimationFillChanged));
公共静态只读DependencyProperty TailSizeProperty=DependencyProperty.Register(“TailSize”,
typeof(int)、typeof(StatusRing)、新属性ymatadata(10,TailSizeChanged));
公共静态只读DependencyProperty AnimationSpeedProperty=DependencyProperty.Register(“AnimationSpeed”,
typeof(double)、typeof(StatusRing)、新属性ymetadata(50.00,AnimationSpeedChanged));
public static readonly dependencProperty IsPlayingProperty=dependencProperty.Register(“IsPlaying”,
typeof(bool)、typeof(StatusRing)、新属性元数据(false、IsPlayingChanged);
#endregion依赖项属性注册
私有只读故事板glowAnimationStoryBoard=新故事板();
公共状态环()
{
已加载+=已加载;
初始化组件();
}
#区域依赖属性
公共整型破折号
{
get=>(int)GetValue(DashsProperty);
set=>SetValue(dashsProperty,value);
}
公共双直径
{
get=>(双精度)GetValue(DiameterProperty);
set=>SetValue(直径属性,值);
}
公共双半径=>直径/2;
公共双高
{
get=>(双精度)GetValue(DashHeightProperty);
set=>SetValue(DashHeightProperty,value);
}
公共双短划线宽度
{
get=>(双精度)GetValue(DashWidthProperty);
set=>SetValue(DashWidthProperty,value);
}
公共灌木丛
{
get=>(SolidColorBrush)GetValue(DashFillProperty);
set=>SetValue(DashFillProperty,value);
}
公共灌木丛
{
get=>(SolidColorBrush)GetValue(DashAccentFillProperty);
set=>SetValue(属性,值);
}
公共整数尾码
{
get=>(int)GetValue(TailSizeProperty);
set=>SetValue(TailSizeProperty,value);
}
公共双动画速度
{
get=>(双精度)GetValue(AnimationSpeedProperty);
set=>SetValue(AnimationSpeedProperty,value);
}
公共广播
{
get=>(bool)GetValue(iPlayingProperty);
set=>SetValue(IsPlayingProperty,value);
}
#endregion依赖属性
已加载专用void(对象发送方,RoutedEventArgs e)
{
var thisControl=发送方为StatusRing;
重新创建(此控件);
}
#区域依赖属性回调
私有静态无效DashChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var thisControl=d作为StatusRing;
重新创建(此控件);
}
专用静态空隙直径已更改(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var thisControl=d作为StatusRing;
重新创建(此控件);
}
私有静态无效DashHeightChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var thisControl=d作为StatusRing;
重新创建(此控件);
}
私有静态无效DashWidthChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var thisControl=d作为StatusRing;
重新创建(此控件);
}
私有静态无效DashFillChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var thisControl=d作为StatusRing;
重新创建(此控件);
}
私有静态虚空DashAnimationFillChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var thisControl=d作为StatusRing;
重新创建(此控件);
}
私有静态无效TailSizeChanged(DependencyObject d,DependencyP
<UserControl x:Class="WpfPlayground.StatusRing"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Canvas x:Name="RootCanvas" />
<local:StatusRing Diameter="250"
Dashes="32"
TailSize="16"
IsPlaying="True" />