看见网上一篇文章,写自定义窗口,借花献佛,整理了一下,延续界面演示。
1.定义窗口,去除边框、
设置属性:
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"
2.定义顶端标题框
创建一个用户控件,用来实现顶端控件。
前端代码
<UserControl 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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="CustomTitleBarTemplate.Views.CustomTitleBars.WindowsTitleBar"
DockPanel.Dock="Top">
<StackPanel>
<Grid>
<!--The proper way would be not to use white as default, but somehow retrieve the users' window chrome color.-->
<DockPanel Background="White"
IsHitTestVisible="False"
Name="TitleBarBackground"></DockPanel>
<DockPanel Name="TitleBar">
<StackPanel Orientation="Horizontal"
DockPanel.Dock="Left"
Spacing="0">
<Image Source="/Assets/Images/Icon.ico"
Height="20"
Width="20"
VerticalAlignment="Center"
Margin="5,0,3,0"
Name="WindowIcon"></Image>
<NativeMenuBar DockPanel.Dock="Top"
Width="100"
HorizontalAlignment="Left"
Name="SeamlessMenuBar"></NativeMenuBar>
<TextBlock Text="Custom TitleBar Demo"
FontSize="12"
Foreground="Black"
VerticalAlignment="Center"
IsHitTestVisible="False"
Name="SystemChromeTitle"></TextBlock>
</StackPanel>
<StackPanel Height="22"
HorizontalAlignment="Right"
Orientation="Horizontal"
Spacing="0"
VerticalAlignment="Top">
<Button Width="46"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
BorderThickness="0"
Name="MinimizeButton"
ToolTip.Tip="Minimize">
<Button.Resources>
<CornerRadius x:Key="ControlCornerRadius">0</CornerRadius>
</Button.Resources>
<Button.Styles>
<Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#44AAAAAA"/>
</Style>
<Style Selector="Button:not(:pointerover) /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
</Button.Styles>
<Path Margin="10,0,10,0"
Stretch="Uniform"
VerticalAlignment="Center"
Fill="{DynamicResource SystemControlForegroundBaseHighBrush}"
Data="M2048 1229v-205h-2048v205h2048z"></Path>
</Button>
<Button Width="46"
VerticalAlignment="Stretch"
BorderThickness="0"
Name="MaximizeButton">
<ToolTip.Tip>
<ToolTip Content="Maximize"
Name="MaximizeToolTip"></ToolTip>
</ToolTip.Tip>
<Button.Resources>
<CornerRadius x:Key="ControlCornerRadius">0</CornerRadius>
</Button.Resources>
<Button.Styles>
<Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="#44AAAAAA"/>
</Style>
<Style Selector="Button:not(:pointerover) /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
</Button.Styles>
<Path Margin="10,0,10,0"
Stretch="Uniform"
Fill="{DynamicResource SystemControlForegroundBaseHighBrush}"
Name="MaximizeIcon"
Data="M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z"></Path>
</Button>
<Button Width="46"
VerticalAlignment="Stretch"
BorderThickness="0"
Name="CloseButton"
ToolTip.Tip="Close">
<Button.Resources>
<CornerRadius x:Key="ControlCornerRadius">0</CornerRadius>
</Button.Resources>
<Button.Styles>
<Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Red"/>
</Style>
<Style Selector="Button:not(:pointerover) /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Button:pointerover > Path">
<Setter Property="Fill" Value="White"/>
</Style>
<Style Selector="Button:not(:pointerover) > Path">
<Setter Property="Fill" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
</Style>
</Button.Styles>
<Path Margin="10,0,10,0"
Stretch="Uniform"
Data="M1169 1024l879 -879l-145 -145l-879 879l-879 -879l-145 145l879 879l-879 879l145 145l879 -879l879 879l145 -145z"></Path>
</Button>
</StackPanel>
</DockPanel>
</Grid>
<NativeMenuBar HorizontalAlignment="Left"
Name="DefaultMenuBar"></NativeMenuBar>
</StackPanel>
</UserControl>
后台代码
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace CustomTitleBarTemplate.Views.CustomTitleBars
{
public partial class WindowsTitleBar : UserControl
{
private Button minimizeButton;
private Button maximizeButton;
private Path maximizeIcon;
private ToolTip maximizeToolTip;
private Button closeButton;
private Image windowIcon;
private DockPanel titleBar;
private DockPanel titleBarBackground;
private TextBlock systemChromeTitle;
private NativeMenuBar seamlessMenuBar;
private NativeMenuBar defaultMenuBar;
public static readonly StyledProperty<bool> IsSeamlessProperty =
AvaloniaProperty.Register<WindowsTitleBar, bool>(nameof(IsSeamless));
/// <summary>
/// 窗口移动
/// </summary>
public event EventHandler<PointerPressedEventArgs> OnPointerMouseHander;
public bool IsSeamless
{
get { return GetValue(IsSeamlessProperty); }
set
{
SetValue(IsSeamlessProperty, value);
if (titleBarBackground != null &&
systemChromeTitle != null &&
seamlessMenuBar != null &&
defaultMenuBar != null)
{
titleBarBackground.IsVisible = IsSeamless ? false : true;
systemChromeTitle.IsVisible = IsSeamless ? false : true;
seamlessMenuBar.IsVisible = IsSeamless ? true : false;
defaultMenuBar.IsVisible = IsSeamless ? false : true;
if (IsSeamless == false)
{
titleBar.Resources["SystemControlForegroundBaseHighBrush"] = new SolidColorBrush { Color = new Color(255, 0, 0, 0) };
}
}
}
}
public WindowsTitleBar()
{
this.InitializeComponent();
this.PointerPressed += WindowsTitleBar_PointerPressed; ;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) == false)
{
this.IsVisible = false;
}
else
{
minimizeButton = this.FindControl<Button>("MinimizeButton");
maximizeButton = this.FindControl<Button>("MaximizeButton");
maximizeIcon = this.FindControl<Path>("MaximizeIcon");
maximizeToolTip = this.FindControl<ToolTip>("MaximizeToolTip");
closeButton = this.FindControl<Button>("CloseButton");
windowIcon = this.FindControl<Image>("WindowIcon");
minimizeButton.Click += MinimizeWindow;
maximizeButton.Click += MaximizeWindow;
closeButton.Click += CloseWindow;
windowIcon.DoubleTapped += CloseWindow;
titleBar = this.FindControl<DockPanel>("TitleBar");
titleBarBackground = this.FindControl<DockPanel>("TitleBarBackground");
systemChromeTitle = this.FindControl<TextBlock>("SystemChromeTitle");
seamlessMenuBar = this.FindControl<NativeMenuBar>("SeamlessMenuBar");
defaultMenuBar = this.FindControl<NativeMenuBar>("DefaultMenuBar");
SubscribeToWindowState();
}
}
private void WindowsTitleBar_PointerPressed(object? sender, PointerPressedEventArgs e)
{
if (e.Pointer.Type == PointerType.Mouse)
{
if (OnPointerMouseHander != null)
{
OnPointerMouseHander(sender, e);
}
}
}
private void CloseWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Window hostWindow = (Window)this.VisualRoot;
hostWindow.Close();
}
private void MaximizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Window hostWindow = (Window)this.VisualRoot;
if (hostWindow.WindowState == WindowState.Normal)
{
hostWindow.WindowState = WindowState.Maximized;
}
else
{
hostWindow.WindowState = WindowState.Normal;
}
}
private void MinimizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Window hostWindow = (Window)this.VisualRoot;
hostWindow.WindowState = WindowState.Minimized;
}
private async void SubscribeToWindowState()
{
Window hostWindow = (Window)this.VisualRoot;
while (hostWindow == null)
{
hostWindow = (Window)this.VisualRoot;
await Task.Delay(50);
}
hostWindow.GetObservable(Window.WindowStateProperty).Subscribe(s =>
{
if (s != WindowState.Maximized)
{
maximizeIcon.Data = Geometry.Parse("M2048 2048v-2048h-2048v2048h2048zM1843 1843h-1638v-1638h1638v1638z");
hostWindow.Padding = new Thickness(0,0,0,0);
maximizeToolTip.Content = "Maximize";
}
if (s == WindowState.Maximized)
{
maximizeIcon.Data = Geometry.Parse("M2048 1638h-410v410h-1638v-1638h410v-410h1638v1638zm-614-1024h-1229v1229h1229v-1229zm409-409h-1229v205h1024v1024h205v-1229z");
hostWindow.Padding = new Thickness(7,7,7,7);
maximizeToolTip.Content = "Restore Down";
// This should be a more universal approach in both cases, but I found it to be less reliable, when for example double-clicking the title bar.
/*hostWindow.Padding = new Thickness(
hostWindow.OffScreenMargin.Left,
hostWindow.OffScreenMargin.Top,
hostWindow.OffScreenMargin.Right,
hostWindow.OffScreenMargin.Bottom);*/
}
});
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
在Window窗口中使用
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:WindowAvalonia.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="WindowAvalonia.Views.MainWindow"
xmlns:titlebars="clr-namespace:CustomTitleBarTemplate.Views.CustomTitleBars;assembly=WindowAvalonia"
x:DataType="vm:MainWindowViewModel"
WindowStartupLocation="CenterScreen"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"
Icon="/Assets/avalonia-logo.ico"
Title="WindowAvalonia">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<NativeMenu.Menu>
<NativeMenu>
<NativeMenuItem Header="File">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Open"/>
<NativeMenuItem Header="Recent">
<NativeMenuItem.Menu>
<NativeMenu/>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItem Header="Quit Avalonia"
Gesture="CTRL+Q"
Command="{Binding QuitProgramCommand}"/>
</NativeMenu>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItem Header="Edit">
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Copy"/>
<NativeMenuItem Header="Paste"/>
</NativeMenu>
</NativeMenuItem.Menu>
</NativeMenuItem>
</NativeMenu>
</NativeMenu.Menu>
<Window.KeyBindings>
<KeyBinding Gesture="CTRL+Q"
Command="{Binding QuitProgramCommand}"></KeyBinding>
</Window.KeyBindings>
<DockPanel HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Name="ContentWrapper">
<titlebars:WindowsTitleBar IsSeamless="True" Name="titleBar" Background="rgb(30,159,255)" BorderBrush="rgb(196,230,255)"> </titlebars:WindowsTitleBar>
<DockPanel Background="Transparent">
<StackPanel HorizontalAlignment="Left"
VerticalAlignment="Top"
Orientation="Horizontal"
Spacing="10">
<SplitButton Content="连接">
<SplitButton.Flyout>
<MenuFlyout Placement="Bottom">
<MenuItem Header="项目1">
<MenuItem Header="子项1" />
<MenuItem Header="子项2" />
<MenuItem Header="子项3" />
</MenuItem>
<MenuItem Header="项目2"
InputGesture="Ctrl+A" />
<MenuItem Header="项目3" />
</MenuFlyout>
</SplitButton.Flyout>
</SplitButton>
<Button Content="新建"></Button>
</StackPanel>
<DockPanel>
<TreeView BorderBrush="Green">
</TreeView>
<TabControl BorderBrush="Red"></TabControl>
<TextBlock Padding="10"></TextBlock>
</DockPanel>
</DockPanel>
</DockPanel>
</Window>
using Avalonia.Controls;
namespace WindowAvalonia.Views
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
titleBar.OnPointerMouseHander += TitleBar_OnPointerMouseHander; ;
}
private void TitleBar_OnPointerMouseHander(object? sender, Avalonia.Input.PointerPressedEventArgs e)
{
this.BeginMoveDrag(e);
}
}
}
运行效果
目前没有收集到大家 感兴趣的东西写,先以此界面,仿照navicat吧