看B站刘铁猛老师视频学习WPF
XAML语言是从xml文件派生而来,是声明式语言,一个标签就表示声明了一个对象。
对象的值可以存储在对象的字段中,也可存储在对象的属性中;
通过给对象的属性赋值,可以在赋值时检查值的合法性,如果不合法可以抛异常给提示。
在XAML中给对象的属性赋值有3中方式:
- Attribute=value
- 属性标签
- 标签扩展
1、Attribute=value
优点:简单快捷
缺点:不易给属性赋复杂值
<Rectangle Height="50" Width="200" Stroke="Red" Fill="Gold" RadiusX="20" RadiusY="10"></Rectangle> <Path Data="M 0,0 L 200,100 L 100,200 Z" Stroke="Red" Fill="Green" ></Path><!--Path对象的Data属性值稍复杂--><!--两个对象中都有Stroke属性,类型是Brush-->
Path对象的Data属性是Geometry类型, Data="M 0,0 L 200,100 L 100,200 Z"实现了对Data的赋值。然而这对于人来说是既不易阅读,也不易书写。
如果属性的类型比Data还复杂,就需要使用第二种方式进行赋值了。
补充:
两个对象中都有Stroke、Fill属性,类型都是Brush;
在xaml文件中,对Stroke属性赋的是字符串,这个字符串最后都被转换Stroke对象了
这是怎么实现的呢?
(1)在后台文件中添加Person类
public class Person{/// <summary>/// 姓名/// </summary>public string Name { get; set; }/// <summary>/// 母亲/// </summary>public Person Mother { get; set; }/// <summary>/// 父亲/// </summary>public Person Father { get; set; }}
(2)在前台文件中添加资源
资源是通过key来检索的,资源中添加Person对象时候,需要指定一个key
<Window x:Class="WpfApp1.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:WpfApp1"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Window.Resources><!--资源是通过key来检索的,在资源中添加对象时需要指定key--><local:Person x:Key="pon" Name="Jeff" ></local:Person></Window.Resources><Grid><Button Width="100" Height="50" Content="Show" Click="Button_Click"></Button></Grid>
</Window>
(3)编辑Button_Click事件
private void Button_Click(object sender, RoutedEventArgs e){//通过key检索资源Person p = this.FindResource("pon") as Person;if (p == null){MessageBox.Show("空对象");}else{StringBuilder sb = new StringBuilder($"姓名:{p.Name}\n");if (p.Mother != null){sb .Append($"妈妈:{p.Mother.Name}\n");}if (p.Father != null){sb.Append($"爸爸:{p.Father.Name}\n");}MessageBox.Show(sb.ToString());}}
运行效果:
(4)给Person的其他属性赋值
<local:Person x:Key="pon" Name="Jeff" Mother="Anna" ></local:Person>
运行效果:
(5)报异常了,显然我们不能给复杂属性(Mother、Father) 直接使用Attribute=value方式赋值,那么怎么样才能像前文中那样Stroke="Red" Fill="Gold"?
这就需要用到System.ComponentModel.TypeConverter类了
添加声明一个新类,继承自System.ComponentModel.TypeConverter
/// <summary>/// 通过重新ConvertFrom方法实现将一个简单类型,通过赋值,转换成一个复杂对象 /// </summary>public class NameToPersonTypeConvert : System.ComponentModel.TypeConverter{public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value){string name = value.ToString();Person person = new Person();person.Name = name;return person;//return base.ConvertFrom(context, culture, value);}}
(6)下一步就是把这个类附加到Person上,
//将NameToPersonTypeConvert类以特性方式附加到Person类上[TypeConverterAttribute(typeof(NameToPersonTypeConvert))]public class Person{/// <summary>/// 姓名/// </summary>public string Name { get; set; }/// <summary>/// 母亲/// </summary>public Person Mother { get; set; }/// <summary>/// 父亲/// </summary>public Person Father { get; set; }}
运行效果:
通过以上步骤,就完成了给对象的复杂类型属性赋一个简单值
2、属性标签
在xaml中,标签是用来声明对象的。
<!--标签内容,是夹在开始标签和结束标签之间的部分。注意区分概念--><Button Width="100" Height="50" Content="这里是对象的内容">这里是标签的内容</Button>
属性标签的格式是:<类名.属性名></类名.属性名>
缺点:代码变多
示例1:
Button的Content是object类型
<Button Width="100" Height="50" ><Button.Content><Rectangle Width="20" Height="20" Stroke="Green" Fill="Green"></Rectangle></Button.Content></Button>
示例2:
Rectangle的Fill是Brush类型
<Rectangle Width="400" Height="400" Stroke="Blue"><Rectangle.Fill><!--设置渐变填充--><LinearGradientBrush><LinearGradientBrush.StartPoint><!--开始位置--><Point X="0" Y="0"></Point></LinearGradientBrush.StartPoint><LinearGradientBrush.EndPoint><!--结束位置--><Point X="1" Y="1"></Point></LinearGradientBrush.EndPoint><LinearGradientBrush.GradientStops><GradientStopCollection><!--设置描述渐变中转换点的位置和颜色--><GradientStop Offset="0.1" Color="Red"></GradientStop><GradientStop Offset="0.3" Color="Yellow"></GradientStop><GradientStop Offset="0.5" Color="Green"></GradientStop><GradientStop Offset="0.7" Color="Pink"></GradientStop><GradientStop Offset="0.9" Color="Pink"></GradientStop></GradientStopCollection></LinearGradientBrush.GradientStops></LinearGradientBrush></Rectangle.Fill></Rectangle>
补充:
(1)Brush的类图关系如下:
(2)注意要点
- 能用attribute=value方式赋值是,就不要用属性标签;
- 如果要赋的值正好是默认值,就不要用在属性标签中写出来;
- 对于属性标签,如果属性值是一组集合,可以不写集合的名称,直接罗列集合元素
示例2的代码可优化成这种方式:
<Rectangle Width="400" Height="400" Stroke="Blue"><Rectangle.Fill><!--开始点、结束点使用attri=value方式赋值 --><!-- StartPoint="0,0" EndPoint="1,1" 是LinearGradientBrush 的默认值,在这里可以不写--><LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <LinearGradientBrush.GradientStops> <!--属性标签是集合,可以直接罗列元素不写属性名称--><GradientStop Offset="0.1" Color="Red"></GradientStop><GradientStop Offset="0.3" Color="Yellow"></GradientStop><GradientStop Offset="0.5" Color="Green"></GradientStop><GradientStop Offset="0.7" Color="Pink"></GradientStop><GradientStop Offset="0.9" Color="Pink"></GradientStop> </LinearGradientBrush.GradientStops></LinearGradientBrush></Rectangle.Fill></Rectangle>
3、标签扩展
标签扩展方式赋值与attribute=value赋值方式类型,只是这个value比较特殊,是花括号括起来的一组值。
WPF中的标签扩展是有限的,我们只要掌握常用的即可
示例1
StaticResource 标签扩展
<Window x:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:sys="clr-namespace:System;assembly=mscorlib"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp1"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Window.Resources><!--在资源中定义字符串,这里需要添加命名空间如下xmlns:sys="clr-namespace:System;assembly=mscorlib"--><sys:String x:Key="strHello">Hello World</sys:String></Window.Resources><Grid><!--文本框显示的字符串来自Window.Resources--><TextBlock Height="30" Width="200" Background="LightYellow" Text="{StaticResource ResourceKey=strHello}"> </TextBlock><TextBlock Height="30" Width="200" Background="LightPink" Text="{StaticResource strHello}" Margin="262,251,330,138"></TextBlock></Grid>
</Window>
运行效果:
示例2
Binding标签扩展
<Grid> <Grid.RowDefinitions><RowDefinition Height="30"></RowDefinition><RowDefinition Height="3"></RowDefinition><RowDefinition Height="30"></RowDefinition></Grid.RowDefinitions><TextBlock x:Name="tb" Text="{Binding ElementName=sld,Path=Value}" Width="150" Height="25" Background="LightCoral"></TextBlock><Slider x:Name="sld" Grid.Row="2" Value="50" Maximum="100" Minimum="0" ></Slider> </Grid>
运行效果: