CustomDrawnElementChrome类,用于重写Button类模板。
CustomDrawnElementChrome.cs
using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Media; namespace Shares.Avalonia.CustomControls { public class CustomDrawnElementChrome : Decorator { public static readonly StyledProperty<Color> BackgroundColorProperty = AvaloniaProperty.Register<CustomDrawnElementChrome, Color>( nameof(BackgroundColor), Colors.LightGray); public Color BackgroundColor { get => GetValue(BackgroundColorProperty); set => SetValue(BackgroundColorProperty, value); } public static readonly StyledProperty<Color> HoverColorProperty = AvaloniaProperty.Register<CustomDrawnElementChrome, Color>( nameof(HoverColor), Colors.White); public Color HoverColor { get => GetValue(HoverColorProperty); set => SetValue(HoverColorProperty, value); } public static readonly StyledProperty<Color> PressedColorProperty = AvaloniaProperty.Register<CustomDrawnElementChrome, Color>( nameof(PressedColor), Colors.Snow); public Color PressedColor { get => GetValue(PressedColorProperty); set => SetValue(PressedColorProperty, value); } public static readonly StyledProperty<IBrush?> BorderBrushProperty = AvaloniaProperty.Register<CustomDrawnElementChrome, IBrush?>( nameof(BorderBrush)); public IBrush? BorderBrush { get => GetValue(BorderBrushProperty); set => SetValue(BorderBrushProperty, value); } public static readonly StyledProperty<double> BorderThicknessProperty = AvaloniaProperty.Register<CustomDrawnElementChrome, double>( nameof(BorderThickness), 1.0); public double BorderThickness { get => GetValue(BorderThicknessProperty); set => SetValue(BorderThicknessProperty, value); } public static readonly StyledProperty<bool> IsPressedProperty = AvaloniaProperty.Register<CustomDrawnElementChrome, bool>( nameof(IsPressed)); public bool IsPressed { get => GetValue(IsPressedProperty); set => SetValue(IsPressedProperty, value); } // 最新的鼠标位置 private Point? lastPointerPosition; public CustomDrawnElementChrome() { PointerMoved += OnPointerMoved; PointerExited += OnPointerExited; PointerPressed += OnPointerPressed; PointerReleased += OnPointerReleased; PointerCaptureLost += OnPointerCaptureLost; } private void OnPointerMoved(object? sender, PointerEventArgs e) { lastPointerPosition = e.GetPosition(this); InvalidateVisual(); } private void OnPointerExited(object? sender, PointerEventArgs e) { lastPointerPosition = null; InvalidateVisual(); } private void OnPointerPressed(object? sender, PointerPressedEventArgs e) { if (!e.Handled && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) { IsPressed = true; InvalidateVisual(); } } private void OnPointerReleased(object? sender, PointerReleasedEventArgs e) { if (IsPressed) { IsPressed = false; InvalidateVisual(); } } private void OnPointerCaptureLost(object? sender, PointerCaptureLostEventArgs e) { if (IsPressed) { IsPressed = false; InvalidateVisual(); } } public override void Render(DrawingContext context) { // 先绘制子元素 base.Render(context); var bounds = new Rect(Bounds.Size); if (bounds.Width <= 0 || bounds.Height <= 0) return; var brush = CreateBackgroundBrush(bounds); Pen? borderPen = null; if (BorderBrush != null && BorderThickness > 0) { borderPen = new Pen(BorderBrush, BorderThickness); } context.DrawRectangle(brush, borderPen, bounds); } private IBrush CreateBackgroundBrush(Rect bounds) { var baseColor = BackgroundColor; if (!IsPointerOver || lastPointerPosition == null) { return new SolidColorBrush(baseColor); } var position = lastPointerPosition.Value; double rx = position.X / bounds.Width; double ry = position.Y / bounds.Height; if (double.IsNaN(rx) || double.IsInfinity(rx) || double.IsNaN(ry) || double.IsInfinity(ry)) { return new SolidColorBrush(baseColor); } var centerPoint = new RelativePoint( new Point(rx, ry), RelativeUnit.Relative); var highlightColor = IsPressed ? PressedColor : HoverColor; return new RadialGradientBrush { GradientStops = { new GradientStop(highlightColor, 0), new GradientStop(baseColor, 1) }, Center = centerPoint, GradientOrigin = centerPoint, RadiusX = new RelativeScalar(0.5, RelativeUnit.Relative), RadiusY = new RelativeScalar(0.5, RelativeUnit.Relative) }; } } }
CustomDrawnElementChromeTest.axaml代码
<Window xmlns="https://github.com/avaloniaui" 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" x:Class="AvaloniaUI.CustomDrawnElementChromeTest" Height="300" Width="300" Title="CustomDrawnElementChromeTest"> <Window.Resources> <ControlTemplate x:Key="ButtonChromeTemplate" TargetType="Button"> <CustomDrawnElementChrome BackgroundColor="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" IsPressed="{TemplateBinding IsPressed}"> <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" /> </CustomDrawnElementChrome> </ControlTemplate> </Window.Resources> <StackPanel HorizontalAlignment="Center" Spacing="5"> <Button Template="{StaticResource ButtonChromeTemplate}" Background="#FF3F51B5" BorderBrush="#80212121" BorderThickness="1.5" Padding="8,4" Content="Chrome Button" /> <Button Content="Normal Button"/> </StackPanel> </Window>
CustomDrawnElementChromeTest.axaml.cs代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Shares.Avalonia;
namespace AvaloniaUI;
public partial class CustomDrawnElementChromeTest : Window
{
public CustomDrawnElementChromeTest()
{
InitializeComponent();
}
}
运行效果

浙公网安备 33010602011771号