<Style TargetType="{x:Type ctrl:ArcGauge}">
"Background" Value="#646464"/>
"Foreground" Value="Black"/>
"Template">
"{x:Type ctrl:ArcGauge}">
"10">
"{Binding RelativeSource={RelativeSource Self},Path=ActualHeight}">
"#FF3B3B3B"/>
"0.5,0.5" Margin="2">
"{Binding Path=Angle,ElementName=PointRotate}"/>
"16" Height="14" Fill="Orange" VerticalAlignment="Top" >
"12"/>
x:Name="bdGrid" Margin="12" UseLayoutRounding="True" ClipToBounds="True">
"#4D000000"/>
"2*"/>
"2*"/>
"#464646" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
"#959595" Margin="4" StrokeThickness="6" Grid.Column="1" Grid.Row="1"/>
"#464646" Margin="14" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
"M5,0 5,0 10,120 0,120z" Fill="#0FA9CE" Stretch="Uniform" Margin="0 30 0 0" RenderTransformOrigin="0.5,1" HorizontalAlignment="Center">
x:Name="PointRotate"/>
"28" Height="28" Fill="Black">
"#0FA9CE" ShadowDepth="0" Direction="0" BlurRadius="16"/>
"Bottom" BorderBrush="#10ABD1" BorderThickness="2" Margin="0 0 0 12" Background="Black" Padding="8 2" HorizontalAlignment="Center">
"{Binding Value,RelativeSource={RelativeSource Mode=TemplatedParent}}" FontSize="16" Width="30" TextAlignment="Center" Foreground="White" FontWeight="Bold"/>
Style>
C#代码:
public class ArcGauge : Control
{
public ArcGauge()
{
Width = 200;
Height = 200;
SetCurrentValue(ValueProperty, 0d);
SetCurrentValue(MinValueProperty, 0d);
SetCurrentValue(MaxValueProperty, 100d);
}
private void InitTick()
{
// 画大刻度
for (int i = 0; i < 9; i++)
{
Line line = new Line();
line.X1 = 0;
line.Y1 = 0;
line.X2 = 0;
line.Y2 = 12;
line.Stroke = Brushes.White;
line.StrokeThickness = 2;
line.HorizontalAlignment = HorizontalAlignment.Center;
line.RenderTransformOrigin = new Point(0.5, 0.5);
line.RenderTransform = new RotateTransform() { Angle = -140 + i * 35 };
bdGrid.Children.Add(line);
DrawText();
}
// 画小刻度
for (int i = 0; i < 8; i++)
{
var start = -140 + 35 * i + 3.5;
for (int j = 0; j < 9; j++)
{
Line line = new Line();
line.X1 = 0;
line.Y1 = 0;
line.X2 = 0;
line.Y2 = 6;
line.Stroke = Brushes.White;
line.StrokeThickness = 1;
line.HorizontalAlignment = HorizontalAlignment.Center;
line.RenderTransformOrigin = new Point(0.5, 0.5);
line.RenderTransform = new RotateTransform() { Angle = start + j * 3.5 };
bdGrid.Children.Add(line);
}
}
}
List<TextBlock> textLabels = new List<TextBlock>();
private void DrawText()
{
foreach (var item in textLabels)
{
bdGrid.Children.Remove(item);
}
textLabels.Clear();
var per = MaxValue / 8;
for (int i = 0; i < 9; i++)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = $"{MinValue + (per * i)}";
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.RenderTransformOrigin = new Point(0.5, 0.5);
textBlock.RenderTransform = new RotateTransform() { Angle = -140 + i * 35 };
textBlock.Margin = new Thickness(12);
textBlock.Foreground = Brushes.White;
bdGrid.Children.Add(textBlock);
textLabels.Add(textBlock);
}
}
static ArcGauge()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ArcGauge), new FrameworkPropertyMetadata(typeof(ArcGauge)));
}
RotateTransform rotateTransform;
Grid bdGrid;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
rotateTransform = GetTemplateChild("PointRotate") as RotateTransform;
bdGrid = GetTemplateChild("bdGrid") as Grid;
Refresh();
InitTick();
}
[Category("值设定")]
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as ArcGauge)?.Refresh();
[Category("值设定")]
public double MinValue
{
get { return (double)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));
[Category("值设定")]
public double MaxValue
{
get { return (double)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(double), typeof(ArcGauge), new PropertyMetadata(0d, OnValueChanged));
private void Refresh()
{
if (rotateTransform == null)
return;
DoubleAnimation da = new DoubleAnimation();
da.Duration = new Duration(TimeSpan.FromMilliseconds(350));
da.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
if (Value > MaxValue)
{
rotateTransform.Angle = 140;
da.To = 140;
}
else if (Value < MinValue)
{
rotateTransform.Angle = -140;
da.To = -140;
}
else
{
var range = MaxValue - MinValue;
var process = Value / range;
var tAngle = process * 280 - 140;
rotateTransform.Angle = tAngle;
da.To = tAngle;
}
rotateTransform.BeginAnimation(RotateTransform.AngleProperty, da);
}
}
Ps:其他的颜色主题,范围标记啥的,可以自己完善一下,先暂时实现主要功能。