- [1. Attribute=Value方式](#1. Attribute=Value方式)
- [1.1. 简单属性赋值](#1.1. 简单属性赋值)
- [1.2. 对象属性赋值](#1.2. 对象属性赋值)
- [2. 属性标签的方式给属性赋值](#2. 属性标签的方式给属性赋值)
- [3. 标签扩展 (Markup Extensions)](#3. 标签扩展 (Markup Extensions))
- [3.1. StaticResource](#3.1. StaticResource)
- [3.2. Binding](#3.2. Binding)
- [3.2.1. 普通 Binding](#3.2.1. 普通 Binding)
- [3.2.2. ElementName Binding](#3.2.2. ElementName Binding)
- [3.2.3. RelativeSource Binding](#3.2.3. RelativeSource Binding)
- [3.2.4. StaticResource Binding (带参数的 Binding)](#3.2.4. StaticResource Binding (带参数的 Binding))
- [3.2.5. TemplateBinding](#3.2.5. TemplateBinding)
- [3.3. 标签扩展总结:](#3.3. 标签扩展总结:)
- [3.4. 标签扩展注意:](#3.4. 标签扩展注意:)
1. Attribute=Value方式
1.1. 简单属性赋值
<Grid>
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
上面的代码中Content
HorizontalAlignment
VerticalAlignment
Width
Click
都是直接复制的方式,但可以看到这种复制最简单,但不能赋太复杂的值。
优点: 赋值方便。
缺点: Value为字符串,但是对象属性未必是字符串,因此无法赋太复杂的值。
1.2. 对象属性赋值
先在cs代码中定义对象Human
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
}
然后我们xaml上有个Human对象,并给human对象的Child属性赋值
xaml代码:
<Window x:Class="MyWPFDemo1.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:MyWPFDemo1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
<Window.Resources>
<local:Human x:Key="Human1" Name="小明"/>
</Window.Resources>
</Window>
cs代码:
namespace MyWPFDemo1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Human h = (Human)this.FindResource("Human1");
MessageBox.Show(h.Name);
//MessageBox.Show(h.Name + "的孩子是" + h.Child.Name); //xaml中没有给child对象赋值,所以直接访问会报错
}
}
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
}
}
在上面的示例中human类中的属性child没有被赋值,如果赋值为字符串会编译出错,那么只有通过实现typeConverter来进行扩展。
首先,我们要从TypeConverter
类派生出自己的类,并重写它的一个ConvertFrom
方法。这个方法有一个参数名为value,这个值就是在XAML文档里为它设置的值我们要做的就是把这个值"翻译"成合适类型的值赋给对象的属性:
[TypeConverterAttribute(typeof(StringToHumanConvertor))]
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
}
public class StringToHumanConvertor : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
string name = value.ToString();
Human child = new Human();
child.Name = name;
return child;
}
}
这样就可以在xaml中直接对Child属性赋值了,
<Window.Resources>
<local:Human x:Key="Human1" Name="小明" Child="小小明"/>
</Window.Resources>
2. 属性标签的方式给属性赋值
在XAML中,非空标签均具有自己的内容(Content)。标签的内容指的就是夹在起始标签和结束标签之间的一些子级标签,每个子级标签都是父级标签内容的一个元素(Element),简称为父级标签的一个元素。顾名思义,属性元素指的是某个标签的一个元素对应这个标签的一个属性,即以元素的形式来表达一个实例的属性。代码描述为:
<ClassName>
<ClassName.PropertyName>
<!--以对象形式为对象的属性赋值-->
</ClassName.PropertyName>
</ClassName>
遇到属性是复杂对象时这种语法的优势就体现出来了,如使用线性渐变画刷来填充这个矩形。遇到属性是复杂对象时这种语法的优势就体现出来了,如使用线性渐变画刷来填充这个矩形。
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Rectangle x:Name="rectangle" Width="200" Height="120">
<Rectangle.Fill>
<LinearGradientBrush>
<LinearGradientBrush.StartPoint>
<Point X="0" Y="0"/>
</LinearGradientBrush.StartPoint>
<LinearGradientBrush.EndPoint>
<Point X="1" Y="1"/>
</LinearGradientBrush.EndPoint>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.2" Color="LightBlue"/>
<GradientStop Offset="0.7" Color="Blue"/>
<GradientStop Offset="1.0" Color="DarkBlue"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
3. 标签扩展 (Markup Extensions)
仔细观察XAML中为对象属性赋值的语法,你会发现大多数赋值都是为属性生成一个新对象。但有时候需要把同一个对象赋值给两个对象的属性,还有的时候需要给对象的属性赋一个null值,WPF甚至允许将一个对象的属性值依赖在其他对象的某个属性上。当需要为对象的属性进行这些特殊类型赋值时就需要使用标记扩展了。
- 所谓标记扩展,实际上是一种特殊的Attribute=Value语法,其特殊的地方在于Value字符串是由一对花括号及其括起来的内容组成,XAML编译器会对这样的内容做出解析、生成相应的对象。
在 WPF 中,标签扩展 (MarkupExtension
) 主要用于提供数据绑定、资源引用等动态功能。对于资源引用和数据绑定,常用的标签扩展有两种主要类型:StaticResource
和 Binding
。而对于这些标签扩展,我们通常会有不同的方式来绑定数据或引用资源。
3.1. StaticResource
StaticResource
是一种标签扩展,用于从资源字典中引用资源。在 XAML 中,StaticResource
通过键名查找静态资源。这是一种在应用启动时就加载并且在整个应用程序生命周期内不会改变的资源引用方式。
xaml
<Button Content="{StaticResource MyButtonStyle}" />
3.2. Binding
Binding
标签扩展用于数据绑定,允许将 UI 元素的属性绑定到数据源。数据源可以是任何实现了 INotifyPropertyChanged
接口的对象或其他可绑定的对象。Binding
是数据绑定机制的核心。
Binding
也有多种方式和特性,以下是 5 种常见的绑定方式:
3.2.1. 普通 Binding
最常见的 Binding
方式,通过指定一个数据源和路径来绑定。
xaml
<TextBlock Text="{Binding Path=Name}" />
3.2.2. ElementName Binding
将数据绑定到页面中的另一个元素,通过 ElementName
指定源元素。
xaml
<TextBlock Text="{Binding Path=Text, ElementName=myTextBox}" />
<TextBox Name="myTextBox" Text="Hello World" />
3.2.3. RelativeSource Binding
使用 RelativeSource
绑定来指定相对于当前元素的上下文,例如父元素或祖先元素。
xaml
<TextBlock Text="{Binding Path=Name, RelativeSource={RelativeSource AncestorType=Window}}" />
3.2.4. StaticResource Binding (带参数的 Binding)
通过 Binding
与静态资源配合使用,比如从资源字典中绑定样式或其他资源。
xaml
<TextBlock Text="{Binding Source={StaticResource MyResourceKey}}" />
3.2.5. TemplateBinding
TemplateBinding
是一种简化的绑定方式,通常用于控制模板中的元素。它通常用于控件模板中的数据绑定,简化了 Binding
的写法。
xaml
<Button Content="{TemplateBinding Button.Content}" />
3.3. 标签扩展总结:
在 WPF 中,常见的 Binding
和 StaticResource
标签扩展包括以下五种主要方式:
StaticResource
用于引用静态资源。
普通 Binding
,直接绑定数据源和属性。
ElementName
绑定,绑定到同一页面中的另一个元素。
RelativeSource
绑定,基于元素的相对位置进行绑定。
TemplateBinding
,简化控件模板中的绑定。
3.4. 标签扩展注意:
● 标记扩展是可以嵌套的,例如Text="{Binding Source=(StaticResource myDataSource),Path=PersonName)"是正确的语法。
● 标记扩展具有一些简写语法,例如"{Binding Value,....!"与"[Binding Path=Value,...]"是等价的、"(StaticResource myString,....}"与"(StaticResource ResourceKey-myString,....)" 是等价的。两种写法中,前者称为固定位置参数 (Positional Parameter),后者称为具名参数(Named Parameters)。固定位置参数实际上就是标记扩展类构造器的参 数,其位置由构造器参数列表决定。
● 标记扩展类的类名均以单词Extension为后级,在XAML使用它们的时候 Extension 后级可以省略不写,比如写Text-"{x:Static.....}" 与写Text="{x:StaticExtension....}"是等价的。