WPF-04 XAML概述

文章目录

    • [一、XAML 简介](#一、XAML 简介)
      • [1.1 什么是 XAML?](#1.1 什么是 XAML?)
      • [1.2 XAML 的特点](#1.2 XAML 的特点)
      • [1.3 一个最简单的 XAML 示例](#1.3 一个最简单的 XAML 示例)
    • [二、XAML 语法基础](#二、XAML 语法基础)
      • [2.1 对象元素](#2.1 对象元素)
      • [2.2 属性设置](#2.2 属性设置)
        • [2.2.1 特性语法(Attribute Syntax)](#2.2.1 特性语法(Attribute Syntax))
        • [2.2.2 属性元素语法(Property Element Syntax)](#2.2.2 属性元素语法(Property Element Syntax))
        • [2.2.3 内容属性(Content Property)](#2.2.3 内容属性(Content Property))
        • [2.2.4 集合语法(Collection Syntax)](#2.2.4 集合语法(Collection Syntax))
      • [2.3 事件处理](#2.3 事件处理)
      • [2.4 标记扩展(Markup Extensions)](#2.4 标记扩展(Markup Extensions))
      • [2.5 类型转换器(Type Converters)](#2.5 类型转换器(Type Converters))
    • [三、XAML 命名空间与类型映射](#三、XAML 命名空间与类型映射)
      • [3.1 默认 XAML 命名空间](#3.1 默认 XAML 命名空间)
      • [3.2 XAML 语言命名空间(x:)](#3.2 XAML 语言命名空间(x:))
      • [3.3 自定义前缀与外部程序集](#3.3 自定义前缀与外部程序集)
    • [四、XAML 高级概念](#四、XAML 高级概念)
      • [4.1 附加属性(Attached Properties)](#4.1 附加属性(Attached Properties))
      • [4.2 附加事件(Attached Events)](#4.2 附加事件(Attached Events))
      • [4.3 命名元素(x:Name)](#4.3 命名元素(x:Name))
      • [4.4 基类与 XAML](#4.4 基类与 XAML)
    • [五、XAML 与代码隐藏](#五、XAML 与代码隐藏)
      • [5.1 分部类与 x:Class](#5.1 分部类与 x:Class)
      • [5.2 事件处理程序](#5.2 事件处理程序)
    • [六、XAML 安全性(简要)](#六、XAML 安全性(简要))
      • [动态加载 XAML](#动态加载 XAML)

一、XAML 简介

1.1 什么是 XAML?

  • XAML (eXtensible Application Markup Language)是一种声明式标记语言,专门用于构建 .NET 应用程序的用户界面(UI)。
  • 它基于 XML 语法,但与 XML 的本质区别在于:XAML 直接映射到 .NET 对象。每个 XAML 元素对应一个 .NET 类的实例,属性对应类的属性或事件。
  • 通过 XAML,开发者可以将 UI 结构与业务逻辑分离:UI 用 XAML 定义,逻辑用 C#、VB 等代码隐藏文件实现。

1.2 XAML 的特点

  • 声明式:描述 UI 的外观和组织结构,而非创建过程。
  • 可读性强:结构清晰,易于理解和维护。
  • 工具友好:支持可视化设计器(如 Visual Studio、Blend)。
  • 与代码无缝集成 :通过 x:Class 将 XAML 与后台代码关联。

1.3 一个最简单的 XAML 示例

xml 复制代码
<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="我的应用" Height="200" Width="300">
    <StackPanel>
        <Button Content="单击我" Width="100" Height="30"/>
    </StackPanel>
</Window>

这个例子创建了一个窗口,包含一个按钮。WindowButton 都是 WPF 中的类。


二、XAML 语法基础

2.1 对象元素

  • 对象元素 声明一个类型的实例,使用 <类型名> 标签。
  • 标签可以成对出现(<StackPanel>...</StackPanel>),也可以是自结束形式(<Button />)。
xml 复制代码
<!-- 对象元素示例 -->
<StackPanel>
    <Button Content="按钮1" />
    <Button Content="按钮2" />
</StackPanel>

当 XAML 被解析时,会调用类型的默认构造函数来创建实例。

2.2 属性设置

2.2.1 特性语法(Attribute Syntax)
  • 最简单的属性设置方式,直接写在开始标签内。
  • 属性值用双引号括起,通常为字符串,通过类型转换器转换为目标类型。
xml 复制代码
<Button Background="Blue" Foreground="White" Content="确定" Width="80"/>
2.2.2 属性元素语法(Property Element Syntax)
  • 当属性值是一个复杂对象时,无法用简单字符串表示,就需要使用属性元素。
  • 格式:<类型名.属性名>,内部包含用于设置该属性的对象元素。
xml 复制代码
<Button>
    <Button.Background>
        <SolidColorBrush Color="Blue"/>
    </Button.Background>
    <Button.Foreground>
        <SolidColorBrush Color="White"/>
    </Button.Foreground>
    <Button.Content>
        确定
    </Button.Content>
</Button>
2.2.3 内容属性(Content Property)
  • 每个类可以指定一个属性作为内容属性 (使用 [ContentProperty] 特性标记)。
  • 设置内容属性时,可以直接将子元素写在标签内部,省略属性元素。

例如 Button 的内容属性是 Content,因此下面两种写法等价:

xml 复制代码
<!-- 隐式使用内容属性 -->
<Button>确定</Button>

<!-- 显式使用内容属性 -->
<Button>
    <Button.Content>
        确定
    </Button.Content>
</Button>

对于 StackPanel,它的内容属性是 Children,所以可以直接添加子元素:

xml 复制代码
<StackPanel>
    <Button>按钮1</Button>
    <Button>按钮2</Button>
</StackPanel>
2.2.4 集合语法(Collection Syntax)
  • 如果属性是一个集合类型(如 IListICollection),可以直接在属性元素内部添加多个子元素,而无需显式写出集合对象。
  • 例如 StackPanel.ChildrenUIElementCollection 类型,但我们可以直接添加子元素:
xml 复制代码
<StackPanel>
    <StackPanel.Children>
        <Button>按钮1</Button>
        <Button>按钮2</Button>
    </StackPanel.Children>
</StackPanel>

实际中,由于内容属性常与集合语法结合,我们通常只写:

xml 复制代码
<StackPanel>
    <Button>按钮1</Button>
    <Button>按钮2</Button>
</StackPanel>

2.3 事件处理

  • 事件也可以通过特性语法关联处理程序,格式为 事件名="处理程序方法名"
  • 处理程序需在代码隐藏文件中实现。
xml 复制代码
<Button Click="Button_Click" Content="单击我"/>
csharp 复制代码
// 代码隐藏文件 (MainWindow.xaml.cs)
private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("按钮被单击了!");
}

2.4 标记扩展(Markup Extensions)

  • 当属性值需要从其他资源、数据绑定或静态属性获取时,使用标记扩展。
  • 语法:{扩展名 参数}。例如 {Binding}{StaticResource}{x:Static}
xml 复制代码
<Button Content="{Binding UserName}" />
<Button Background="{StaticResource MyBrush}" />
<TextBlock Text="{x:Static SystemFonts.IconFontFamily}" />

2.5 类型转换器(Type Converters)

  • 很多属性接受复杂类型,但 XAML 允许用字符串表示,通过类型转换器自动转换。
  • 例如 Brush 类型可以通过颜色名称字符串转换:
xml 复制代码
<Button Background="Red" />

等价于:

xml 复制代码
<Button>
    <Button.Background>
        <SolidColorBrush Color="Red"/>
    </Button.Background>
</Button>

再如 Thickness 类型:

xml 复制代码
<Button Margin="5,10,5,10" />

等价于:

xml 复制代码
<Button>
    <Button.Margin>
        <Thickness Left="5" Top="10" Right="5" Bottom="10"/>
    </Button.Margin>
</Button>

三、XAML 命名空间与类型映射

3.1 默认 XAML 命名空间

  • 每个 XAML 文件的根元素必须声明 XML 命名空间,以将 XAML 元素映射到实际的 .NET 类型。
  • WPF 的默认命名空间:http://schemas.microsoft.com/winfx/2006/xaml/presentation
    它映射到 WPF 的核心程序集(PresentationFramework、PresentationCore、WindowsBase)。
  • 没有前缀的元素都来自此默认命名空间。

3.2 XAML 语言命名空间(x:)

  • 第二个常用的命名空间:http://schemas.microsoft.com/winfx/2006/xaml
    通常使用前缀 x:
  • 它提供 XAML 语言级别的指令,如:
    • x:Class:指定代码隐藏的分部类名。
    • x:Name:为元素命名,以便在后台代码中引用。
    • x:Key:为资源字典中的资源定义唯一键。
    • x:Static:引用静态成员。
    • x:Type:引用 Type 对象。

示例:

xml 复制代码
<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="示例" Height="200" Width="300">
    <Grid>
        <Button x:Name="myButton" Content="单击" Click="Button_Click"/>
    </Grid>
</Window>

3.3 自定义前缀与外部程序集

  • 如需使用自定义程序集中的类型,可在根元素中定义新的 xmlns 前缀,映射到 CLR 命名空间和程序集。
  • 语法:xmlns:前缀="clr-namespace:命名空间;assembly=程序集名称"
xml 复制代码
<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyApp.CustomControls"
        Title="自定义控件示例" Height="200" Width="300">
    <StackPanel>
        <local:MyNumericUpDown Value="10"/>
    </StackPanel>
</Window>

四、XAML 高级概念

4.1 附加属性(Attached Properties)

  • 允许一个元素设置不属于自己定义的属性,通常用于布局或交互场景。
  • 语法:所有者类型.属性名="值"
  • 例如,DockPanel.Dock 是一个附加属性,由 DockPanel 类定义,但可以设置在 Button 上。
xml 复制代码
<DockPanel>
    <Button DockPanel.Dock="Left" Content="左侧按钮"/>
    <Button DockPanel.Dock="Right" Content="右侧按钮"/>
    <Button Content="中间按钮"/>
</DockPanel>

工作原理DockPanel 在布局时会检查每个子元素是否有 DockPanel.Dock 附加属性值,然后决定排列方式。

4.2 附加事件(Attached Events)

  • 类似附加属性,允许子元素为父元素定义的事件添加处理程序。
  • 语法:所有者类型.事件名="处理程序方法名"
  • 例如,在 Grid 上处理其内部所有按钮的 Click 事件:
xml 复制代码
<Grid Button.Click="Grid_Click">
    <Button Content="按钮1"/>
    <Button Content="按钮2"/>
</Grid>
csharp 复制代码
private void Grid_Click(object sender, RoutedEventArgs e)
{
    // 注意:sender 是 Grid,但 e.OriginalSource 是实际被单击的按钮
    MessageBox.Show($"单击了 {(e.OriginalSource as Button).Content}");
}

4.3 命名元素(x:Name)

  • 使用 x:Name 为元素分配一个唯一标识符,以便在后台代码中直接访问该对象。
  • 许多 WPF 元素也提供了同名的 Name 属性(如 FrameworkElement.Name),两者等价。
xml 复制代码
<TextBox x:Name="txtInput" Width="200"/>
<Button Click="Button_Click" Content="显示文本"/>
csharp 复制代码
private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show(txtInput.Text);  // 直接访问 txtInput
}

4.4 基类与 XAML

  • 虽然 XAML 直接实例化具体类型,但所有 WPF 控件都继承自 FrameworkElement(或 FrameworkContentElement),从而获得大量通用属性(如 WidthHeightMarginName 等)。
  • 理解继承关系有助于掌握哪些属性可以在哪些元素上使用。

五、XAML 与代码隐藏

5.1 分部类与 x:Class

  • XAML 文件通过 x:Class 指令指定代码隐藏的类名。
  • 编译器会将 XAML 生成的代码和开发者编写的代码合并为一个分部类。
xml 复制代码
<Window x:Class="MyApp.MainWindow" ...>
    ...
</Window>

在后台代码文件中:

csharp 复制代码
namespace MyApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();  // 由 XAML 编译器生成的方法,用于加载 UI
        }
    }
}

5.2 事件处理程序

  • 在 XAML 中声明事件处理程序时,方法必须存在于分部类的另一部分中。
  • 处理程序必须匹配委托签名(通常为 object sender, RoutedEventArgs e)。
xml 复制代码
<Button Click="OnButtonClick" Content="确定"/>
csharp 复制代码
private void OnButtonClick(object sender, RoutedEventArgs e)
{
    // 处理逻辑
}

六、XAML 安全性(简要)

  • 在部分信任环境(如 XBAP、Internet 区域)中运行的 XAML 受到 .NET 安全策略限制,不能执行某些危险操作(如文件 I/O、网络访问等)。
  • 完全信任的应用程序可以加载和执行任何 XAML。

动态加载 XAML

  • 使用 XamlReader.Load 方法可以从字符串或文件动态加载 XAML 并创建对象树。
  • 通常用于插件、主题切换等场景。
csharp 复制代码
string xaml = "<Button xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' Content='动态按钮'/>";
var button = (Button)XamlReader.Parse(xaml);
myStackPanel.Children.Add(button);

相关推荐
△曉風殘月〆19 小时前
如何在WPF中捕获窗口外的事件
wpf
爱吃烤鸡翅的酸菜鱼2 天前
Java 事件发布-订阅机制全解析:从原生实现到主流中间件
java·中间件·wpf·事件·发布订阅
武藤一雄3 天前
WPF中ViewModel之间的5种通讯方式
开发语言·前端·microsoft·c#·wpf
CSharp精选营3 天前
都是微软亲儿子,WPF凭啥干不掉WinForm?这3个场景说明白了
c#·wpf·跨平台·winform
baivfhpwxf20233 天前
wpf TextBlock 控件如何根据内容换行?
wpf
亘元有量-流量变现3 天前
鸿蒙、安卓、苹果音频设备技术深度解析与开发实践
android·wpf·harmonyos·亘元有量·积分墙
软泡芙3 天前
【Bug】ReactiveUI WPF绑定中依赖属性不更新的问题分析与解决方案
java·bug·wpf
浪扼飞舟3 天前
WPF输入验证(ValidationRule)
java·javascript·wpf
IOFsmLtzR5 天前
Flink Agents 源码解读 --- (5) --- ActionExecutionOperator
microsoft·flink·wpf