WPF XAML 系统学习XAML语法

【XAML文档的树形结构】

   

     UI在用户眼里面是个平面结构。如下图所示,在用户眼里看来,这个界面就是一个窗体里面平铺了4个文本框和一个按钮的界面。



    在传统的Visual C++、Delphi、Visual Basic6.0和Windows Form程序员的思维里,UI也是一个平面的结构。因此,程序员要做的事情就是根据美工给的给定的UI布局把控件安置在窗体的表面,并用使用长度,宽度和间距把控件对齐。


    与传统的设计思维不同,XAML使用树形逻辑结构来描述UI,下面是用来描述界面布局的XAML代码:

<Window x:Class="WpfApplication1.wnd31"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="304" Width="525">
    <Grid Background="LightSlateGray">
        <Grid.RowDefinitions>
            <RowDefinition Height="49*"/>
            <RowDefinition Height="70*"/>
            <RowDefinition Height="62*"/>
            <RowDefinition Height="50*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="276*"/>
            <ColumnDefinition Width="241*"/>
        </Grid.ColumnDefinitions>
        <TextBox Height="28" Margin="5" Text="TextBox" Width="497" Grid.ColumnSpan="2" Grid.Row="0"/>
        <TextBox Height="28" Margin="5" Text="TextBox" Width="497" Grid.ColumnSpan="2" Grid.Row="1"/>
        <TextBox Height="28" Margin="5" Text="TextBox" Width="257" Grid.ColumnSpan="1" Grid.Row="2"/>
        <TextBox Height="28" Margin="5" Text="TextBox" Width="226" Grid.ColumnSpan="1" Grid.Row="2" Grid.Column="1" />
        <Button Content="Button" Margin="5" Width="497" Grid.ColumnSpan="2" Height="28" Grid.Row="3" Click="Button_Click"/>
    </Grid>
</Window>

    因为代码中有许多对Attribute的属性,所以结构看起来并不是那么清晰。如果我们把对Attribute的赋值都去掉,那么上面的代码就显现了它的树形框架结构。

<Window>  
    <Grid>         
        <TextBox />  
        <TextBox />  
        <TextBox />  
        <TextBox />  
        <Button />   
    </Grid>  
</Window>

    如果用一张图来表示上面的那段代码,它会是下面这个样子 



    以<Window>对象为根节点,一层一层向下包含。这种树形结构对于WPF整个体系都具有非常重要的意义,它不但影响着UI的布局设计,还深刻的影响着WPF的属性(Property)子系统和事件(Event)子系统等方方面面。在实际的编程过程中,我们经常要在这棵树上进行按名称查找元素,获取父/子节点等操作,为了方便操作这棵树,WPF基本类库为程序员准备了VisualTreeHelperLogicTreeHelper两个助手类(Helper Class),同时还在一些重要的基类里封装了一些专门用于操作这棵树的方法。


【XAML中为对象赋值的方法】


    XAML是一种声明性语言,XAML会为每一个标签创建一个与之对于的对象,对象创建之后要对它的属性进行必要的初始化之后才有使用意义。因为XAML语言不能够编写程序的运行逻辑,所以一份XAML文档除了使用标签声明对象就是初始化对象属性了。

注意:
XAML中对对象赋值总共有两种方法:
A:使用字符串进行简单赋值。
B:使用属性元素(Property Element)进行复杂赋值。


【使用标签的Attribute为对象属性赋值】


    前面我们已经知道,一个标签的Attribute有一部分与对象的Property对应,<Rectangle>标签里面的Fill这个Attribute就是这样,他与Rectangle类对象的Fill属性对应,在MSDN文档库里可以查询到,Retangle类的Fill类型是一个Brush。Brush是一个抽象类,凡是已Brush为基类的类都可以成为Fill的属性值。Brush的派生类有很多:


SolidColorBrush:       单色画刷。
LinearGradientBrush:线性渐变画刷。
RadialGradientBrush:径向渐变画刷。
ImageBrush:             位图画刷。
DrawingBrush:          矢量图画刷。
VisualBrush:              可视元素画刷。


    使用字符串对Attribute的简单赋值,假设我们的Rectangle只需要填充成单一的蓝色,那么我们只需要简单的写成:

<Window x:Class="WpfApplication1.wnd321"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="wnd321" Height="343" Width="452">
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <Rectangle x:Name="rectangle" Width="200" Height="150" Fill="Blue"/>
    </Grid>
</Window>



    我们看到,blue这个字符串最终被翻译成了SolidcolorBrush并赋值给了Rectangle对象。换成C#代码是这样。

SolidColorBrush brush = new SolidColorBrush();  
brush.Color = Colors.Blue;  
this.rectangle1.Fill = brush;

    需要注意的是,这种Attribute=Value的赋值时,由于XAML语法有限,Value只能是一个字符串值,这就引发了下面两个问题:
A,如果一个类可以使用XAML类来进行声明,并允许它的的Property可以和它的Attribute互相映射,那就需要为这些Property准备适当的转换机制。


B,由于Value是个字符串,所以其格式复杂程度有限,尽管可以在转换机制里面包含一定的按格式解析字符串的功能以便转换成较复杂的目标对象,但这会让最终的XAML使用者头疼不已,因为他们不得不在一个没有编码辅助的情况下手写一个格式复杂的字符串来满足需求。


    第一个问题的解决方式是使用TypeConverter类的派生类,在派生类里面重新TypeConverter的一些方法,第二个问题的解决办法就是使用属性元素(Property Element)。


【属性元素】


    在XAML中,非空标签均具有自己的内容(Content)。标签的内容就是指夹在起始标签和结束标签中的一些子级标签,每个子级标签都是父级标签中的一个元素(Element),简称为父级标签的一个元素。顾名思义,属性元素指的就是某个标签的一个元素对应这个标签的一个属性,即已元素的形式来表达一个实例的属性。代码描述为:

<ClassName>    
           <ClassName.PropertyName>  
           </ClassName.PropertyName>  
<ClassName>

使用线性渐变来填充这个矩形

<Window x:Class="WpfApplication1.wnd323"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="wnd323" Height="300" Width="400">
    <Grid>
        <Rectangle x:Name="rectangle" Width="200" Height="150">
            <Rectangle.Fill>
                <LinearGradientBrush>
                    <!--渐变的位置颜色-->
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Offset="0.2" Color="LightBlue"/>
                        <GradientStop Offset="0.7" Color="Blue"/>
                        <GradientStop Offset="1"   Color="DarkBlue"/>
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>
</Window>



    一般情况下,对于复杂的绘图和动画创作,应该先在Blend里进行操作,然后回到VS里进行精确的微调,在保证效果的情况下,提高代码的可读性与可维护性。


这里几个简化XAML的技巧:
能用Atrribute=value方式进行赋值的就不要使用属性元素。
充分利用默认值,除去冗余。
充分利用XAML的简写方式:XAML的简写方式很多,需要在工作中慢慢积累。


【标记扩展】


    有时候,一个对象的属性值,依赖在其它对象的某个属性上,此时就需要使用标记扩展了。


    下面的例子是TextBox的Text属性依赖Slider的Value上,这样Slider移动时,TextBox的值会跟着移动。

<Window x:Class="WpfApplication1.wnd324"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="wnd324" Height="276" Width="494">
    <StackPanel Background="LightSlateGray">
        <Slider x:Name ="slider1" Margin="5" ValueChanged="slider1_ValueChanged"/>
        <TextBox x:Name ="txtBox" Height="23" Text="{Binding ElementName=slider1, Path=Value, Mode=OneWay}" Margin="5"/>
    </StackPanel>
</Window>



注意只有MarkupExtension类的派生类才能使用标记扩展语法创建对象。


【引用命名空间】


格式规范

xmlns:映射名="clr-namespace:类库中名称空间的名字;assembly=类库文件名"


如:   xmlns:controls="clr-namespace:Controls;assembly=MyLibrary"


参考《深入浅出WPF》

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郎涯技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值