当前位置: 首页 > news >正文

C# Avalonia 20 - WindowsMenu- ModernWindowTest

ModernWindowChrome控件cs代码

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Metadata;
using System;namespace Shares.Avalonia.CustomControls
{[TemplatePart("PART_TitleBar", typeof(Control))][TemplatePart("PART_CloseButton", typeof(Button))][TemplatePart("PART_GripBottomRight", typeof(Control))][TemplatePart("PART_EdgeLeft", typeof(Control))][TemplatePart("PART_EdgeRight", typeof(Control))][TemplatePart("PART_EdgeTop", typeof(Control))][TemplatePart("PART_EdgeBottom", typeof(Control))][TemplatePart("PART_CornerTopLeft", typeof(Control))][TemplatePart("PART_CornerTopRight", typeof(Control))][TemplatePart("PART_CornerBottomLeft", typeof(Control))][TemplatePart("PART_CornerBottomRight", typeof(Control))]public class ModernWindowChrome : TemplatedControl{public static readonly AttachedProperty<object?> FooterProperty =AvaloniaProperty.RegisterAttached<ModernWindowChrome, Window, object?>("Footer");public static void SetFooter(Window element, object? value) => element.SetValue(FooterProperty, value);public static object? GetFooter(Window element) => element.GetValue(FooterProperty);[Flags]private enum ResizeEdges{None = 0,Left = 1,Top = 2,Right = 4,Bottom = 8}private bool isResizing;private ResizeEdges edges;private PixelPoint startWindowPos;private Size startWindowSize;private PixelPoint startPointerScreenPx;private double startRenderScaling;private Control? titleBar;private Button? closeButton;private Control?[]? resizeParts;private IInputElement? captured;protected override void OnApplyTemplate(TemplateAppliedEventArgs e){base.OnApplyTemplate(e);Unhook();titleBar = e.NameScope.Find<Control>("PART_TitleBar");closeButton = e.NameScope.Find<Button>("PART_CloseButton");resizeParts = new[]{e.NameScope.Find<Control>("PART_GripBottomRight"),e.NameScope.Find<Control>("PART_EdgeLeft"),e.NameScope.Find<Control>("PART_EdgeRight"),e.NameScope.Find<Control>("PART_EdgeTop"),e.NameScope.Find<Control>("PART_EdgeBottom"),e.NameScope.Find<Control>("PART_CornerTopLeft"),e.NameScope.Find<Control>("PART_CornerTopRight"),e.NameScope.Find<Control>("PART_CornerBottomLeft"),e.NameScope.Find<Control>("PART_CornerBottomRight"),};if (titleBar is not null)titleBar.PointerPressed += TitleBarPointerPressed;if (closeButton is not null)closeButton.Click += CloseButtonClick;foreach (var part in resizeParts){if (part is null)continue;part.PointerPressed += ResizePointerPressed;part.PointerMoved += ResizePointerMoved;part.PointerReleased += ResizePointerReleased;}}private void TitleBarPointerPressed(object? sender, PointerPressedEventArgs e){var window = TopLevel.GetTopLevel(this) as Window;if (window is null)return;if (sender is not Control c)return;if (e.GetCurrentPoint(c).Properties.IsLeftButtonPressed)window.BeginMoveDrag(e);}private void CloseButtonClick(object? sender, RoutedEventArgs e){var window = TopLevel.GetTopLevel(this) as Window;window?.Close();}private void ResizePointerPressed(object? sender, PointerPressedEventArgs e){var window = TopLevel.GetTopLevel(this) as Window;if (window is null)return;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(window);if (topLevel is null)return;isResizing = true;startWindowPos = window.Position;startWindowSize = new Size(window.Bounds.Width, window.Bounds.Height);startRenderScaling = window.RenderScaling;startPointerScreenPx = GetPointerScreenPx(e, topLevel);captured = c;e.Pointer.Capture(c);e.Handled = true;}private void ResizePointerReleased(object? sender, PointerReleasedEventArgs e){if (!isResizing)return;isResizing = false;edges = ResizeEdges.None;if (e.Pointer?.Captured == captured)e.Pointer?.Capture(null);captured = null;e.Handled = true;}private void ResizePointerMoved(object? sender, PointerEventArgs e){if (!isResizing || edges == ResizeEdges.None)return;var window = TopLevel.GetTopLevel(this) as Window;if (window is null)return;var topLevel = TopLevel.GetTopLevel(window);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 minWidth = window.MinWidth;var minHeight = window.MinHeight;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);}window.Position = new PixelPoint(newX, newY);window.Width = newW;window.Height = newH;e.Handled = true;}private void Unhook(){if (titleBar is not null)titleBar.PointerPressed -= TitleBarPointerPressed;if (closeButton is not null)closeButton.Click -= CloseButtonClick;if (resizeParts is null)return;foreach (var part in resizeParts){if (part is null)continue;part.PointerPressed -= ResizePointerPressed;part.PointerMoved -= ResizePointerMoved;part.PointerReleased -= ResizePointerReleased;}}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);return topLevel.PointToScreen(pInTopLevel);}private int ClampDeltaPxForMin(double startSizeDip, double minSizeDip){var clampPx = (startSizeDip - minSizeDip) * startRenderScaling;return (int)Math.Round(clampPx);}}
}

ModernWindowChrome控件style代码

xmlns:local="using:Shares.Avalonia.CustomControls"

    <!--Window样式--><Style Selector="Window.ModernWindow"><Setter Property="SystemDecorations" Value="None"/><Setter Property="TransparencyLevelHint" Value="Transparent"/><Setter Property="Background" Value="Transparent"/><Setter Property="MinWidth" Value="150"/><Setter Property="MinHeight" Value="120"/><!-- Window 模板 --><Setter Property="Template"><ControlTemplate><!-- Chrome 作为根 --><local:ModernWindowChrome><!-- 给 Chrome 内联一个 ControlTheme --><local:ModernWindowChrome.Theme><ControlTheme TargetType="local:ModernWindowChrome"><Setter Property="Template"><ControlTemplate><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"><!-- 标题栏 --><Grid Grid.Row="0"x:Name="PART_TitleBar"Margin="1"Background="Transparent"ColumnDefinitions="*,auto"><TextBlock Grid.Column="0"VerticalAlignment="Center"HorizontalAlignment="Center"Padding="5"Text="{Binding $parent[Window].Title}"/><Button Grid.Column="1"x:Name="PART_CloseButton"Margin="4"Padding="6,2"VerticalAlignment="Center"Content="x"/></Grid><!-- 内容区 --><Grid Grid.Row="1" Background="#B5CBEF"><ContentPresenterContent="{Binding $parent[Window].Content}"/></Grid><!-- Footer + 右下角 Grip --><Grid Grid.Row="2"Margin="2"ColumnDefinitions="*,auto"Background="Transparent"><ContentPresenter Grid.Column="0"VerticalAlignment="Center"HorizontalAlignment="Center"Content="{Binding $parent[Window].(local:ModernWindowChrome.Footer)}"/><Border Grid.Column="1"x:Name="PART_GripBottomRight"Width="16"Height="16"Margin="5"Background="Transparent"HorizontalAlignment="Right"VerticalAlignment="Bottom"Tag="BottomRight"><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 x:Name="PART_EdgeLeft"Width="5"Fill="Transparent"HorizontalAlignment="Left"VerticalAlignment="Stretch"Cursor="SizeWestEast"Tag="Left"Grid.RowSpan="3"/><Rectangle x:Name="PART_EdgeRight"Width="5"Fill="Transparent"HorizontalAlignment="Right"VerticalAlignment="Stretch"Cursor="SizeWestEast"Tag="Right"Grid.RowSpan="3"/><Rectangle x:Name="PART_EdgeTop"Height="5"Fill="Transparent"HorizontalAlignment="Stretch"VerticalAlignment="Top"Cursor="SizeNorthSouth"Tag="Top"Grid.RowSpan="3"/><Rectangle x:Name="PART_EdgeBottom"Height="5"Fill="Transparent"HorizontalAlignment="Stretch"VerticalAlignment="Bottom"Cursor="SizeNorthSouth"Tag="Bottom"Grid.RowSpan="3"/><!-- 四角 --><Rectangle x:Name="PART_CornerTopLeft"Width="10"Height="10"Fill="Transparent"HorizontalAlignment="Left"VerticalAlignment="Top"Cursor="SizeAll"Tag="TopLeft"Grid.RowSpan="3"/><Rectangle x:Name="PART_CornerTopRight"Width="10"Height="10"Fill="Transparent"HorizontalAlignment="Right"VerticalAlignment="Top"Cursor="SizeAll"Tag="TopRight"Grid.RowSpan="3"/><Rectangle x:Name="PART_CornerBottomLeft"Width="10"Height="10"Fill="Transparent"HorizontalAlignment="Left"VerticalAlignment="Bottom"Cursor="SizeAll"Tag="BottomLeft"Grid.RowSpan="3"/><Rectangle x:Name="PART_CornerBottomRight"Width="10"Height="10"Fill="Transparent"HorizontalAlignment="Right"VerticalAlignment="Bottom"Cursor="SizeAll"Tag="BottomRight"Grid.RowSpan="3"/></Grid></Border></ControlTemplate></Setter></ControlTheme></local:ModernWindowChrome.Theme></local:ModernWindowChrome></ControlTemplate></Setter></Style>

ModernWindowTest.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" Classes="ModernWindow"x:Class="AvaloniaUI.ModernWindowTest"Title="ModernWindowTest"><ModernWindowChrome.Footer><StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Center"><Button Content="OK"/><Button Content="Cancel"/></StackPanel></ModernWindowChrome.Footer>Welcome to Avalonia!
</Window>

ModernWindowTest.axaml.cs代码

using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Shares.Avalonia;namespace AvaloniaUI;public partial class ModernWindowTest : Window
{public ModernWindowTest(){InitializeComponent();this.Load("avares://Shares/Avalonia/Styles/Styles.axaml");//这里是置顶里写的扩展,如果不用,可以自行加到App.axaml中}
}

运行效果

image

 

http://www.jsqmd.com/news/522166/

相关文章:

  • 2026年市面上口碑好的茶叶压饼成型液压机源头厂家推荐榜单,普洱茶茶饼压制/紧压茶成型/茶叶压块/自动化生产线,茶叶压饼成型液压机制造企业哪家权威 - 品牌推广师
  • ESP32-CAM变身RTSP监控摄像头:手把手教你用M5Stack搭建家庭安防系统
  • 图片AI不是噱头,已批量交付!创材深造半年推出13款金属3D打印材料
  • 了解纽兰机械销售额增长趋势,对企业选择有啥影响? - 工业品网
  • 2026年常州网布袋切缝机选购指南,价格适中型号排名 - 工业品牌热点
  • 2026年贵州钻水井服务市场观察:贵阳、遵义、毕节、安顺、凯里地区靠谱企业评估与推荐 - 深度智识库
  • AI让你一周做出产品?恭喜,你大概率又做了一个没市场的玩意儿
  • 2026年广西地区可靠的开箱机生产企业推荐,费用怎么算? - myqiye
  • XZ6318输入电压18V 输出电压1.5-5V 输出电流300mA
  • jquery.validate,自定义错误
  • 分享2026年好用的挥手感应吸油烟机品牌,电机质量哪家靠谱 - mypinpai
  • 博客园发布脚本优化总结test - a
  • 探寻2026年电声元器件制造厂排名,专业靠谱的选哪家 - 工业推荐榜
  • 2026实战:机械厂获客成本飙升?这5个垂直推广平台让询盘量翻倍! - 品牌推荐大师1
  • 切片
  • 了解2026年东光优质锅炉制造厂家分析,选锅炉不迷路,蒸汽锅炉/锅炉/导热油锅炉,锅炉销售厂家分析 - 品牌推荐师
  • 从商宇UPS到微模块数据中心,看四川骏杨明如何定义2026机房基础设施价值 - 速递信息
  • 预算有限怎么租最划算?2026年四川地区彩色复印机、会议设备租赁性价比排名 - 速递信息
  • 2026年常州稳定型网眼袋切缝机费用多少,哪家值得选 - 工业设备
  • 如何选择防辐射工程方案?2026四川成都医用铅门铅玻璃施工厂家排名解析 - 速递信息
  • 2026年制袋机口碑排行榜,含节能改造、来样定制与半自动款式 - 工业品牌热点
  • 2026 年贵州波纹管优质实力厂家盘点 靠谱可靠口碑优选 - 深度智识库
  • SAP-ABAP-SLAV用法
  • 从零实现富文本编辑器#12-React可编辑节点的组件预设
  • 2026 年贵州 PE 管优质实力厂家盘点 靠谱可靠品牌选购指南 - 深度智识库
  • 立足成都,服务四川:2026年辐射防护铅门、铅玻璃、硫酸钡板实力厂家口碑盘点与推荐 - 速递信息
  • 2026年GEO优化服务商深度技术测评:五家厂商全链路解决方案拆解 - 品牌推荐
  • 常州编织袋自动切缝机口碑好的厂家有哪些 - myqiye
  • 2026中小企业CRM深度横评:从客户管理到外勤管理的全维度对决 - jfjfkk-
  • 聊聊2026年佛山口碑好的蜂鸣器厂家,靠谱之选怎么选择 - 工业品网