- XAML 教程
- XAML - 首页
- XAML - 概述
- XAML - 环境设置
- 在 macOS 上编写 XAML 应用程序
- XAML 与 C# 代码对比
- XAML 与 VB.NET 对比
- XAML - 构建块
- XAML - 控件
- XAML - 布局
- XAML - 事件处理
- XAML - 数据绑定
- XAML - 标记扩展
- XAML - 依赖属性
- XAML - 资源
- XAML - 模板
- XAML - 样式
- XAML - 触发器
- XAML - 调试
- XAML - 自定义控件
- XAML 有用资源
- XAML 快速指南
- XAML - 有用资源
- XAML - 讨论
XAML 快速指南
XAML - 概述
XAML 代表可扩展应用程序标记语言 (Extensible Application Markup Language)。它是一种基于 XML 的简单声明式语言。
在 XAML 中,创建、初始化和设置具有层次关系的对象属性非常容易。
它主要用于设计 GUI。
它也可以用于其他目的,例如,在工作流基础中声明工作流。
XAML 可用于不同的平台,例如 WPF(Windows Presentation Foundation)、Silverlight、移动开发和 Windows 应用商店应用。它可以在不同的 .NET 框架和 CLR(公共语言运行时)版本中使用。
XAML 的工作原理
XAML 是一种声明式语言,因为它定义了您想要做什么的目标和方法。XAML 处理器负责找出方法部分。让我们看一下下面的模式。它总结了 XAML 的方面:
该图说明了以下操作:
XAML 文件由特定于平台的 XAML 处理器解释。
XAML 处理器将 XAML 转换为描述 UI 元素的内部代码。
内部代码和 C# 代码通过部分类定义链接在一起,然后 .NET 编译器构建应用程序。
XAML 的优点
使用 XAML 可以解决我们在 GUI 设计中长期面临的一个问题。它可以用于设计 Windows 窗体应用程序中的 UI 元素。
在早期的 GUI 框架中,应用程序的外观和行为之间没有真正的分离。GUI 和其行为都在同一种语言(例如 C# 或 VB.net)中创建,这需要开发人员付出更多努力来实现 UI 及其相关的行为。
使用 XAML,很容易将行为与设计代码分离。因此,XAML 程序员和设计师可以并行工作。XAML 代码非常易于阅读和理解。
XAML - 环境设置
Microsoft 提供了两个重要的 XAML 工具:
- Visual Studio
- Expression Blend
目前,这两个工具都可以创建 XAML,但事实是 Visual Studio 更受开发人员使用,而 Expression Blend 仍然更常被设计师使用。
Microsoft 提供了 Visual Studio 的免费版本,可以从 https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx 下载
注意 -在本教程中,我们将主要使用 WPF 项目和 Windows 应用商店应用。但是 Visual Studio 的免费版本不支持 Windows 应用商店应用。因此,为此目的,您需要 Visual Studio 的许可版本。
安装
按照以下步骤在您的系统上安装 Visual Studio:
下载文件后,运行安装程序。将显示以下对话框。
单击“安装”按钮,它将启动安装过程。
安装过程成功完成后,您将看到以下屏幕。
关闭此对话框,如果需要,重新启动计算机。
现在从“开始”菜单打开 Visual Studio,它将显示以下对话框。第一次需要一些时间,仅用于准备。
完成后,您将看到 Visual Studio 的主窗口。
实现的第一步
让我们从一个简单的实现开始。请按照以下步骤操作:
单击“文件”→“新建”→“项目”菜单选项。
将显示以下对话框:
在“模板”下,选择 Visual C# 并选择 WPF 应用程序。为项目命名,然后单击“确定”按钮。
在 mainwindow.xaml 文件中,默认情况下会编写以下 XAML 标记。您将在本教程的后面部分了解所有这些标记。
<Window x:Class = "FirstStepDemo.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:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local = "clr-namespace:FirstStepDemo" mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604"> <Grid> </Grid> </Window>
默认情况下,网格被设置为页面后的第一个元素。
让我们在 Grid 元素下添加一个按钮和一个文本块。这称为对象元素语法,左尖括号后跟我们要实例化的内容的名称,例如按钮,然后定义一个内容属性。分配给 Content 的字符串将显示在按钮上。现在将按钮的高度和宽度分别设置为 30 和 50。同样初始化文本块的属性。
现在查看设计窗口。您将看到一个按钮。现在按 F5 执行此 XAML 代码。
<Window x:Class = "FirstStepDemo.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:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local = "clr-namespace:FirstStepDemo" mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <Button Content = "First Button" Height = "30" Width = "80"/> <TextBlock Text = "Congratulations you have successfully build your first app" Height = "30" Margin = "162,180,122,109"/> </Grid> </Window>
编译并执行上述代码后,您将看到以下窗口。
恭喜!您已经设计了您的第一个按钮。
在 macOS 上编写 XAML 应用程序
XAML 应用程序也可以在 Mac 上开发。在 Mac 上,XAML 可用作 iOS 和 Android 应用程序。要在 Mac 上设置环境,请访问 www.xamarin.com。单击“产品”,然后选择 Xamarin 平台。下载并安装 Xamarin Studio。它将允许您为各种平台开发应用程序。
XAML – C# 语法
本章将学习编写 XAML 应用程序的基本 XAML 语法/规则。让我们来看一个简单的 XAML 文件。
<Window x:Class = "Resources.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "525"> <Grid> </Grid> </Window>
正如您在上面的 XAML 文件中看到的,有不同类型的标记和元素。下表简要描述了所有元素。
序号 | 元素和描述 |
---|---|
1 | <Window 它是根的起始对象元素或容器。 |
2 | x:Class="Resources.MainWindow" 它是部分类声明,它将标记连接到在其中定义的代码隐藏部分类。 |
3 | xmlns 映射 WPF 客户端/框架的默认 XAML 命名空间 |
4 | xmlns:x XAML 语言的 XAML 命名空间,将其映射到 x: 前缀 |
5 | > 根对象的元素结束。 |
6 | <Grid> </Grid> 空网格对象的起始和结束标记。 |
7 | </Window> 关闭对象元素 |
对象元素的语法规则
XAML 的语法规则几乎与 XML 相同。如果您查看 XAML 文档,您会注意到它实际上是一个有效的 XML 文件。但是,XML 文件不可能是有效的 XAML 文件。这是因为在 XML 中,属性的值必须是字符串,而在 XAML 中,它可以是不同的对象,称为属性元素语法。
对象元素的语法以左尖括号 (<) 开头,后跟对象的名称,例如 Button。
定义该对象元素的一些属性。
对象元素必须用正斜杠 (/) 关闭,然后紧跟右尖括号 (>)。
没有子元素的简单对象的示例:
<Button/>
带有一些属性的对象元素示例:
<Button Content = "Click Me" Height = "30" Width = "60"/>
定义属性的替代语法的示例(属性元素语法):
<Button> <Button.Content>Click Me</Button.Content> <Button.Height>30</Button.Height> <Button.Width>60</Button.Width> </Button>
带子元素的对象示例 - StackPanel 包含 Textblock 作为子元素
<StackPanel Orientation = "Horizontal"> <TextBlock Text = "Hello"/> </StackPanel>
XAML 与 C# 代码对比
您可以使用 XAML 创建、初始化和设置对象的属性。相同的活动也可以使用编程代码执行。
XAML 只是一种简单易用的设计 UI 元素的方法。使用 XAML,您可以决定是在 XAML 中声明对象还是使用代码声明它们。
让我们来看一个简单的例子,演示如何在 XAML 中编写:
<Window x:Class = "XAMLVsCode.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "525"> <StackPanel> <TextBlock Text = "Welcome to XAML Tutorial" Height = "20" Width = "200" Margin = "5"/> <Button Content = "Ok" Height = "20" Width = "60" Margin = "5"/> </StackPanel> </Window>
在这个例子中,我们创建了一个包含按钮和文本块的堆叠面板,并定义了按钮和文本块的一些属性,例如高度、宽度和边距。编译并执行上述代码后,将生成以下输出:
现在来看一下用 C# 编写的相同代码。
using System; using System.Text; using System.Windows; using System.Windows.Controls; namespace XAMLVsCode { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // Create the StackPanel StackPanel stackPanel = new StackPanel(); this.Content = stackPanel; // Create the TextBlock TextBlock textBlock = new TextBlock(); textBlock.Text = "Welcome to XAML Tutorial"; textBlock.Height = 20; textBlock.Width = 200; textBlock.Margin = new Thickness(5); stackPanel.Children.Add(textBlock); // Create the Button Button button = new Button(); button.Content = "OK"; button.Height = 20; button.Width = 50; button.Margin = new Thickness(20); stackPanel.Children.Add(button); } } }
编译并执行上述代码后,将生成以下输出。请注意,它与 XAML 代码的输出完全相同。
现在您可以看到使用和理解 XAML 是多么简单。
XAML 与 VB.NET 对比
本章将用 VB.Net 编写相同的示例,以便熟悉 VB.Net 的人也可以理解 XAML 的优点。
让我们再次来看一下用 XAML 编写的相同示例:
<Window x:Class = "XAMLVsCode.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <StackPanel> <TextBlock Text = "Welcome to XAML Tutorial with VB.net" Height = "20" Width = "220" Margin = "5"/> <Button Content = "Ok" Height = "20" Width = "60" Margin = "5"/> </StackPanel> </Window>
在这个例子中,我们创建了一个包含按钮和文本块的堆叠面板,并定义了按钮和文本块的一些属性,例如高度、宽度和边距。编译并执行上述代码后,将生成以下输出:
现在来看一下用 VB.Net 编写的相同代码:
Public Class MainWindow Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs) Dim panel As New StackPanel() panel.Orientation = Orientation.Vertical Me.Content = panel Dim txtInput As New TextBlock txtInput.Text = "Welcome to XAML Tutorial with VB.net" txtInput.Width = 220 txtInput.Height = 20 txtInput.Margin = New Thickness(5) panel.Children.Add(txtInput) Dim btn As New Button() btn.Content = "Ok" btn.Width = 60 btn.Height = 20 btn.Margin = New Thickness(5) panel.Children.Add(btn) End Sub End Class
编译并执行上述代码后,输出与 XAML 代码的输出完全相同。
现在您可以看到与 VB.Net 相比,使用 XAML 是多么简单。
在上面的示例中,我们看到在 XAML 中可以完成的操作也可以在其他过程语言(如 C# 和 VB.Net)中完成。
让我们来看另一个示例,在这个示例中我们将同时使用 XAML 和 VB.Net。我们将使用 XAML 设计 GUI,并在 VB.Net 中实现行为。
在这个示例中,一个按钮被添加到主窗口。当用户单击此按钮时,它会在消息框上显示一条消息。以下是 XAML 中的代码,其中声明了一个带有某些属性的 Button 对象。
<Window x:Class="MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <Button Name = "btn" HorizontalAlignment = "Center" Width = "60" Height = "30" Content = "Click Me" /> </Grid> </Window>
在 VB.Net 中,实现了按钮单击事件(行为)。此事件在消息框上显示消息。
Public Class MainWindow Private Sub btn_Click(sender As Object, e As RoutedEventArgs) Handles btn.Click MessageBox.Show("Button is Clicked") End Sub End Class
编译并执行上述代码后,将显示以下屏幕:
现在单击上面显示“单击我”的按钮。它将显示以下消息:
XAML - 构建块
本章将介绍 XAML 应用程序的一些基本和重要的构建块。它将解释如何
- 创建和初始化对象,
- 使用资源、样式和模板可以轻松修改对象,
- 使用变换和动画使对象具有交互性。
对象
XAML 是一种典型的声明式语言,可以创建和实例化对象。它是基于 XML 描述对象的另一种方式,即需要创建哪些对象以及在程序执行之前如何初始化这些对象。对象可以是
- 容器 (Stack Panel,Dock Panel)
- UI 元素/控件 (Button,TextBox 等)
- 资源字典
资源
资源通常是与某个对象关联的定义,你预期会多次使用它。它能够为控件或当前窗口本地存储数据,或为整个应用程序全局存储数据。
样式
XAML 框架提供了几种策略来个性化和定制应用程序的外观。样式使我们能够灵活地设置对象的某些属性,并在多个对象中重用这些特定设置,以保持一致的外观。
- 在样式中,你只能设置对象的现有属性,例如高度、宽度、字体大小等。
- 只能指定控件的默认行为。
- 可以在一个样式中添加多个属性。
在第一个图中,你可以看到相同的 height 和 width 属性分别为所有三个按钮设置;但在第二个图中,你可以看到所有按钮都相同的 height 和 width 被添加到一个样式中,然后这个样式与所有按钮关联。
模板
模板描述了控件的整体外观和视觉外观。每个控件都关联一个默认模板,它赋予该控件外观。在 XAML 中,当你想自定义控件的视觉行为和视觉外观时,可以轻松创建自己的模板。
在下面的屏幕截图中,有两个按钮,一个是带有模板的按钮,另一个是默认按钮。
现在,当鼠标悬停在按钮上时,它还会更改颜色,如下所示。
使用模板,你可以访问比样式中更多的控件部分。你可以指定控件的现有行为和新行为。
动画和变换
Windows 运行时中的动画和变换可以通过构建交互性和移动性来改进你的 XAML 应用程序。通过使用 Windows 运行时动画库中的动画,你可以轻松地在你的 XAML 应用程序中集成交互式外观和感觉。动画用于
- 增强用户界面或使其更具吸引力。
- 吸引用户注意变化。
在下面的屏幕截图中,你可以看到一个正方形 -
当鼠标悬停在这个正方形上时,它会向所有方向扩展,如下所示。
XAML - 控件
XAML 用户界面框架提供了一个广泛的控件库,支持 Windows 的 UI 开发。其中一些具有可视化表示,例如 Button、Textbox、TextBlock 等;而其他控件用作其他控件或内容的容器,例如图像。所有 XAML 控件都继承自 **System.Windows.Controls.Control**。
控件的完整继承层次结构如下所示 -
以下是我们将在本章中逐一讨论的控件列表。
序号 | 控件和描述 |
---|---|
1 | Button
响应用户输入的控件。 |
2 | Calendar
表示一个控件,允许用户使用可视化日历显示来选择日期。 |
3 | CheckBox
用户可以选择或清除的控件。 |
4 | ComboBox
用户可以选择的下拉列表。 |
5 | ContextMenu
获取或设置上下文菜单元素,当通过用户界面 (UI) 从此元素内部请求上下文菜单时,该元素应该出现。 |
6 | DataGrid
表示一个控件,以可自定义的网格显示数据。 |
7 | DatePicker
允许用户选择日期的控件。 |
8 | Dialogs
应用程序还可以向用户显示其他窗口,以收集或显示重要信息。 |
9 | GridView
一个控件,以可以水平滚动的行和列显示项目集合。 |
10 | Image
显示图像的控件。 |
11 | ListBox
一个控件,显示用户可以选择的行内项目列表。 |
12 | Menus
表示一个 Windows 菜单控件,使你能够分层组织与命令和事件处理程序关联的元素。 |
13 | PasswordBox
用于输入密码的控件。 |
14 | Popup
在应用程序窗口的边界内,在现有内容之上显示内容。 |
15 | ProgressBar
通过显示进度条来指示进度的控件。 |
16 | ProgressRing
通过显示圆环来指示不确定进度的控件。 |
17 | RadioButton
允许用户从一组选项中选择单个选项的控件。 |
18 | RichEditBox
允许用户编辑富文本文档的控件,其内容包括格式化文本、超链接和图像。 |
19 | ScrollViewer
一个容器控件,允许用户平移和缩放其内容。 |
20 | SearchBox
允许用户输入搜索查询的控件。 |
21 | Slider
一个控件,允许用户通过沿轨道移动 Thumb 控件来从一系列值中进行选择。 |
22 | TextBlock
显示文本的控件。 |
23 | TimePicker
允许用户设置时间值的控件。 |
24 | ToggleButton
可以在两种状态之间切换的按钮。 |
25 | ToolTip
一个弹出窗口,显示元素的信息。 |
26 | Window
提供最小化/最大化选项、标题栏、边框和关闭按钮的根窗口。 |
本章将讨论所有这些控件的实现。
XAML - 布局
控件的布局对于应用程序可用性非常重要和关键。需要在应用程序中排列一组 GUI 元素。选择布局面板时需要考虑某些要点;
- 子元素的位置。
- 子元素的大小。
- 子元素彼此重叠的分层。
当应用程序在不同的屏幕分辨率上使用时,固定的像素排列控件不起作用。XAML 提供了一套丰富的内置布局面板来以适当的方式排列 GUI 元素。一些最常用和流行的布局面板如下所示 -
序号 | 面板和描述 |
---|---|
1 | StackPanel
Stack panel 是 XAML 中一个简单而有用的布局面板。在 Stack panel 中,子元素可以根据 orientation 属性在一个单行中水平或垂直排列。 |
2 | WrapPanel
在 WrapPanel 中,子元素根据 orientation 属性按顺序从左到右或从上到下排列。 |
3 | DockPanel
DockPanel 定义一个区域,用于相对于彼此排列子元素,无论是水平还是垂直。使用 DockPanel,你可以轻松地将子元素停靠到顶部、底部、右侧、左侧和中心,使用 Dock 属性。 |
4 | CanvasPanel
Canvas panel 是一个基本布局面板,其中子元素可以使用相对于 Canvas 任何侧面的坐标(例如左、右、上、下)显式定位。 |
5 | GridPanel
Grid 面板提供了一个灵活的区域,该区域由行和列组成。在 Grid 中,子元素可以以表格形式排列。 |
XAML - 事件处理
XAML 中事件的通用概念类似于其他流行编程语言(如 .NET 和 C++)中的事件。在 XAML 中,所有控件都公开了一些事件,以便可以订阅它们以用于特定目的。
每当发生事件时,应用程序都会收到通知,并且程序可以对其做出反应,例如,关闭按钮用于关闭对话框。
可以订阅许多类型的事件,以实现基于应用程序需求的不同应用程序行为,但最常用的事件是那些与鼠标和键盘相关的事件,例如:
- Click
- MouseDown
- MouseEnter
- MouseLeave
- MouseUp
- KeyDown
- KeyUp
在本章中,我们将使用一些基本且最常用的事件来了解如何将特定控件的事件链接到代码隐藏,在代码隐藏中,将根据用户希望在发生特定事件时执行的操作来实现行为。
让我们来看一个简单的按钮单击事件示例。下面是 Button 控件的 XAML 实现,该控件已创建并初始化了一些属性和 Click 事件 (Click="OnClick")。
<Window x:Class = "XAMLEventHandling.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <Button x:Name = "button1" Content = "Click" Click = "OnClick" Width = "150" Height = "30" HorizontalAlignment = "Center" /> </Grid> </Window>
每当单击此按钮时,它都会触发 **OnClick** 事件,你可以添加任何类型的行为作为对 Click 的响应。让我们来看一下 OnClick 事件实现,它会在单击此按钮时显示一条消息。
using System; using System.Windows; using System.Windows.Controls; namespace XAMLEventHandling { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void OnClick(object sender, RoutedEventArgs e) { MessageBox.Show("Button is clicked!"); } } }
编译并执行上述代码后,将产生以下输出 -
单击按钮时,将触发单击 (OnClick) 事件,并将显示以下消息。
现在让我们来看一个稍微复杂的示例,其中处理多个事件。
示例
以下示例包含一个带有 ContextMenu 的文本框,用于操作文本框内的文本。
以下 XAML 代码创建了一个 TextBox、一个 ContextMenu 和一些具有属性和事件(例如 Checked、Unchecked 和 Click)的 MenuItem。
<Window x:Class = "XAMLContextMenu.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <TextBox Name = "textBox1" TextWrapping = "Wrap" Margin = "10" Grid.Row = "7"> Hi, this is XAML tutorial. <TextBox.ContextMenu> <ContextMenu> <MenuItem Header = "_Bold" IsCheckable = "True" Checked = "Bold_Checked" Unchecked = "Bold_Unchecked" /> <MenuItem Header = "_Italic" IsCheckable = "True" Checked = "Italic_Checked" Unchecked = "Italic_Unchecked" /> <Separator /> <MenuItem Header = "Increase Font Size" Click = "IncreaseFont_Click" /> <MenuItem Header = "_Decrease Font Size" Click = "DecreaseFont_Click" /> </ContextMenu> </TextBox.ContextMenu> </TextBox> </Grid> </Window>
以下是 C# 中不同事件的实现,每当选中、取消选中或单击菜单项时,这些事件都会触发。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace XAMLContextMenu { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Bold_Checked(object sender, RoutedEventArgs e) { textBox1.FontWeight = FontWeights.Bold; } private void Bold_Unchecked(object sender, RoutedEventArgs e) { textBox1.FontWeight = FontWeights.Normal; } private void Italic_Checked(object sender, RoutedEventArgs e) { textBox1.FontStyle = FontStyles.Italic; } private void Italic_Unchecked(object sender, RoutedEventArgs e) { textBox1.FontStyle = FontStyles.Normal; } private void IncreaseFont_Click(object sender, RoutedEventArgs e) { if (textBox1.FontSize < 18) { textBox1.FontSize += 2; } } private void DecreaseFont_Click(object sender, RoutedEventArgs e) { if (textBox1.FontSize > 10) { textBox1.FontSize -= 2; } } } }
编译并执行上述代码后,将产生以下输出 -
我们建议你执行上述示例代码并尝试其他一些事件。
事件
序号 | 控件和描述 |
---|---|
1 | Checked 当 ToggleButton 被选中时触发。(继承自 ToggleButton) |
2 | Click 当单击按钮控件时发生。(继承自 ButtonBase) |
3 | ContextMenuClosing 在元素上的任何上下文菜单关闭之前发生。(继承自 FrameworkElement。) |
4 | ContextMenuOpening 当元素上的任何上下文菜单打开时发生。(继承自 FrameworkElement。) |
5 | DataContextChanged 当 FrameworkElement.DataContext 属性的值更改时发生。(继承自 FrameworkElement) |
6 | DragEnter 当输入系统报告以该元素作为目标的基础拖动事件时发生。(继承自 UIElement)。 |
7 | DragLeave 当输入系统报告以该元素作为原点的基础拖动事件时发生。(继承自 UIElement) |
8 | DragOver 当输入系统报告以该元素作为潜在放置目标的基础拖动事件时发生。(继承自 UIElement) |
9 | DragStarting 当启动拖动操作时发生。(继承自 UIElement) |
10 | DropCompleted 当拖放操作结束时发生。(继承自 UIElement) |
11 | DropDownClosed 当 ComboBox 的下拉部分关闭时发生。 |
12 | DropDownOpened 当 ComboBox 的下拉部分打开时发生。 |
13 | GotFocus 当 UIElement 获得焦点时发生。(继承自 UIElement) |
14 | Holding 当在此元素的命中测试区域上发生其他未处理的保持交互时发生。(继承自 UIElement) |
15 | 中间状态 当ToggleButton的状态切换到不确定状态时触发。(继承自ToggleButton) |
16 | IsEnabledChanged 当IsEnabled属性更改时发生。(继承自Control) |
17 | KeyDown 当UIElement具有焦点时按下键盘按键时发生。(继承自UIElement) |
18 | KeyUp 当UIElement具有焦点时释放键盘按键时发生。(继承自UIElement) |
19 | LostFocus 当UIElement失去焦点时发生。(继承自UIElement) |
20 | ManipulationCompleted 当对UIElement的操作完成后发生。(继承自UIElement) |
21 | ManipulationDelta 当输入设备在操作过程中更改位置时发生。(继承自UIElement) |
22 | ManipulationInertiaStarting 当输入设备在操作过程中与UIElement对象失去接触并开始惯性时发生。(继承自UIElement) |
23 | ManipulationStarted 当输入设备开始对UIElement进行操作时发生。(继承自UIElement) |
24 | ManipulationStarting 当首次创建操作处理器时发生。(继承自UIElement) |
25 | SelectionChanged 文本选择更改时发生。 |
26 | SizeChanged 当FrameworkElement上的ActualHeight或ActualWidth属性的值发生更改时发生。(继承自FrameworkElement) |
27 | Unchecked 当ToggleButton取消选中时发生。(继承自ToggleButton) |
28 | ValueChanged 当范围值更改时发生。(继承自RangeBase) |
XAML - 数据绑定
数据绑定是XAML应用程序中的一种机制,它为使用部分类的Windows运行时应用程序提供了一种简单易用的方法来显示和交互数据。在此机制中,数据的管理与数据显示方式完全分离。
数据绑定允许数据在UI元素和用户界面上的数据对象之间流动。当建立绑定并且数据或业务模型发生更改时,它将自动将更新反映到UI元素,反之亦然。也可以绑定到页面上的另一个元素,而不是标准数据源。数据绑定可以分为两种类型:
- 单向数据绑定
- 双向数据绑定
单向数据绑定
在单向绑定中,数据从其源(即保存数据的对象)绑定到其目标(即显示数据的对象)。
让我们来看一个简单的单向数据绑定示例。以下XAML代码创建了四个文本块,并具有一些属性。
<Window x:Class = "DataBindingOneWay.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <StackPanel Name = "Display"> <StackPanel Orientation = "Horizontal" Margin = "50, 50, 0, 0"> <TextBlock Text = "Name: " Margin = "10" Width = "100" /> <TextBlock Margin = "10" Width = "100" Text = "{Binding Name}" /> </StackPanel> <StackPanel Orientation = "Horizontal" Margin = "50,0,50,0"> <TextBlock Text = "Title: " Margin = "10" Width = "100" /> <TextBlock Margin = "10" Width = "100" Text = "{Binding Title}" /> </StackPanel> </StackPanel> </Grid> </Window>
两个文本块的Text属性静态设置为“Name”和“Title”,而其他两个文本块的Text属性绑定到“Name”和“Title”,它们是Employee类的类变量,如下所示。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBindingOneWay { public class Employee { public string Name { get; set; } public string Title { get; set; } public static Employee GetEmployee() { var emp = new Employee() { Name = "Ali Ahmed", Title = "Developer" }; return emp; } } }
在这个类中,我们只有两个变量,**Name**和**Title**,以及一个静态方法,其中初始化Employee对象并将返回该Employee对象。因此,我们绑定到一个属性Name和Title,但我们没有选择该属性属于哪个对象。最简单的方法是将一个对象分配给DataContext,我们在下面的C#代码中绑定其属性:
using System; using System.Windows; using System.Windows.Controls; namespace DataBindingOneWay { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = Employee.GetEmployee(); } } }
让我们运行此应用程序,您可以在我们的MainWindow中立即看到我们已成功绑定到该Employee对象的Name和Title。
双向数据绑定
在双向绑定中,用户可以通过用户界面修改数据,并将该数据更新到源。如果用户查看视图时源发生更改,则需要更新视图。
示例
让我们来看下面的例子,其中创建了一个带三个组合框项的组合框和一个文本框,并具有一些属性。在这个例子中,我们没有任何标准的数据源,但是UI元素绑定到其他UI元素。
<Window x:Class = "XAMLTestBinding.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <StackPanel> <ComboBox Name = "comboBox" Margin = "50" Width = "100"> <ComboBoxItem Content = "Green" /> <ComboBoxItem Content = "Yellow" IsSelected = "True" /> <ComboBoxItem Content = "Orange" /> </ComboBox> <TextBox Name = "textBox" Margin = "50" Width = "100" Height = "23" VerticalAlignment = "Top" Text = "{Binding ElementName = comboBox, Path = SelectedItem.Content, Mode = TwoWay, UpdateSourceTrigger = PropertyChanged}" Background = "{Binding ElementName = comboBox, Path = SelectedItem.Content}"> </TextBox> </StackPanel> </Window>
编译并执行上述代码后,将生成以下输出。当用户从组合框中选择一个项目时,文本框文本和背景颜色将相应更新。
同样,当用户在文本框中键入有效的颜色名称时,组合框和文本框的背景颜色也将更新。
XAML - 标记扩展
在XAML应用程序中,标记扩展是一种获取既不是特定XAML对象也不是原始类型的值的方法/技术。标记扩展可以通过打开和关闭大括号来定义,在大括号内定义标记扩展的范围。
数据绑定和静态资源是标记扩展。**System.xaml**中有一些预定义的XAML标记扩展可以使用。
让我们来看一个简单的例子,其中使用了**StaticResources**标记扩展,它是一个预定义的XAML标记扩展。
以下XAML代码创建了两个具有某些属性的文本块,它们的foregroundColor在**Window.Resources**中定义。
<Window x:Class = "XAMLStaticResourcesMarkupExtension.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "525"> <Window.Resources> <SolidColorBrush Color = "Blue" x:Key = "myBrush"></SolidColorBrush> </Window.Resources> <Grid> <StackPanel Orientation = "Vertical"> <TextBlock Foreground = "{StaticResource myBrush}" Text = "First Name" Width = "100" Margin = "10" /> <TextBlock Foreground = "{StaticResource myBrush}" Text = "Last Name" Width = "100" Margin = "10" /> </StackPanel> </Grid> </Window>
在**Window.Resources**中,您可以看到使用了**x:Key**,它唯一标识在XAML定义的字典中创建和引用的元素,以在资源字典中标识资源。
编译并执行上述代码后,将生成以下MainWindow。您可以看到两个带有蓝色前景色的文本块。
在XAML中,也可以通过继承MarkupExtension类并覆盖ProvideValue方法(它是MarkupExtension类中的抽象方法)来定义自定义标记扩展。
让我们来看一个自定义标记扩展的简单示例。
<Window x:Class = "XAMLMarkupExtension.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my = "clr-namespace:XAMLMarkupExtension" Title = "MainWindow" Height = "350" Width = "525"> <Grid> <Button Content = "{my:MyMarkupExtension FirstStr = Markup, SecondStr = Extension}" Width = "200" Height = "20" /> </Grid> </Window>
在上面的XAML代码中,创建了一个具有某些属性的按钮,并且对于content值,使用了自定义标记扩展**(my:MyMarkupExtension)**,其中有两个值“Markup”和“Extension”,分别分配给FirstStr和SecondStr。
实际上,MyMarkupExtension
是一个从MarkupExtension
派生的类,如下面的C#实现所示。此类包含两个字符串变量FirstStr和SecondStr,它们被连接起来,并将该字符串从ProvideValue方法返回到按钮的Content。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace XAMLMarkupExtension { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class MyMarkupExtension : MarkupExtension { public MyMarkupExtension() { } public String FirstStr { get; set; } public String SecondStr { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { return FirstStr + " " + SecondStr; } } }
让我们运行此应用程序,您可以在我们的MainWindow中立即看到“markup extension”已成功用作按钮的内容。
XAML - 依赖属性
依赖属性是一种特定类型的属性,其值由一个敏锐的属性系统跟踪,该系统也是Windows运行时应用程序的一部分。定义依赖属性的类必须继承自DependencyObject类。
在XAML中使用的许多UI控件类都派生自DependencyObject类并支持依赖属性。以下XAML代码创建了一个具有某些属性的按钮。
<Window x:Class = "XAMLDependencyProperty.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local = "clr-namespace:XAMLDependencyProperty" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <Button Height = "40" Width = "175" Margin = "10" Content = "Dependency Property"> <Button.Style> <Style TargetType = "{x:Type Button}"> <Style.Triggers> <Trigger Property = "IsMouseOver" Value = "True"> <Setter Property = "Foreground" Value = "Red" /> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button> </Grid> </Window>
XAML中的x:Type标记扩展具有与C#中的typeof()类似的功能。当指定采用对象类型的属性时使用它,例如<Style TargetType = "{x:Type Button}">
编译并执行上述代码后,将生成以下MainWindow。当鼠标悬停在按钮上时,它将更改按钮的前景色。当鼠标离开按钮时,它将恢复到原来的颜色。
依赖属性与其他CLR属性的主要区别在于:
CLR属性可以使用**getter**和**setter**直接从类的私有成员读取/写入。对于依赖属性,它不会存储在本地对象中。
依赖属性存储在DependencyObject类提供的键/值对字典中。
它还节省了大量内存,因为它只在属性更改时才存储。
它也可以在XAML中绑定。
在.NET框架中,也可以定义自定义依赖属性。以下是C#中定义自定义依赖属性的步骤。
使用系统调用register声明和注册您的依赖属性。
为属性提供setter和getter。
定义一个静态处理程序来处理全局发生的任何更改。
定义一个实例处理程序来处理发生在此特定实例的任何更改。
以下是C#中依赖属性的代码,该属性用于设置用户控件的SetText属性。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfApplication3 { /// <summary> /// Interaction logic for UserControl1.xaml /// </summary> public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); } public static readonly DependencyProperty SetTextProperty = DependencyProperty.Register("SetText", typeof(string), typeof(UserControl1), new PropertyMetadata("", new PropertyChangedCallback(OnSetTextChanged))); public string SetText { get {return(string) GetValue(SetTextProperty); } set {SetValue(SetTextProperty, value);} } private static void OnSetTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UserControl1 UserControl1Control = d as UserControl1; UserControl1Control.OnSetTextChanged(e); } private void OnSetTextChanged(DependencyPropertyChangedEventArgs e) { tbTest.Text = e.NewValue.ToString(); } } }
这是XAML文件,其中TextBlock被定义为用户控件,并且Text属性将由SetText依赖属性分配给它。
以下XAML代码创建了一个用户控件,并初始化其SetText依赖属性和其他一些属性。
<Window x:Class = "WpfApplication3.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:views = "clr-namespace:WpfApplication3" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <views:UserControl1 SetText = "Hellow World" /> </Grid> </Window>
让我们运行此应用程序,您可以在我们的MainWindow中立即看到用户控件的依赖属性已成功用作文本。
XAML - 资源
资源通常是与某些对象相关的定义,您只希望多次使用它。它能够为控件或当前窗口本地存储数据,或者为整个应用程序全局存储数据。
将对象定义为资源允许我们从另一个位置访问它。因此,它允许可重用性。资源在资源字典中定义,任何对象都可以有效地定义为资源,使其成为可共享的资产。一个唯一的键被指定给XAML资源,并且可以使用该键通过使用StaticResource标记扩展来引用它。
让我们再次来看一个简单的例子,其中创建了两个具有某些属性的文本块,它们的foregroundColor在**Window.Resources**中定义。
<Window x:Class = "XAMLResources.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Window.Resources> <SolidColorBrush Color = "Blue" x:Key = "myBrush"></SolidColorBrush> </Window.Resources> <StackPanel Orientation = "Vertical"> <TextBlock Foreground = "{StaticResource myBrush}" Text = "First Name" Width = "100" Margin = "10" /> <TextBlock Foreground = "{StaticResource myBrush}" Text = "Last Name" Width = "100" Margin = "10" /> </StackPanel> </Window>
编译并执行上述代码后,将生成以下MainWindow。您可以看到两个带有蓝色前景色的文本块。资源的优点是,如果有多个文本块并且您想更改它们的背景颜色,则只需要在资源字典中更改它。
资源范围
资源在资源字典中定义,但是可以在许多地方定义资源字典。在上面的示例中,资源字典是在窗口/页面级别定义的。资源在哪个字典中定义会立即限制该资源的范围。因此,范围(即可以使用资源的位置)取决于您定义资源的位置。
在网格的资源字典中定义资源,并且只有该网格及其子元素可以访问它。
在窗口/页面上定义它,并且该窗口/页面上的所有元素都可以访问它。
App根可以在App.xaml资源字典中找到。它是我们应用程序的根,因此此处定义的资源的作用域为整个应用程序。
就资源的范围而言,最常见的是应用程序级别、页面级别和特定元素级别,如Grid、StackPanel等。
资源字典
XAML应用程序中的资源字典意味着单独文件中的资源字典。这几乎在所有XAML应用程序中都是遵循的。在单独的文件中定义资源具有以下优点:
在资源字典和UI相关代码之间分离。
在单独的文件(例如App.xaml)中定义所有资源将使它们在整个应用程序中可用。
那么,我们如何在单独的文件中的资源字典中定义资源呢?这很容易,只需通过以下步骤通过Visual Studio添加一个新的资源字典:
在您的解决方案中,添加一个新文件夹并将其命名为**ResourceDictionaries**。
右键单击此文件夹,然后从“添加”子菜单项中选择“资源字典”,并将其命名为**DictionaryWithBrush.xaml**
让我们来看一下同一个应用程序;资源字典现在在应用程序级别定义。
这是MainWindow.xaml的XAML代码。
<Window x:Class = "XAMLResources.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <StackPanel Orientation = "Vertical"> <TextBlock Foreground = "{StaticResource myBrush}" Text = "First Name" Width = "100" Margin = "10" /> <TextBlock Foreground = "{StaticResource myBrush}" Text = "Last Name" Width = "100" Margin = "10"/> </StackPanel> </Window>
这是DictionaryWithBrush.xaml中的实现:
<ResourceDictionary xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush Color = "Blue" x:Key = "myBrush"></SolidColorBrush> </ResourceDictionary>
这是app.xaml中的实现:
<Application x:Class = "XAMLResources.App" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" StartupUri = "MainWindow.xaml"> <Application.Resources> <ResourceDictionary Source = " XAMLResources\ResourceDictionaries\DictionaryWithBrush.xaml" /> </Application.Resources> </Application>
编译并执行上述代码后,将生成以下输出:
我们建议您执行上述代码并尝试更多资源,例如背景颜色等。
XAML - 模板
模板描述了控件的整体外观和视觉外观。对于每个控件,都与之关联一个默认模板,该模板赋予该控件外观。
在XAML中,当您想要自定义控件的视觉行为和视觉外观时,可以轻松创建您自己的模板。逻辑和模板之间的连接可以通过数据绑定来实现。
样式和模板的主要区别在于:
样式只能更改控件的默认属性外观。
使用模板,您可以访问比样式中更多控件的部分。您还可以指定控件的现有和新行为。
最常用的模板有两种。
- 控件模板
- 数据模板
控件模板
控件模板定义或指定控件的视觉外观和结构。所有UI元素都具有一定的外观和行为,例如,按钮具有外观和行为。单击事件或鼠标悬停事件是响应单击和悬停而触发的行为,并且还有一个可以由控件模板更改的按钮默认外观。
让我们再次看看一个简单的示例,其中创建了两个具有某些属性的按钮。一个是带模板的,另一个是带默认按钮的。
<Window x:Class = "TemplateDemo.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Window.Resources> <ControlTemplate x:Key = "ButtonTemplate" TargetType = "Button"> <Grid> <Ellipse x:Name = "ButtonEllipse" Height = "100" Width = "150" > <Ellipse.Fill> <LinearGradientBrush StartPoint = "0,0.2" EndPoint = "0.2,1.4"> <GradientStop Offset = "0" Color = "Red"/> <GradientStop Offset = "1" Color = "Orange"/> </LinearGradientBrush> </Ellipse.Fill> </Ellipse> <ContentPresenter Content = "{TemplateBinding Content}" HorizontalAlignment = "Center" VerticalAlignment = "Center" /> </Grid> <ControlTemplate.Triggers> <Trigger Property = "IsMouseOver" Value = "True"> <Setter TargetName = "ButtonEllipse" Property = "Fill" > <Setter.Value> <LinearGradientBrush StartPoint = "0,0.2" EndPoint="0.2,1.4"> <GradientStop Offset = "0" Color = "YellowGreen"/> <GradientStop Offset = "1" Color = "Gold"/> </LinearGradientBrush> </Setter.Value> </Setter> </Trigger> <Trigger Property = "IsPressed" Value = "True"> <Setter Property = "RenderTransform"> <Setter.Value> <ScaleTransform ScaleX = "0.8" ScaleY = "0.8" CenterX = "0" CenterY = "0" /> </Setter.Value> </Setter> <Setter Property = "RenderTransformOrigin" Value = "0.5,0.5" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Window.Resources> <StackPanel> <Button Content = "Round Button!" Template = "{StaticResource ButtonTemplate}" Width = "150" Margin = "50" /> <Button Content = "Default Button!" Height = "40" Width = "150" Margin = "5" /> </StackPanel> </Window>
编译并执行上述代码后,将生成以下MainWindow:
当您将鼠标悬停在带有自定义模板的按钮上时,它也会更改颜色,如下所示:
数据模板
数据模板定义和指定数据集合的外观和结构。它提供了灵活地格式化和定义任何UI元素上数据的呈现方式。它主要用于与数据相关的项目控件,例如ComboBox、ListBox等。
让我们看看数据模板的一个简单示例。以下XAML代码创建了一个带有数据模板和文本块的组合框。
<Window x:Class = "XAMLDataTemplate.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Grid VerticalAlignment = "Top"> <ComboBox Name = "Presidents" ItemsSource = "{Binding}" Height = "30" Width = "400"> <ComboBox.ItemTemplate> <DataTemplate> <StackPanel Orientation = "Horizontal" Margin = "2"> <TextBlock Text = "Name: " Width = "95" Background = "Aqua" Margin = "2" /> <TextBlock Text = "{Binding Name}" Width = "95" Background = "AliceBlue" Margin = "2" /> <TextBlock Text = "Title: " Width = "95" Background = "Aqua" Margin = "10,2,0,2" /> <TextBlock Text = "{Binding Title}" Width = "95" Background = "AliceBlue" Margin = "2" /> </StackPanel> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> </Grid> </Window>
这是C#中的实现,其中employee对象被赋值给DataContext:
using System; using System.Windows; using System.Windows.Controls; namespace XAMLDataTemplate { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = Employee.GetEmployees(); } } }
这是C#中Employee类的实现:
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace XAMLDataTemplate { public class Employee : INotifyPropertyChanged { private string name; public string Name { get { return name; } set { name = value; RaiseProperChanged(); } } private string title; public string Title { get { return title; } set { title = value; RaiseProperChanged(); } } public static Employee GetEmployee() { var emp = new Employee() { Name = "Waqas", Title = "Software Engineer" }; return emp; } public event PropertyChangedEventHandler PropertyChanged; private void RaiseProperChanged( [CallerMemberName] string caller = ""){ if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(caller)); } } public static ObservableCollection<Employee> GetEmployees() { var employees = new ObservableCollection<Employee>(); employees.Add(new Employee() { Name = "Ali", Title = "Developer" }); employees.Add(new Employee() { Name = "Ahmed", Title = "Programmer" }); employees.Add(new Employee() { Name = "Amjad", Title = "Desiner" }); employees.Add(new Employee() { Name = "Waqas", Title = "Programmer" }); employees.Add(new Employee() { Name = "Bilal", Title = "Engineer" }); employees.Add(new Employee() { Name = "Waqar", Title = "Manager" }); return employees; } } }
编译并执行上述代码后,将生成以下输出。它包含一个组合框,当您单击组合框时,您会看到在Employee类中创建的数据集合作为组合框项目列出。
我们建议您执行上述代码并进行试验。
XAML - 样式
XAML 框架提供了几种策略来个性化和定制应用程序的外观。样式使我们能够灵活地设置对象的某些属性,并在多个对象中重用这些特定设置,以保持一致的外观。
在样式中,您只能设置对象的现有属性,例如高度、宽度和字体大小。
只能指定控件的默认行为。
可以在单个样式中添加多个属性。
样式用于为一组控件提供统一的外观。隐式样式用于将外观应用于给定类型的全部控件并简化应用程序。
假设我们有三个按钮,并且它们的外观必须相同:相同的宽度和高度、相同的字体大小和相同的文本颜色。我们可以在按钮元素本身设置所有这些属性,对于所有按钮来说,这仍然是可以的,如下面的图所示。
但在实际应用程序中,通常会有更多需要看起来完全相同的按钮。当然,不仅仅是按钮,您通常希望文本块、文本框和组合框等在您的应用程序中看起来相同。当然必须有更好的方法来实现这一点——这就是所谓的样式。您可以将样式视为一种方便的方法,可以将一组属性值应用于多个元素,如下面的图所示。
让我们看看包含三个在XAML中创建并具有某些属性的按钮的示例。
<Window x:Class = "XAMLStyle.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:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local = "clr-namespace:XAMLStyle" mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604"> <StackPanel> <Button Content = "Button1" Height = "30" Width = "80" Foreground = "Blue" FontSize = "12" Margin = "10"/> <Button Content = "Button2" Height = "30" Width = "80" Foreground = "Blue" FontSize = "12" Margin = "10"/> <Button Content = "Button3" Height = "30" Width = "80" Foreground = "Blue" FontSize = "12" Margin = "10"/> </StackPanel> </Window>
查看上面的代码,您将看到对于所有按钮,高度、宽度、前景色、字体大小和边距属性都保持不变。编译并执行上述代码后,将显示以下输出:
现在让我们看看相同的示例,但这次我们将使用样式。
<Window x:Class = "XAMLStyle.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:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local = "clr-namespace:XAMLStyle" mc:Ignorable = "d" Title = "MainWindow" Height = "350" Width = "604"> <Window.Resources> <Style x:Key = "myButtonStyle" TargetType = "Button"> <Setter Property = "Height" Value = "30"/> <Setter Property = "Width" Value = "80"/> <Setter Property = "Foreground" Value = "Blue"/> <Setter Property = "FontSize" Value = "12"/> <Setter Property = "Margin" Value = "10"/> </Style> </Window.Resources> <StackPanel> <Button Content = "Button1" Style = "{StaticResource myButtonStyle}"/> <Button Content = "Button2" Style = "{StaticResource myButtonStyle}"/> <Button Content = "Button3" Style = "{StaticResource myButtonStyle}"/> </StackPanel> </Window>
样式在资源字典中定义,每个样式都有一个唯一的键标识符和一个目标类型。在<style>内部,您可以看到为将包含在样式中的每个属性定义了多个setter标签。
在上面的示例中,每个按钮的所有公共属性现在都在样式中定义,然后通过使用StaticResource标记扩展设置style属性,将样式分配给每个按钮。
编译并执行上述代码后,将生成以下窗口,该窗口与输出相同。
这样做的优势是显而易见的。我们可以在其作用域内的任何位置重复使用该样式,如果需要更改它,我们只需在样式定义中更改一次,而无需在每个元素上更改。
样式的定义级别会立即限制该样式的作用域。因此,作用域(即可以使用样式的位置)取决于您定义样式的位置。样式可以在以下级别定义:
序号 | 级别和说明 |
---|---|
1 | 控件级别
在控件级别定义的样式只能应用于该特定控件。 |
2 | 布局级别
在任何布局级别定义的样式只能被该布局及其子元素访问。 |
3 | 窗口级别
在窗口级别定义的样式可以被该窗口上的所有元素访问。 |
4 | 应用程序级别
在应用程序级别定义的样式可以在整个应用程序中访问。 |
XAML - 触发器
基本上,触发器使您可以根据属性的值来更改属性值或执行操作。因此,它基本上允许您动态更改控件的外观和/或行为,而无需创建新的控件。
触发器用于在满足某些条件时更改任何给定属性的值。触发器通常在样式中或应用于特定控件的文档根中定义。触发器有三种类型:
- 属性触发器
- 数据触发器
- 事件触发器
属性触发器
在属性触发器中,当一个属性发生更改时,它将导致另一个属性发生立即或动画更改。例如,如果您想在鼠标悬停在按钮上时更改按钮外观,可以使用属性触发器。
示例
以下示例演示如何在鼠标进入按钮区域时更改按钮的前景色。
<Window x:Class = "XAMLPropertyTriggers.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Window.Resources> <Style x:Key = "TriggerStyle" TargetType = "Button"> <Setter Property = "Foreground" Value = "Blue" /> <Style.Triggers> <Trigger Property = "IsMouseOver" Value = "True"> <Setter Property = "Foreground" Value = "Green" /> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Button Width = "100" Height = "70" Style = "{StaticResource TriggerStyle}" Content = "Trigger"/> </Grid> </Window>
编译并执行上述代码后,将产生以下输出 -
当鼠标进入按钮区域时,前景色将更改为绿色。
数据触发器
当绑定数据满足某些条件时,数据触发器将执行某些操作。让我们看看以下XAML代码,其中创建了一个复选框和一个文本块以及一些属性。选中复选框时,它会将前景色更改为红色。
<Window x:Class = "XAMLDataTrigger.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "Data Trigger" Height = "350" Width = "604"> <StackPanel HorizontalAlignment = "Center"> <CheckBox x:Name = "redColorCheckBox" Content = "Set red as foreground color" Margin = "20"/> <TextBlock Name = "txtblock" VerticalAlignment = "Center" Text = "Event Trigger" FontSize = "24" Margin = "20"> <TextBlock.Style> <Style> <Style.Triggers> <DataTrigger Binding = "{Binding ElementName = redColorCheckBox, Path = IsChecked}" Value = "true"> <Setter Property = "TextBlock.Foreground" Value = "Red"/> <Setter Property = "TextBlock.Cursor" Value = "Hand" /> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> </StackPanel> </Window>
编译并执行上述代码后,将产生以下输出 -
选中复选框时,文本块的前景色将更改为红色。
事件触发器
触发事件将在触发特定事件时执行某些操作。它通常用于完成某些动画,例如DoubleAnimation、ColorAnimation等。以下代码块创建了一个简单的按钮。触发单击事件时,它将扩展按钮的宽度和高度。
<Window x:Class = "XAMLEventTrigger.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <Button Content = "Click Me" Width = "60" Height = "30"> <Button.Triggers> <EventTrigger RoutedEvent = "Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty = "Width" Duration = "0:0:4"> <LinearDoubleKeyFrame Value = "60" KeyTime = "0:0:0"/> <LinearDoubleKeyFrame Value = "120" KeyTime = "0:0:1"/> <LinearDoubleKeyFrame Value = "200" KeyTime = "0:0:2"/> <LinearDoubleKeyFrame Value = "300" KeyTime = "0:0:3"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty = "Height" Duration = "0:0:4"> <LinearDoubleKeyFrame Value = "30" KeyTime = "0:0:0"/> <LinearDoubleKeyFrame Value = "40" KeyTime = "0:0:1"/> <LinearDoubleKeyFrame Value = "80" KeyTime = "0:0:2"/> <LinearDoubleKeyFrame Value = "150" KeyTime = "0:0:3"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Button.Triggers> </Button> </Grid> </Window>
编译并执行上述代码后,将产生以下输出 -
现在,单击按钮,您将观察到它将开始在两个维度上扩展。
XAML - 调试
如果您熟悉任何过程语言(如C#、C/C++等)中的调试以及`break`的使用,并且期望在XAML中进行相同类型的调试,那么您会惊讶地发现,目前还无法像调试其他过程语言代码那样调试XAML代码。调试XAML应用程序意味着尝试查找错误;
在数据绑定中,您的数据没有显示在屏幕上,您不知道原因
或者问题与复杂的布局有关。
或者对齐问题或边距颜色、叠加层等问题,以及一些扩展模板,如ListBox和组合框。
XAML中的调试通常用于检查绑定是否有效,如果无效,则检查问题所在。不幸的是,除了Silverlight之外,无法在XAML绑定中设置断点,但我们可以使用输出窗口检查数据绑定错误。让我们看看以下XAML代码以查找数据绑定中的错误。
<Window x:Class = "DataBindingOneWay.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <Grid> <StackPanel Name = "Display"> <StackPanel Orientation = "Horizontal" Margin = "50, 50, 0, 0"> <TextBlock Text = "Name: " Margin = "10" Width = "100"/> <TextBlock Margin = "10" Width = "100" Text = "{Binding FirstName}"/> </StackPanel> <StackPanel Orientation = "Horizontal" Margin = "50,0,50,0"> <TextBlock Text = "Title: " Margin = "10" Width = "100"/> <TextBlock Margin = "10" Width="100" Text = "{Binding Title}" /> </StackPanel> </StackPanel> </Grid> </Window>
两个文本块的Text属性静态设置为“Name”和“Title”,而其他两个文本块的Text属性绑定到“FirstName”和“Title”。但是,类变量在Employee类中故意取为Name和Title,这是不正确的变量名。现在让我们尝试了解在未显示所需输出时可以在哪里找到这种类型的错误。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataBindingOneWay { public class Employee { public string Name { get; set; } public string Title { get; set; } public static Employee GetEmployee() { var emp = new Employee() { Name = "Ali Ahmed", Title = "Developer" }; return emp; } } }
这是C#代码中MainWindow类的实现:
using System; using System.Windows; using System.Windows.Controls; namespace DataBindingOneWay { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = Employee.GetEmployee(); } } }
让我们运行此应用程序,您可以在我们的MainWindow中立即看到我们已成功绑定到该Employee对象的Title,但名称未绑定。
要检查名称发生了什么,让我们看看生成大量日志的输出窗口。
查找错误的最简单方法是搜索错误,您将找到以下提到的错误,该错误显示为“BindingExpression path error: 'FirstName' property not found on 'object' ''Employe”
System.Windows.Data Error: 40 : BindingExpression path error: 'FirstName' property not found on 'object' ''Employee' (HashCode = 11611730)'. BindingExpression:Path = FirstName; DataItem = 'Employee' (HashCode = 11611730); target element is 'TextBlock' (Name = ''); target property is 'Text' (type 'String')
这清楚地表明FirstName不是Employee类的成员,因此它有助于修复应用程序中的此类问题。
再次将FirstName更改为Name后,您将看到所需的输出。
XAML的UI调试工具
XAML的UI调试工具在Visual Studio 2015中引入,用于检查运行时的XAML代码。借助这些工具,XAML代码以正在运行的WPF应用程序的可视化树的形式呈现,以及树中不同的UI元素属性。要启用此工具,请按照以下步骤操作。
步骤1 - 转到“工具”菜单,然后从“工具”菜单中选择“选项”。
步骤2 - 您将看到以下对话框。
步骤3 - 转到左侧“调试”项下的“常规选项”。
步骤4 - 选中突出显示的选项,即“为XAML启用UI调试工具”。
步骤5 - 按“确定”按钮。
现在运行任何XAML应用程序或使用以下XAML代码:
<Window x:Class = "XAMLTestBinding.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Title = "MainWindow" Height = "350" Width = "604"> <StackPanel> <ComboBox Name = "comboBox" Margin = "50" Width = "100"> <ComboBoxItem Content = "Green"/> <ComboBoxItem Content = "Yellow" IsSelected = "True"/> <ComboBoxItem Content = "Orange" /> </ComboBox> <TextBox Name = "textBox" Margin = "50" Width = "100" Height = "23" VerticalAlignment = "Top" Text = "{ Binding ElementName = comboBox, Path = SelectedItem.Content, Mode = TwoWay, UpdateSourceTrigger = PropertyChanged}" Background = "{Binding ElementName = comboBox, Path = SelectedItem.Content}"> </TextBox> </StackPanel> </Window>
应用程序执行时,将显示实时可视化树,其中所有元素都以树的形式显示。
此实时可视化树显示完整的布局结构,以了解UI元素放置的位置。但此选项仅在Visual Studio 2015中可用。如果您使用的是旧版本的Visual Studio,则无法使用此工具;但是,还有另一个工具可以与Visual Studio集成,例如适用于Visual Studio的XAML Spy。您可以从http://xamlspy.com/download下载它。如果您使用的是旧版本的Visual Studio,我们建议您下载此工具。
XAML - 自定义控件
XAML提供创建自定义控件的最强大的功能之一,这使得创建功能丰富且可自定义的控件变得非常容易。当Microsoft提供的全部内置控件无法满足您的标准或您不想支付第三方控件的费用时,可以使用自定义控件。
在本节中,您将学习如何创建自定义控件。在开始查看自定义控件之前,让我们快速了解一下用户控件。
用户控件
用户控件提供了一种技术,可以将不同的内置控件收集并组合在一起,并将其打包到可重复使用的XAML中。用户控件用于以下场景:
如果控件包含现有控件,即您可以创建多个现有控件的单个控件。
如果控件不需要主题支持。用户控件不支持复杂的自定义、控件模板,并且难以设置样式。
如果开发人员更喜欢使用代码隐藏模型编写控件,其中编写视图,然后编写直接代码来处理事件。
您不会在应用程序之间共享控件。
让我们以用户控件为例,并按照以下步骤操作:
步骤 1 − 创建一个新的 WPF 项目,然后右键单击您的解决方案并选择添加 > 新建项…
步骤 2 − 将打开以下对话框,现在选择用户控件 (WPF) 并将其命名为MyUserControl。
步骤 3 − 单击“添加”按钮,您将看到两个新文件 (MyUserControl.xaml 和 MyUserControl.cs) 将添加到您的解决方案中。
下面是在 MyUserControl.xaml 文件中创建按钮和文本框以及一些属性的 XAML 代码。
<UserControl x:Class = "XAMLUserControl.MyUserControl" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "300"> <Grid> <TextBox Height = "23" HorizontalAlignment = "Left" Margin = "80,49,0,0" Name = "txtBox" VerticalAlignment = "Top" Width = "200" /> <Button Content = "Click Me" Height = "23" HorizontalAlignment = "Left" Margin = "96,88,0,0" Name = "button" VerticalAlignment = "Top" Width = "75" Click = "button_Click" /> </Grid> </UserControl>
下面是在 MyUserControl.cs 文件中用于按钮单击事件的 C# 代码,该代码更新文本框。
using System; using System.Windows; using System.Windows.Controls; namespace XAMLUserControl { /// <summary> /// Interaction logic for MyUserControl.xaml /// </summary> public partial class MyUserControl : UserControl { public MyUserControl() { InitializeComponent(); } private void button_Click(object sender, RoutedEventArgs e) { txtBox.Text = "You have just clicked the button"; } } }
以下是 MainWindow.xaml 中添加用户控件的实现。
<Window x:Class = "XAMLUserControl.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:control = "clr-namespace:XAMLUserControl" Title = "MainWindow" Height = "350" Width = "525"> <Grid> <control:MyUserControl/> </Grid> </Window>
编译并执行上述代码后,将产生以下输出 -
现在单击“单击我”按钮,您将看到文本框文本已更新。
自定义控件
自定义控件是一个类,它提供自己的样式和模板,这些样式和模板通常在generic.xaml中定义。自定义控件用于以下场景:
如果控件不存在,并且您必须从头创建它。
如果您想通过添加额外属性或额外功能来扩展或添加现有控件的功能以适应您的特定场景。
如果您的控件需要支持主题和样式。
如果您想跨应用程序共享您的控件。
让我们以自定义控件为例,并按照以下步骤操作。
步骤 1 − 创建一个新的 WPF 项目,然后右键单击您的解决方案并选择添加 > 新建项…
步骤 2 − 将打开以下对话框。现在选择自定义控件 (WPF) 并将其命名为MyCustomControl。
步骤 3 − 单击“添加”按钮,您将看到两个新文件 (Themes/Generic.xaml 和 MyCustomControl.cs) 将添加到您的解决方案中。
下面是在 Generic.xaml 文件中为自定义控件设置样式的 XAML 代码。
<ResourceDictionary xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local = "clr-namespace:XAMLCustomControls"> <Style TargetType = "{x:Type local:MyCustomControl}" BasedOn = "{StaticResource {x:Type Button}}"> <Setter Property = "Background" Value = "LightSalmon"/> <Setter Property = "Foreground" Value = "Blue"/> </Style> </ResourceDictionary>
下面是 MyCustomControl 类的 C# 代码,它继承自按钮类,并且在构造函数中,它重写了元数据。
using System; using System.Windows; using System.Windows.Controls; namespace XAMLCustomControls { public class MyCustomControl : Button { static MyCustomControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl))); } } }
下面是在 C# 中自定义控件单击事件的实现,它更新文本块的文本。
using System; using System.Windows; using System.Windows.Controls; namespace XAMLCustomControls { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void customControl_Click(object sender, RoutedEventArgs e) { txtBlock.Text = "You have just click your custom control"; } } }
以下是 MainWindow.xaml 中添加自定义控件和文本块的实现。
<Window x:Class = "XAMLCustomControls.MainWindow" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:control = "clr-namespace:XAMLCustomControls" Title = "MainWindow" Height = "350" Width = "604"> <StackPanel> <control:MyCustomControl x:Name = "customControl" Content = "Click Me" Width = "70" Margin = "10" Click = "customControl_Click"/> <TextBlock Name = "txtBlock" Width = "250" Height = "30"/> </StackPanel> </Window>
编译并执行上述代码后,它将产生以下输出。请注意,输出包含一个自定义控件,它是一个自定义按钮。
现在单击自定义按钮。您将看到文本块文本已更新。