WPF-ToolBarTray,ToolBar,StatusBar
目录
在 Windows Presentation Foundation中,ToolBarTray、ToolBar、StatusBar是典型的"命令承载与状态反馈"UI结构组件。
一、ToolBarTray
ToolBarTray 是 ToolBar 的容器管理器,用于:
-
承载多个 ToolBar
-
支持 ToolBar 分组排列(行 / 列)
-
支持拖拽重排(Band / BandIndex)
-
支持 ToolBar 停靠行为
ToolBarTray = “可编排工具栏宿主”
核心属性:
| 属性 | 作用 |
|---|---|
| Orientation | 工具栏排列方向 |
| IsLocked | 是否禁止拖动 |
| Background | 背景 |
| ToolBars | 子工具栏集合 |
ToolBar 上的重要属性:
| 属性 | 作用 |
|---|---|
| Band | 所在行 |
| BandIndex | 行内顺序 |
| Header | 标题 |
| OverflowMode | 溢出策略 |
使用场景:
- CAD 系统
- 报表设计器
- 编辑器(文本,图片,流程)
- 企业后台复杂管理系统
**适合:**功能多,操作频繁,需要分组命令
**不适合:**简单的CRUD页面,简单的CRUD页面使用Ribbon或普通按钮更便利一点。
二、ToolBar
ToolBar是命令按钮的承载容器。
支持放置:
- Button
- ToggleButton
- ComboBox
- TextBox
- Separator
- 自定义控件
内部自带:
- 溢出面板
- 键盘导航
- 样式支持
适合场景:
- 命令高频
- 命令具有明显分组
- 适合放图标性操作
不适合放复杂表单
三、StatusBar
StatusBar 用于:展示系统当前状态 / 反馈信息
常见内容:
- 当前用户
- 服务器状态
- 选中对象信息
- 鼠标坐标
- 进度条
- 日志提示
使用场景:
- 文本编辑器(字数统计)
- 图像软件(分辨率)
- ERP系统(连接状态)
- 数据采集系统(实时数值)
三者的协作模式
标准布局结构:
DockPanel
├── ToolBarTray (Top)
├── 主内容区域
└── StatusBar (Bottom)形成:
- 命令输入(ToolBar)
- 业务处理(Content)
- 状态反馈(StatusBar)
深入使用场景
- ToolBarTray & ToolBar: 如果你只需要一行固定的按钮,直接用
ToolBar。但如果你想模仿 Office 或 Visual Studio 那种可拖拽、多行排列的界面,必须使用ToolBarTray。它能自动处理子级ToolBar的换行(Band 属性)和溢出处理。 - StatusBar: 它是应用与用户的“悄悄话”窗口。不要在状态栏放核心业务按钮,它应该保持低干扰性。
示例:
<Window
x:Class="demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:demo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<DockPanel>
<!-- 1. ToolBarTray 区域 -->
<ToolBarTray Background="GhostWhite" DockPanel.Dock="Top">
<!-- 第一个工具栏 (Band 0) -->
<ToolBar Band="0" BandIndex="0">
<Button Command="{Binding SaveCommand}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,0,5,0" Text="💾" />
<TextBlock Text="保存" />
</StackPanel>
</Button>
<Separator />
<Button Content="新建" />
<Button Content="打开" />
</ToolBar>
<!-- 第二个工具栏 (Band 0,会接在后面或另起一行) -->
<ToolBar Band="0" BandIndex="1">
<ComboBox Width="120" SelectedIndex="0">
<ComboBoxItem Content="微软雅黑" />
<ComboBoxItem Content="Consolas" />
</ComboBox>
<ToggleButton
Width="30"
Content="B"
FontWeight="Bold" />
<ToggleButton
Width="30"
Content="I"
FontStyle="Italic" />
</ToolBar>
</ToolBarTray>
<!-- 2. StatusBar 区域 -->
<StatusBar Background="#F0F0F0" DockPanel.Dock="Bottom">
<StatusBarItem>
<TextBlock Text="{Binding StatusMessage}" />
</StatusBarItem>
<Separator />
<StatusBarItem>
<ProgressBar
Width="100"
Height="15"
Value="{Binding ProgressValue}" />
</StatusBarItem>
<StatusBarItem HorizontalAlignment="Right">
<TextBlock Margin="0,0,10,0" Text="UTF-8" />
</StatusBarItem>
</StatusBar>
<!-- 3. 主内容区域 -->
<Grid>
<TextBox
Padding="10"
AcceptsReturn="True"
Text="在工具栏点击保存或处理,观察状态栏变化。你可以尝试拖动工具栏左侧的把手来移动它。" />
<Button
Margin="20"
Padding="10,5"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Command="{Binding ProcessCommand}"
Content="开始后台处理" />
</Grid>
</DockPanel>
</Window>using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace demo
{
public class MainViewModel : INotifyPropertyChanged
{
private string _statusMessage = "就绪";
private int _progressValue = 0;
public string StatusMessage
{
get => _statusMessage;
set { _statusMessage = value; OnPropertyChanged(); }
}
public int ProgressValue
{
get => _progressValue;
set { _progressValue = value; OnPropertyChanged(); }
}
// 命令定义
public ICommand SaveCommand { get; }
public ICommand ProcessCommand { get; }
public MainViewModel()
{
SaveCommand = new RelayCommand(_ => StatusMessage = $"文件已于 {DateTime.Now:T} 保存");
ProcessCommand = new RelayCommand(_ => SimulateWork());
}
private async void SimulateWork()
{
StatusMessage = "正在处理数据...";
for (int i = 0; i <= 100; i += 10)
{
ProgressValue = i;
await System.Threading.Tasks.Task.Delay(200);
}
StatusMessage = "处理完成!";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}