Files

487 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Window 使用文档
本文档介绍 AtomUI Window 控件的各种使用方式,示例代码参考自 Gallery 演示程序。
> 📖 Gallery 主窗口源码位置:`controlgallery/AtomUIGallery/Workspace/Views/WorkspaceWindow.axaml`
---
## 前置准备
在 AXAML 中使用 Window,需要引入以下命名空间:
```xml
xmlns:atom="https://atomui.net"
```
或使用 `using` 语法:
```xml
xmlns:atom="using:AtomUI.Desktop.Controls"
```
在 C# 代码中引入:
```csharp
using AtomUI.Desktop.Controls; // Window, ReactiveWindow<T>
using AtomUI.Controls; // MediaBreakPoint 等共享类型
```
---
## 1. 基本窗口
最基本的 Window 用法,设置标题、大小和启动位置:
```xml
<atom:Window xmlns="https://github.com/avaloniaui"
xmlns:atom="https://atomui.net"
Title="我的应用程序"
Width="1200" Height="800"
WindowStartupLocation="CenterScreen">
<TextBlock Text="Hello, AtomUI!" />
</atom:Window>
```
---
## 2. 设置窗口 Logo
通过 `Logo` 属性在标题栏显示应用程序图标:
```xml
<atom:Window Title="我的应用程序"
WindowStartupLocation="CenterScreen"
Width="1200" Height="800">
<atom:Window.Logo>
<Image Source="/Assets/app-logo.png" />
</atom:Window.Logo>
<!-- 窗口内容 -->
</atom:Window>
```
> 📖 参考:`controlgallery/AtomUIGallery/Workspace/Views/WorkspaceWindow.axaml` 中 Logo 设置。
---
## 3. 配置标题按钮
Window 提供多个标题按钮配置属性,可灵活控制标题栏功能按钮的显示/隐藏:
```xml
<!-- 显示置顶(Pin)按钮和全屏按钮 -->
<atom:Window IsPinCaptionButtonEnabled="True"
IsFullScreenCaptionButtonEnabled="True"
Title="全功能窗口">
<!-- 内容 -->
</atom:Window>
<!-- 禁用关闭按钮(macOS 下红绿灯中的关闭按钮变灰) -->
<atom:Window IsCloseCaptionButtonEnabled="False"
Title="不可关闭的窗口">
<!-- 内容 -->
</atom:Window>
```
在代码中动态控制标题按钮(参考 Gallery 示例):
```csharp
// 动态切换全屏按钮显示
IsFullScreenCaptionButtonEnabled = true;
// 动态切换置顶按钮显示
IsPinCaptionButtonEnabled = true;
// 动态切换关闭按钮可用性(macOS 下控制原生红绿灯按钮)
IsCloseCaptionButtonEnabled = false;
```
> 📖 参考:`controlgallery/AtomUIGallery/Workspace/Views/WorkspaceWindow.axaml.cs` 中 `HandleMenuItemCheckChanged` 方法。
---
## 4. 隐藏标题栏
如果需要完全自定义窗口外观,可以隐藏默认标题栏:
```xml
<atom:Window IsTitleBarVisible="False"
Title="无标题栏窗口">
<!-- 需要自行实现关闭/最小化等功能 -->
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal"
HorizontalAlignment="Right">
<atom:Button ButtonType="Text" Content="—" />
<atom:Button ButtonType="Text" Content="✕" />
</StackPanel>
<!-- 主内容 -->
</DockPanel>
</atom:Window>
```
---
## 5. 控制窗口大小和拖拽
### 限制最大尺寸为屏幕比例
```xml
<!-- 窗口最大宽度不超过屏幕的 80%,最大高度不超过 90% -->
<atom:Window MaxWidthScreenRatio="0.8"
MaxHeightScreenRatio="0.9"
Title="受限窗口">
<!-- 内容 -->
</atom:Window>
```
### 禁用窗口拖拽
```xml
<!-- 禁用标题栏拖拽移动 -->
<atom:Window IsMoveEnabled="False" Title="不可移动的窗口">
<!-- 内容 -->
</atom:Window>
```
### 禁用窗口缩放
```xml
<atom:Window CanResize="False" Title="固定大小窗口"
Width="600" Height="400">
<!-- 内容 -->
</atom:Window>
```
### 使用扩展方法居中窗口
```csharp
// 将窗口居中到当前所在屏幕
this.CenterOnScreen();
// 居中到指定屏幕
var screen = this.GetHostScreen();
this.CenterOnScreen(screen);
```
---
## 6. 框架层背景
### 窗口级框架背景
覆盖整个窗口区域(标题栏 + 内容区)的背景装饰:
```xml
<atom:Window Title="渐变背景窗口">
<atom:Window.WindowFrameLayer>
<Border>
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Color="#667eea" Offset="0" />
<GradientStop Color="#764ba2" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
</atom:Window.WindowFrameLayer>
<!-- 内容 -->
</atom:Window>
```
### 内容区域独立背景
仅为内容区域设置背景,不影响标题栏:
```xml
<atom:Window ContentFrameBackground="#f0f2f5" Title="灰色内容区">
<!-- 内容区域有独立背景色 -->
</atom:Window>
```
### 标题栏独立背景
仅为标题栏设置背景色:
```xml
<atom:Window TitleBarFrameBackground="DarkBlue" Title="蓝色标题栏">
<!-- 内容 -->
</atom:Window>
```
### 带不透明度的背景图层
```xml
<atom:Window WindowFrameLayerOpacity="0.15" Title="半透明背景">
<atom:Window.WindowFrameLayer>
<Image Source="/Assets/background-pattern.png" Stretch="UniformToFill" />
</atom:Window.WindowFrameLayer>
<!-- 内容 -->
</atom:Window>
```
---
## 7. ReactiveWindow(MVVM 模式)
### 基本 MVVM 模式
`ReactiveWindow<TViewModel>` 是推荐的 MVVM 窗口基类:
**AXAML:**
```xml
<atom:Window xmlns="https://github.com/avaloniaui"
xmlns:atom="using:AtomUI.Desktop.Controls"
xmlns:vm="using:MyApp.ViewModels"
x:Class="MyApp.Views.MainWindow"
x:DataType="vm:MainViewModel"
Title="MVVM 窗口">
<TextBlock Text="{Binding Greeting}" />
</atom:Window>
```
**C# Code-behind:**
```csharp
using AtomUI.Desktop.Controls;
using MyApp.ViewModels;
namespace MyApp.Views;
public partial class MainWindow : ReactiveWindow<MainViewModel>
{
public MainWindow()
{
DataContext = new MainViewModel();
InitializeComponent();
}
}
```
**ViewModel:**
```csharp
using ReactiveUI;
namespace MyApp.ViewModels;
public class MainViewModel : ReactiveObject, IActivatableViewModel
{
public ViewModelActivator Activator { get; } = new();
private string _greeting = "Hello, AtomUI!";
public string Greeting
{
get => _greeting;
set => this.RaiseAndSetIfChanged(ref _greeting, value);
}
}
```
### ViewModel 自动激活
如果 ViewModel 实现了 `IActivatableViewModel`,窗口显示时自动激活 ViewModel:
```csharp
public class MainViewModel : ReactiveObject, IActivatableViewModel
{
public ViewModelActivator Activator { get; } = new();
public MainViewModel()
{
this.WhenActivated(disposables =>
{
// 窗口显示时执行
Debug.WriteLine("ViewModel activated");
// 订阅自动清理
Observable.Interval(TimeSpan.FromSeconds(1))
.Subscribe(_ => { /* 定时任务 */ })
.DisposeWith(disposables);
});
}
}
```
> 📖 参考:`controlgallery/AtomUIGallery/Workspace/Views/WorkspaceWindow.axaml.cs` 使用了 `ReactiveWindow<WorkspaceWindowViewModel>`。
---
## 8. 响应媒体断点变化
Window 内置的媒体查询系统基于内容区域宽度自动计算断点:
### 通过事件响应
```csharp
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MediaBreakPointChanged += OnMediaBreakPointChanged;
}
private void OnMediaBreakPointChanged(object? sender, MediaBreakPointChangedEventArgs e)
{
switch (e.MediaBreakPoint)
{
case MediaBreakPoint.ExtraSmall:
// ≤ 575px:切换到紧凑布局
break;
case MediaBreakPoint.Small:
// ≥ 576px:显示简化侧边栏
break;
case MediaBreakPoint.Medium:
// ≥ 768px:显示完整侧边栏
break;
case MediaBreakPoint.Large:
// ≥ 992px:标准桌面布局
break;
case MediaBreakPoint.ExtraLarge:
// ≥ 1200px:宽屏布局
break;
case MediaBreakPoint.ExtraExtraLarge:
// ≥ 1600px:超宽屏布局
break;
}
}
}
```
### 通过属性绑定
```xml
<!-- 基于断点控制侧边栏可见性 -->
<Panel>
<DockPanel>
<Border DockPanel.Dock="Left" Width="250"
IsVisible="{Binding MediaBreakPoint,
RelativeSource={RelativeSource AncestorType=atom:Window},
Converter={StaticResource BreakPointToVisibilityConverter}}">
<!-- 侧边栏 -->
</Border>
<!-- 主内容 -->
</DockPanel>
</Panel>
```
---
## 9. macOS 特有配置
在 macOS 上精确控制原生红绿灯按钮位置:
```xml
<atom:Window MacOSCaptionGroupOffset="10, 2"
MacOSCaptionGroupSpacing="5"
Title="macOS 窗口">
<!-- 内容 -->
</atom:Window>
```
> 注意:macOS 红绿灯按钮的位置和间距由 `MacOSCaptionGroupOffset` 和 `MacOSCaptionGroupSpacing` 控制,这些属性仅在 macOS 平台生效。在主题中默认值为 `(10, 2)` 和 `5`。
---
## 10. 获取主窗口引用
在应用程序的任何位置获取主窗口引用:
```csharp
// 静态方法获取主窗口
var mainWindow = Window.GetMainWindow();
if (mainWindow != null)
{
mainWindow.Title = "Updated Title";
}
```
---
## 11. 窗口图标自动继承
子窗口(对话框等)如果没有设置 `Icon`,会自动从主窗口继承图标:
```csharp
// 子窗口自动使用主窗口的图标
var dialog = new Window
{
Title = "Dialog",
Width = 400,
Height = 300,
// Icon 不设置,会自动从主窗口继承
};
dialog.ShowDialog(this);
```
---
## 常见组合模式
### 标准桌面应用窗口
```xml
<atom:Window xmlns="https://github.com/avaloniaui"
xmlns:atom="https://atomui.net"
Title="我的应用"
Icon="/Assets/app.ico"
IsPinCaptionButtonEnabled="True"
WindowStartupLocation="CenterScreen"
Width="1300" Height="900">
<atom:Window.Logo>
<Image Source="/Assets/logo.png" />
</atom:Window.Logo>
<DockPanel LastChildFill="True">
<atom:Menu DockPanel.Dock="Top">
<atom:MenuItem Header="文件" />
<atom:MenuItem Header="编辑" />
<atom:MenuItem Header="帮助" />
</atom:Menu>
<!-- 主内容 -->
<TextBlock Text="主内容区域"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DockPanel>
</atom:Window>
```
> 📖 这正是 Gallery 主窗口 `controlgallery/AtomUIGallery/Workspace/Views/WorkspaceWindow.axaml` 的结构模式。
### 固定尺寸对话框
```xml
<atom:Window Title="设置"
CanResize="False"
CanMinimize="False"
CanMaximize="False"
IsPinCaptionButtonEnabled="False"
IsFullScreenCaptionButtonEnabled="False"
Width="500" Height="400"
WindowStartupLocation="CenterOwner">
<!-- 对话框内容 -->
<StackPanel Margin="20">
<TextBlock Text="设置项..." />
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right" Margin="0,20,0,0">
<atom:Button Margin="0,0,8,0">取消</atom:Button>
<atom:Button ButtonType="Primary">确定</atom:Button>
</StackPanel>
</StackPanel>
</atom:Window>
```
### 带主题切换的窗口
```csharp
// 切换暗色主题
Application.Current?.SetDarkThemeMode(true);
// 切换紧凑模式
Application.Current?.SetCompactThemeMode(true);
// 启用/禁用动画
Application.Current?.SetMotionEnabled(false);
```
> 📖 参考:`controlgallery/AtomUIGallery/Workspace/Views/WorkspaceWindow.axaml.cs` 中完整的主题切换实现。