看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>
运行效果: