下一个例子会把这个写成一个style + cs类,这样方便模板调用。
ModernWindow.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" Height="300" Width="300" x:Class="AvaloniaUI.ModernWindow" SystemDecorations="None" TransparencyLevelHint="Transparent" Background="Transparent" Title="ModernWindow"> <Border x:Name="windowFrame" BorderBrush="#395984" BorderThickness="1" CornerRadius="0,20,30,40"> <Border.Background> <LinearGradientBrush> <GradientStop Color="#E7EBF7" Offset="0"/> <GradientStop Color="#CEE3FF" Offset="0.5"/> </LinearGradientBrush> </Border.Background> <Grid RowDefinitions="auto,*,auto"> <!-- 标题栏:PointerPressed 用于拖动窗口 --> <Grid Grid.Row="0" Margin="1" Background="Transparent" ColumnDefinitions="*,auto" PointerPressed="titleBar_PointerPressed"> <!-- 可拖拽区域 --> <TextBlock Grid.Column="0" VerticalAlignment="Center" Padding="5" Text="Modern Window"/> <!-- 关闭按钮 --> <Button Grid.Column="1" Margin="4" Padding="6,2" VerticalAlignment="Center" Click="cmdClose_Click"> x </Button> </Grid> <Grid Grid.Row="1" Background="#B5CBEF" > <TextBlock Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" FontSize="20" Text="Content Goes Here"/> </Grid> <!-- Footer --> <Grid Grid.Row="2" Margin="1,10,1,1" ColumnDefinitions="*,auto" Background="Transparent"> <!-- Footer 文本 --> <TextBlock Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="5" Text="Footer"/> <!-- 右下角 ResizeGrip --> <Border Grid.Column="1" ZIndex="100" Width="16" Height="16" Margin="5" Background="Transparent" HorizontalAlignment="Right" VerticalAlignment="Bottom" Tag="BottomRight" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"> <Rectangle Margin="1"> <Rectangle.Fill> <VisualBrush TileMode="Tile" DestinationRect="0,0,4,4" SourceRect="0,0,8,8"> <VisualBrush.Visual> <Canvas Width="8" Height="8"> <Rectangle Width="4" Height="4" Canvas.Left="4" Canvas.Top="4" Fill="#AAA"/> </Canvas> </VisualBrush.Visual> </VisualBrush> </Rectangle.Fill> </Rectangle> </Border> </Grid> <!-- 四边 --> <Rectangle Width="5" Fill="Transparent" HorizontalAlignment="Left" VerticalAlignment="Stretch" Cursor="SizeWestEast" Tag="Left" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> <Rectangle Width="5" Fill="Transparent" HorizontalAlignment="Right" VerticalAlignment="Stretch" Cursor="SizeWestEast" Tag="Right" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> <Rectangle Height="5" Fill="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Top" Cursor="SizeNorthSouth" Tag="Top" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> <Rectangle Height="5" Fill="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Cursor="SizeNorthSouth" Tag="Bottom" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> <!-- 四角(10x10) --> <Rectangle Width="10" Height="10" Fill="Transparent" HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="SizeAll" Tag="TopLeft" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> <Rectangle Width="10" Height="10" Fill="Transparent" HorizontalAlignment="Right" VerticalAlignment="Top" Cursor="SizeAll" Tag="TopRight" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> <Rectangle Width="10" Height="10" Fill="Transparent" HorizontalAlignment="Left" VerticalAlignment="Bottom" Cursor="SizeAll" Tag="BottomLeft" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> <Rectangle Width="10" Height="10" Fill="Transparent" HorizontalAlignment="Right" VerticalAlignment="Bottom" Cursor="SizeAll" Tag="BottomRight" Grid.RowSpan="3" PointerPressed="resizeGrip_PointerPressed" PointerMoved="resizeGrip_PointerMoved" PointerReleased="resizeGrip_PointerReleased"/> </Grid> </Border> </Window>
ModernWindow.axaml.cs代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using System;
namespace AvaloniaUI;
public partial class ModernWindow : Window
{
[Flags]
private enum ResizeEdges
{
None = 0,
Left = 1,
Top = 2,
Right = 4,
Bottom = 8
}
private bool isResizing;
private ResizeEdges edges;
private PixelPoint startWindowPos; // Pixel
private Size startWindowSize; // DIP
private PixelPoint startPointerScreenPx; // Screen Pixel
private double startRenderScaling;
public ModernWindow()
{
InitializeComponent();
MinWidth = 150;
MinHeight = 120;
}
private void titleBar_PointerPressed(object? sender, PointerPressedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
BeginMoveDrag(e);
}
private void cmdClose_Click(object? sender, RoutedEventArgs e)
{
Close();
}
private void resizeGrip_PointerPressed(object? sender, PointerPressedEventArgs e)
{
if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
return;
if (sender is not Control c)
return;
edges = ParseEdges(c.Tag as string);
if (edges == ResizeEdges.None)
return;
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel is null)
return;
isResizing = true;
startWindowPos = Position; // Pixel
startWindowSize = new Size(Bounds.Width, Bounds.Height); // DIP
startRenderScaling = RenderScaling;
startPointerScreenPx = GetPointerScreenPx(e, topLevel);
e.Pointer.Capture(c);
e.Handled = true;
}
private void resizeGrip_PointerReleased(object? sender, PointerReleasedEventArgs e)
{
if (!isResizing)
return;
isResizing = false;
edges = ResizeEdges.None;
e.Pointer?.Capture(null);
e.Handled = true;
}
private void resizeGrip_PointerMoved(object? sender, PointerEventArgs e)
{
if (!isResizing || edges == ResizeEdges.None)
return;
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel is null)
return;
var pointerScreenPx = GetPointerScreenPx(e, topLevel);
var dxPx = pointerScreenPx.X - startPointerScreenPx.X;
var dyPx = pointerScreenPx.Y - startPointerScreenPx.Y;
var dxDip = dxPx / startRenderScaling;
var dyDip = dyPx / startRenderScaling;
var newX = startWindowPos.X;
var newY = startWindowPos.Y;
var newW = startWindowSize.Width;
var newH = startWindowSize.Height;
var hasLeft = (edges & ResizeEdges.Left) != 0;
var hasRight = (edges & ResizeEdges.Right) != 0;
var hasTop = (edges & ResizeEdges.Top) != 0;
var hasBottom = (edges & ResizeEdges.Bottom) != 0;
if (hasRight)
newW = Math.Max(MinWidth, startWindowSize.Width + dxDip);
if (hasBottom)
newH = Math.Max(MinHeight, startWindowSize.Height + dyDip);
if (hasLeft)
{
newW = Math.Max(MinWidth, startWindowSize.Width - dxDip);
newX = startWindowPos.X + dxPx;
if (newW <= MinWidth)
newX = startWindowPos.X + ClampDeltaPxForMin(startWindowSize.Width, MinWidth);
}
if (hasTop)
{
newH = Math.Max(MinHeight, startWindowSize.Height - dyDip);
newY = startWindowPos.Y + dyPx;
if (newH <= MinHeight)
newY = startWindowPos.Y + ClampDeltaPxForMin(startWindowSize.Height, MinHeight);
}
Position = new PixelPoint(newX, newY);
Width = newW;
Height = newH;
e.Handled = true;
}
private static ResizeEdges ParseEdges(string? tag)
{
return tag switch
{
"Left" => ResizeEdges.Left,
"Right" => ResizeEdges.Right,
"Top" => ResizeEdges.Top,
"Bottom" => ResizeEdges.Bottom,
"TopLeft" => ResizeEdges.Top | ResizeEdges.Left,
"TopRight" => ResizeEdges.Top | ResizeEdges.Right,
"BottomLeft" => ResizeEdges.Bottom | ResizeEdges.Left,
"BottomRight" => ResizeEdges.Bottom | ResizeEdges.Right,
_ => ResizeEdges.None
};
}
private static PixelPoint GetPointerScreenPx(PointerEventArgs e, TopLevel topLevel)
{
var pInTopLevel = e.GetPosition(topLevel); // DIP
return topLevel.PointToScreen(pInTopLevel); // Pixel
}
private int ClampDeltaPxForMin(double startSizeDip, double minSizeDip)
{
var clampPx = (startSizeDip - minSizeDip) * startRenderScaling;
return (int)Math.Round(clampPx);
}
}
运行效果

浙公网安备 33010602011771号