Avalonia制作仪表盘,把控件给大家演示一下,Avalonia有三类自定义控件,分别是用户控件、模版控件、自主控件。前面已经很多用户控件了,这个是演示模版控件,另外一种不知道哪种情况下使用。
前端代码:
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GaugeAvalonia.Views;assembly=GaugeAvalonia"
x:CompileBindings="False"
>
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>
<Style Selector="local|ArcGauge">
<Setter Property="Background" Value="#646464"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ArcGauge}">
<Border Margin="10">
<Grid Width="{Binding RelativeSource={RelativeSource Self},Path=Height}">
<Ellipse Fill="#FF3B3B3B"/>
<Grid RenderTransformOrigin="0.5,0.5" Margin="2">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform Angle="{Binding Angle}"/>
</TransformGroup>
</Grid.RenderTransform>
<Ellipse Width="16" Height="14" Fill="Orange" VerticalAlignment="Top" >
<Ellipse.Effect>
<BlurEffect Radius="12"/>
</Ellipse.Effect>
</Ellipse>
</Grid>
<Grid x:Name="bdGrid" Margin="12" UseLayoutRounding="True" ClipToBounds="True">
<Ellipse>
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="#4D000000"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="2*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Ellipse Stroke="#464646" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
<Ellipse Stroke="#959595" Margin="4" StrokeThickness="6" Grid.Column="1" Grid.Row="1"/>
<Ellipse Stroke="#464646" Margin="14" StrokeThickness="1" Grid.Column="1" Grid.Row="1"/>
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Path Data="M5,0 5,0 10,120 0,120z" Fill="#0FA9CE" Stretch="Uniform" Margin="0 30 0 0" HorizontalAlignment="Center">
<Path.RenderTransform>
<TransformGroup>
<RotateTransform Angle="{Binding Path=Angle, Mode=TwoWay}"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
<Ellipse Width="28" Height="28" Fill="Black">
<Ellipse.Effect>
<!--<DropShadowEffect Color="#0FA9CE" ShadowDepth="0" Direction="0" BlurRadius="16"/>-->
</Ellipse.Effect>
</Ellipse>
<Border VerticalAlignment="Bottom" BorderBrush="#10ABD1" BorderThickness="2" Margin="0 0 0 12" Background="Black" Padding="8 2" HorizontalAlignment="Center">
<TextBlock Text="{Binding Value,RelativeSource={RelativeSource Mode=TemplatedParent}}" FontSize="16" Width="30" TextAlignment="Center" Foreground="White" FontWeight="Bold"/>
</Border>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Styles>
后台代码:
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Media;
using System.Collections.Generic;
using System.ComponentModel;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Primitives;
using System.Linq;
namespace GaugeAvalonia.Views
{
public class ArcGauge: TemplatedControl
{
Grid bdGrid;
static ArcGauge()
{
// DefaultStyleKeyProperty.OverrideMetadata(typeof(ArcGauge), new FrameworkPropertyMetadata(typeof(ArcGauge)));
}
public ArcGauge()
{
this.Loaded += ArcGauge_Loaded;
//Width = 200;
//Height = 200;
SetCurrentValue(ValueProperty, 0d);
SetCurrentValue(MinValueProperty, 0d);
SetCurrentValue(MaxValueProperty, 100d);
}
private void ArcGauge_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
InitTick();
}
public override void Render(DrawingContext context)
{
base.Render(context);
bdGrid = (Grid)this.GetTemplateChildren().Where(x => x.Name == "bdGrid").First();
Refresh();
}
private void InitTick()
{
// 画大刻度
for (int i = 0; i < 9; i++)
{
Line line = new Line();
line.StartPoint = new Point(0, 0);
line.EndPoint=new Point(0, 12);
line.HorizontalAlignment= Avalonia.Layout.HorizontalAlignment
.Center;
line.Stroke = Brushes.White;
line.StrokeThickness = 2;
line.RenderTransformOrigin = RelativePoint.Center;
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.StartPoint = new Point(0, 0);
line.EndPoint = new Point(0, 6);
line.Stroke = Brushes.White;
line.StrokeThickness = 1;
line.HorizontalAlignment = Avalonia.Layout.HorizontalAlignment .Center;
line.RenderTransformOrigin = RelativePoint.Center;
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 = Avalonia.Layout.HorizontalAlignment.Center;
textBlock.RenderTransformOrigin = RelativePoint.Center;
textBlock.RenderTransform = new RotateTransform() { Angle = -140 + i * 35 };
textBlock.Margin = new Thickness(12);
textBlock.Foreground = Brushes.White;
bdGrid.Children.Add(textBlock);
textLabels.Add(textBlock);
}
}
//public static readonly StyledProperty<IBrush> BackgroundProperty =
// AvaloniaProperty.Register<ArcGauge, IBrush>(nameof(Value));
//public IBrush Background
//{
// get
// {
// return GetValue(BackgroundProperty);
// }
// set
// {
// SetValue(BackgroundProperty, value);
// }
//}
//public static readonly StyledProperty<IBrush> ForegroundProperty =
// AvaloniaProperty.Register<ArcGauge, IBrush>(nameof(Value));
//public IBrush Foreground
//{
// get
// {
// return GetValue(ForegroundProperty);
// }
// set
// {
// SetValue(ForegroundProperty, value);
// }
// }
[Category("值设定")]
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly StyledProperty<double> ValueProperty =
AvaloniaProperty.Register<ArcGauge, double>(nameof(Value), coerce: OnValueChanged);
private static double OnValueChanged(AvaloniaObject @object, double arg2)
{
ArcGauge gauge= @object as ArcGauge;
gauge.Refresh();
return arg2;
}
[Category("值设定")]
public double MinValue
{
get { return (double)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
public static readonly StyledProperty<double> MinValueProperty =
AvaloniaProperty.Register<ArcGauge, double>(nameof(MinValue), coerce: OnValueChanged);
public double MaxValue
{
get { return (double)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
public static readonly StyledProperty<double> MaxValueProperty =
AvaloniaProperty.Register<ArcGauge, double>(nameof(MaxValue), coerce: OnValueChanged);
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
public static readonly StyledProperty<double> AngleProperty =
AvaloniaProperty.Register<ArcGauge, double>(nameof(Angle));
private void Refresh()
{
if (Value > MaxValue)
{
Angle = 140;
}
else if (Value < MinValue)
{
Angle = -140;
}
else
{
var range = MaxValue - MinValue;
var process = Value / range;
var tAngle = process * 280 - 140;
Angle = tAngle;
}
}
}
}
运行效果:
目前Avalonia的内容也不知道该演示什么了。估计博文会更新慢了。