添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

WPF 入门教程ToolBar和StatusBar

工具栏是一行命令,通常位于标准 Windows 应用程序主菜单的正下方。这实际上可能是一个带有按钮的简单面板,但是通过使用 WPF ToolBar 控件,您可以获得一些额外的好处,例如自动溢出处理以及最终用户重新定位工具栏的可能性。

WPF ToolBar 通常放置在 ToolBarTray 控件内。ToolBarTray 将处理诸如放置和调整大小之类的事情,并且您可以在 ToolBarTray 元素内拥有多个 ToolBar 控件。让我们尝试一个非常基本的例子,看看它是什么样的:

<Window x:Class="WpfTutorialSamples.Common_interface_controls.ToolbarSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ToolbarSample" Height="200" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="New" CanExecute="CommonCommandBinding_CanExecute" />
        <CommandBinding Command="Open" CanExecute="CommonCommandBinding_CanExecute" />
        <CommandBinding Command="Save" CanExecute="CommonCommandBinding_CanExecute" />
    </Window.CommandBindings>
    <DockPanel>
        <ToolBarTray DockPanel.Dock="Top">
            <ToolBar>
                <Button Command="New" Content="New" />
                <Button Command="Open" Content="Open" />
                <Button Command="Save" Content="Save" />
            </ToolBar>
            <ToolBar>
                <Button Command="Cut" Content="Cut" />
                <Button Command="Copy" Content="Copy" />
                <Button Command="Paste" Content="Paste" />
            </ToolBar>
        </ToolBarTray>
        <TextBox AcceptsReturn="True" />
    </DockPanel>
</Window>


using System;
using System.Windows;
using System.Windows.Input;
namespace WpfTutorialSamples.Common_interface_controls
	public partial class ToolbarSample : Window
		public ToolbarSample()
			InitializeComponent();
		private void CommonCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
			e.CanExecute = true;

请注意我如何为所有按钮使用命令。我们在前一章讨论过这个问题,使用命令肯定会给我们带来一些好处。查看菜单章节或有关命令的文章,了解更多信息。

在此示例中,我将 ToolBarTray 添加到屏幕顶部,并在其中添加了两个 ToolBar 控件。每个都包含一些按钮,我们使用命令来赋予它们它们的行为。在代码隐藏中,我确保处理前三个按钮的 CanExecute 事件,因为这不是由 WPF 自动完成的,这与剪切、复制和粘贴命令相反,WPF 能够为我们完全处理这些命令。

尝试运行该示例并将光标放在工具栏之一的左侧部分(虚线区域)。如果您单击并按住鼠标左键,您现在可以重新定位工具栏,例如在另一个下方,甚至使它们切换位置。

图片

虽然工具栏按钮上的文本完全可以,但通常的方法是使用图标或至少是图标和一段文本的组合。由于 WPF 使用常规 Button 控件,因此向工具栏项添加图标非常容易。看看下一个例子,我们都做:

<Window x:Class="WpfTutorialSamples.Common_interface_controls.ToolbarIconSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ToolbarIconSample" Height="200" Width="300">
    <DockPanel>
        <ToolBarTray DockPanel.Dock="Top">
            <ToolBar>
                <Button Command="Cut" ToolTip="Cut selection to Windows Clipboard.">
                    <Image Source="/WpfTutorialSamples;component/Images/cut.png" />
                </Button>
                <Button Command="Copy" ToolTip="Copy selection to Windows Clipboard.">
                    <Image Source="/WpfTutorialSamples;component/Images/copy.png" />
                </Button>
                <Button Command="Paste" ToolTip="Paste from Windows Clipboard.">
                    <StackPanel Orientation="Horizontal">
                        <Image Source="/WpfTutorialSamples;component/Images/paste.png" />
                        <TextBlock Margin="3,0,0,0">Paste</TextBlock>
                    </StackPanel>
                </Button>
            </ToolBar>
        </ToolBarTray>
        <TextBox AcceptsReturn="True" />
    </DockPanel>
</Window>

通过将 图像 控件指定为前两个按钮的内容,它们将基于图标而不是基于文本。在第三个按钮上,我在 StackPanel 中 组合了 Image 控件和 TextBlock 控件,以实现按钮上的图标和文本,这是一种常用的技术,用于特别重要或图标不太明显的按钮。

请注意我是如何在每个按钮上使用 ToolTip 属性来添加解释性文本的。这对于那些只有图标的按钮尤其重要,因为仅查看图标可能无法清楚按钮的用途。使用 ToolTip 属性,用户可以将鼠标悬停在按钮上以获取其功能的描述,如屏幕截图所示。

溢出

正如已经提到的,使用 ToolBar 控件而不仅仅是按钮面板的一个很好的理由是自动溢出处理。这意味着如果不再有足够的空间来显示工具栏上的所有按钮,WPF 会将它们放在一个菜单中,该菜单可通过单击工具栏右侧的箭头来访问。您可以在此屏幕截图上看到它是如何工作的,它显示了第一个示例,但窗口较小,从而为工具栏留下了较少的空间:

WPF 甚至允许您决定哪些项目适合溢出隐藏,哪些应该始终可见。通常,在设计工具栏时,有些项目不如其他项目重要,而有些项目您甚至可能希望一直显示在溢出菜单中,无论空间是否足够。

这是附加属性 ToolBar.OverflowMode 发挥作用的地方。默认值是 AsNeeded,这只是意味着如果没有足够的空间,则将工具栏项放入溢出菜单中。您可以使用 Always Never 来代替,这正是名称所暗示的: 始终 将项目放在溢出菜单中或防止该项目被移动到溢出菜单。以下是有关如何分配此属性的示例:

<ToolBar>
    <Button Command="Cut" Content="Cut" ToolBar.OverflowMode="Always" />
    <Button Command="Copy" Content="Copy" ToolBar.OverflowMode="AsNeeded" />
    <Button Command="Paste" Content="Paste" ToolBar.OverflowMode="Never" />
</ToolBar>

位置

虽然工具栏最常见的位置确实在屏幕顶部,但也可以在应用程序窗口的底部甚至两侧找到工具栏。WPF 工具栏当然支持所有这些,虽然底部放置的工具栏只是停靠到面板底部而不是顶部,垂直工具栏需要使用工具栏托盘的 方向 属性。请允许我用一个例子来演示:

<Window x:Class="WpfTutorialSamples.Common_interface_controls.ToolbarPositionSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ToolbarPositionSample" Height="200" Width="300">
	<DockPanel>
		<ToolBarTray DockPanel.Dock="Top">
			<ToolBar>
				<Button Command="Cut" ToolTip="Cut selection to Windows Clipboard.">
					<Image Source="/WpfTutorialSamples;component/Images/cut.png" />
				</Button>
				<Button Command="Copy" ToolTip="Copy selection to Windows Clipboard.">
					<Image Source="/WpfTutorialSamples;component/Images/copy.png" />
				</Button>
				<Button Command="Paste" ToolTip="Paste from Windows Clipboard.">
					<StackPanel Orientation="Horizontal">
						<Image Source="/WpfTutorialSamples;component/Images/paste.png" />
						<TextBlock Margin="3,0,0,0">Paste</TextBlock>
					</StackPanel>
				</Button>
			</ToolBar>
		</ToolBarTray>
		<ToolBarTray DockPanel.Dock="Right" Orientation="Vertical">
			<ToolBar>
				<Button Command="Cut" ToolTip="Cut selection to Windows Clipboard.">
					<Image Source="/WpfTutorialSamples;component/Images/cut.png" />
				</Button>
				<Button Command="Copy" ToolTip="Copy selection to Windows Clipboard.">
					<Image Source="/WpfTutorialSamples;component/Images/copy.png" />
				</Button>
				<Button Command="Paste" ToolTip="Paste from Windows Clipboard.">
					<Image Source="/WpfTutorialSamples;component/Images/paste.png" />
				</Button>
			</ToolBar>
		</ToolBarTray>
		<TextBox AcceptsReturn="True" />
	</DockPanel>
</Window>

这里的技巧在于结合 DockPanel.Dock 属性,将 ToolBarTray 放在应用程序的右侧,以及 Orientation 属性,将方向从水平更改为垂直。这使得将工具栏放置在您可能想到的几乎任何位置成为可能。

工具栏上的自定义控件

正如您在前面所有示例中看到的那样,我们在工具栏上使用常规 WPF 按钮控件。这也意味着您可以在工具栏上放置几乎任何其他 WPF 控件,而无需额外的努力。当然,有些控件在工具栏上的效果比其他控件更好,但是像 ComboBox 和 TextBox 这样的控件通常用于旧版本的 Microsoft Office 的工具栏上,您可以在自己的 WPF 工具栏上做同样的事情。

此示例中引入的另一件事是 Separator 元素,它只是在两组工具栏项之间创建一个分隔符。从示例中可以看出,它非常易于使用!

<Window x:Class="WpfTutorialSamples.Common_interface_controls.ToolbarCustomControlsSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ToolbarCustomControlsSample" Height="200" Width="300">
	<DockPanel>
		<ToolBarTray DockPanel.Dock="Top">
			<ToolBar>
				<Button Command="Cut" ToolTip="Cut selection to Windows Clipboard.">
					<Image Source="/WpfTutorialSamples;component/Images/cut.png" />
				</Button>
				<Button Command="Copy" ToolTip="Copy selection to Windows Clipboard.">
					<Image Source="/WpfTutorialSamples;component/Images/copy.png" />
				</Button>
				<Button Command="Paste" ToolTip="Paste from Windows Clipboard.">
					<StackPanel Orientation="Horizontal">
						<Image Source="/WpfTutorialSamples;component/Images/paste.png" />
						<TextBlock Margin="3,0,0,0">Paste</TextBlock>
					</StackPanel>
				</Button>
				<Separator />
				<Label>Font size:</Label>
				<ComboBox>
					<ComboBoxItem>10</ComboBoxItem>
					<ComboBoxItem IsSelected="True">12</ComboBoxItem>
					<ComboBoxItem>14</ComboBoxItem>
					<ComboBoxItem>16</ComboBoxItem>
				</ComboBox>
			</ToolBar>
		</ToolBarTray>
		<TextBox AcceptsReturn="True" />
	</DockPanel>
</Window>


2:状态栏

应用程序窗口的顶部通常被主菜单和/或工具栏占据,如前几章所述,窗口的底部通常是状态栏的主页。状态栏用于显示有关应用程序当前状态的各种信息,如光标位置、字数、任务进度等。对我们来说幸运的是,WPF 带有一个很好的 StatusBar 控件,可以很容易地将状态栏功能添加到您的应用程序中。

<Window x:Class="WpfTutorialSamples.Common_interface_controls.StatusBarSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="StatusBarSample" Height="150" Width="300">
	<DockPanel>
		<StatusBar DockPanel.Dock="Bottom">
			<StatusBarItem>
				<TextBlock Name="lblCursorPosition" />
			</StatusBarItem>
		</StatusBar>
		<TextBox AcceptsReturn="True" Name="txtEditor" SelectionChanged="txtEditor_SelectionChanged" />
	</DockPanel>
</Window>
using System;
using System.Windows;
namespace WpfTutorialSamples.Common_interface_controls
	public partial class StatusBarSample : Window
		public StatusBarSample()
			InitializeComponent();
		private void txtEditor_SelectionChanged(object sender, RoutedEventArgs e)
			int row = txtEditor.GetLineIndexFromCharacterIndex(txtEditor.CaretIndex);
			int col = txtEditor.CaretIndex - txtEditor.GetCharacterIndexFromLineIndex(row);
			lblCursorPosition.Text = "Line " + (row + 1) + ", Char " + (col + 1);
}

这一切都非常简单 - 一个显示当前光标位置的 TextBlock 控件,就像在几乎任何其他允许您编辑文本的应用程序中一样。在这个非常基本的形式中,StatusBar 可以很容易地成为一个带有一组控件的面板,但是当我们需要将它分成几个信息区域时,StatusBar 的真正优势就出现了。

高级状态栏示例

让我们尝试使用 StatusBar 的更高级示例。我们要做的第一件事是让 StatusBar 使用另一个面板进行布局。默认情况下,它使用 DockPanel ,但是当我们想要更复杂的布局时,列以某种方式调整其宽度并对齐内容, Grid 是更好的选择。

我们将 Grid 分成三个区域,左右两个区域固定宽度,中间一列自动占据剩余空间。我们还将为 Separator 控件在它们之间添加列。这是它现在的样子:

<Window x:Class="WpfTutorialSamples.Common_interface_controls.StatusBarAdvancedSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="StatusBarAdvancedSample" Height="150" Width="400">
    <DockPanel>
        <StatusBar DockPanel.Dock="Bottom">
            <StatusBar.ItemsPanel>
                <ItemsPanelTemplate>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="100" />
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </StatusBar.ItemsPanel>
            <StatusBarItem>
                <TextBlock Name="lblCursorPosition" />
            </StatusBarItem>
            <Separator Grid.Column="1" />
            <StatusBarItem Grid.Column="2">
                <TextBlock Text="c:\path\of\current\file.txt" />
            </StatusBarItem>
            <Separator Grid.Column="3" />
            <StatusBarItem Grid.Column="4">
                <ProgressBar Value="50" Width="90" Height="16" />
            </StatusBarItem>
        </StatusBar>
        <TextBox AcceptsReturn="True" Name="txtEditor" SelectionChanged="txtEditor_SelectionChanged" />
    </DockPanel>
</Window>


using System;
using System.Windows;
namespace WpfTutorialSamples.Common_interface_controls
	public partial class StatusBarAdvancedSample : Window
		public StatusBarAdvancedSample()
			InitializeComponent();
		private void txtEditor_SelectionChanged(object sender, RoutedEventArgs e)
			int row = txtEditor.GetLineIndexFromCharacterIndex(txtEditor.CaretIndex);