1、XAML是一种声明式语言,通过在XAML中声明一个节点来定义对象,XAML解析器会把声明的对象解析成C#中的一个对象
2、WPF中的两颗树
-
逻辑树——XAML中通过声明控件形成的树
-
可视化树——如果把所有的控件(包含控件中包含的控件)都看作一棵树的话就是可视化树
-
可以使用LogicalTreeHelper和VisualTreeHelper来操作树中的节点
3、使用TypeConverter将XAML中的Attribute和C#类中的Property进行映射
例如:有一个类
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
}
在xaml中使用时,我想给Child属性直接赋值
<local:Human Name="TestName" Child="TestChildName"></local:Human>
而不是使用如下方式:
<local:Human x:Key="testKey" Name="TestName">
<local:Human.Child>
<local:Human Name="TestChildName" />
</local:Human.Child>
</local:Human>
就需要一个TypeConverter来实现,因为第一种方式Child属性接收的是字符串类型
先定义一个TypeConverter:
/// <summary>
/// 重载此方法可以在写Xaml时没有错误提示
/// </summary>
/// <param name="context"></param>
/// <param name="sourceType"></param>
/// <returns></returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// 把字符串转换成Human对象
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <returns></returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string inpuString)
{
return new Human()
{
Name = inpuString
};
}
return base.ConvertFrom(context, culture, value);
}
然后把TypeConverter应用到Human类
[TypeConverter(typeof(HumanTypeConverter))]
public class Human
{
public string Name { get; set; }
public Human Child { get; set; }
}
如果不实现CanConvertFrom方法,则会报以下错误
4、标记扩展(MarkupExtensions)
a)所谓标记扩展,实际上是一种特殊的Attribute=Value语法,特殊的地方在与Value字符串由一堆花括号及其括起来的内容组成,XAML编译器会对这样的内容作出解析,生成相应的对象,例如:
<TextBlock Text="{Binding Name, Source={StaticResource testKey}}" />
b)尽管标记扩展的语法简洁方便,单并不是所有的对象都可以用标记扩展的语法类书写,只有MarkupExtension类的派生类(直接或间接)才能使用标记扩展语法类创建对象
c)标记扩展是可以嵌套的,比如:
<TextBlock Text="{Binding Path=Name, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Grid}}" />
d)参照下面两种写法
<TextBlock Text="{Binding Name, Source={StaticResource testKey}}" />
<TextBlock Text="{Binding Path=Name, Source={StaticResource testKey}}" />
前者中的Name为固定位置参数(Positional Parameters),后者中的Name为具名参数(Named Parameters),固定位置参数实际上是标记扩展类的构造函数的参数,其位置顺序由构造函数的参数决定
5、x:Code标签,允许在xaml文件中编写C#代码(代码必须写在CDATA标签中),但是没有智能提示,其实也没有实际意义……
<Grid>
<TextBlock Text="{Binding Path=Name, Source={StaticResource testKey}}" />
<x:Code>
<![CDATA[
private void TestButton_Click(object sender, RoutedEventArgs e)
{
Human human = this.Resources["testKey"] as Human;
MessageBox.Show(human.Child.Name);
}
]]>
</x:Code>
</Grid>
6、xaml中的注释
只能出现在标签的内容区域,即只能出现在开始标签和结束标签之间
不能单独注释标签的Attribute
不能嵌套
<!--<local:Human x:Key="testKey" Name="TestName">
<local:Human.Child>
<local:Human Name="TestChildName" />
</local:Human.Child>
</local:Human>-->