欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

XAML 界面原理与语法

程序员文章站 2022-06-08 14:57:26
...

XAML(Extensible Application Markup Language),是用于实例化.NET对象的标记语言。XAML是微软技术体系中的UI编程语言。Windows 10 应用程序中的界面是由xaml 文件组成的,和这些xaml文件一一对应起来的是xaml.cs文件,这就是微软典型的Code-Behind模式的编程方式。Xaml文件的语法类似XML和HTML的结合体,这是微软的XAML语言特有的语法结构。

理解XAML

XAML是一种声明性标记语言,它简化了为.NET Framework应用程序创建UI的过程,使程序界面编程更加简单和简洁。XAML直接以程序集中定义的一组特定后备类型表示对象的实例化。XAML文件中的每个元素代表.NET中的一个类,并且XAML文件中的每个属性代表.NET类中的一个属性、方法或事件。后台文件.xaml.cs中部分类包含了XAML呈现层可以用的事件、方法和属性。

编写XAML代码是需要注意,声明一个XAML元素时,可以用Name属性为该元素指定一个名称,这样在C#代码里面才可以访问到此元素。

XAML必须遵循的4大原则:

  1. XAML是大小写区分的,元素和属性的名称必须严格区分大小写。
  2. 所有的属性值,无论它是什么数据类型,都必须包含在双引号中;
  3. 所有的元素都必须是封闭的;如<Button …/> <Button>…</Button>
  4. 最终的XAML文件也必须是合适的XML文档。

XAML语法

1.命名空间

XAML里面的元素对应着.NET里面的类,但是只提供类名是不够的,XAML解析器还需要知道这个类位于哪个.NET名称空间,这样解析器才能够正确的识别XAML的元素。

xmlns特性是XML中的一个特殊特性,它专门用来声明命名空间。一旦声明一个命名空间,在文档中的任何地方都可以使用该命名空间。

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

是Windows 10 的核心命名空间。包含了大部分用来构建用户界面的控件类。该名称空间的声明没有使用命名空间前缀,所以他成为整个文档的默认命名空间。所以没有前缀的元素都是自动位于这个命名空间下。

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

它包含了XAML的实用特性。该名称空间被映射为前缀为x。

 

XML命名空间的名称和任何特定的.NET名称空间都不匹配。这种设计的原因有以下两个。

第一个原因:XML命名空间通常是URI。这些URI开起来像是在指定Web上的位置,但实际不是。通过使用URI格式的命名空间,不同的XML文档格式就会互相区分开来,作为唯一的标识符,表示这是创建在某个特定环境下的XML文档。

第二个原因:XAML中使用的XML命名空间和.NET命名空间不是一一对应的,如果一一对应的花,会显著增加XAML文档的复杂程度。XAML将这些.NET命名空间组合到单个XML命名空间中。

2.对象元素

XAML的对象元素是指XAML中的一个完整的节点,一个XAML文件始终只有一个根元素,在Windows 10 里面通常是Page作为根元素,其他都是子元素。子元素可以包含一个或多个子元素。

对象元素语法是一种XAML标记语法,它通过声明XML元素将Windows 10 的类或结构实例化。对象元素以左尖括号(<)开始,后面紧跟要实例化的类或结构的类型名称。类型名称后面可以有零个或多个空格,对于对象元素还可以声明零个或多个特性,并用一个或多个空格来分隔每个"特型名=值"这样的属性对。

3.设置属性

XAML中的属性也可以使用多种语法设置,不同的属性类型也会有不同的设置方式,并不是全部的属性设置都是通用的,总的来说可以通过下面的4种方式来设置对象元素的属性:

1.使用属性语法;

<objectName propertyName = "propertyValue" … />

2.使用属性元素语法;

<Object>

          <Object.property>

          PropertyValueAsObjectElement

          </Object.property>

</Object>

3.使用内容元素语法;

4.使用集合语法(通常是隐式集合语法)。

 

并不是所有属性都适用取决于属性对象的特性。

4.附加属性

附加属性是一种特定类型的属性,和普通属性的作用并不一样。这种属性的特殊之处在于,其属性值受到XAML中专用属性系统的跟踪和影响。附加属性可用于多个控件,但却在另一个类中定义。常用于控件布局。

5.标记扩展

标记扩展是一个被广泛使用的XAML语言概念。通过XAML标记扩展来设定属性值。从而可以让对象元素的属性具备更加灵活和复杂的赋值逻辑。常用的有以下五种:

  1. Binding(绑定)标记扩展,实现在XAML载入时,将数据绑定到XAML对象;
  2. StaticResource(静态资源)标记扩展,实现引用数据字典(ResourceDictionary)中定义的静态资源。
  3. ThemeResource(主题资源)标记扩展,表示系统内置的静态资源。
  4. TemplateBinding(模板绑定)标记扩展,是现在XAML页面中,对象模板板顶调用。
  5. RelativeSource(绑定关联源)标记扩展,实现对特定数据源的绑定。

在语法上,XAML使用大括号{}来表示扩展。例如:

<TextBlock Text = "{Binding Source = {StaticResource myDataSource}, Path = PersonName}"/>

这里有两处使用了XAML扩展,一处是Banding,另一处是StaticResource,这种用法称为嵌套扩展,TextBlock元素的Text属性的值为{}中的结果。当XAML编译器看到大括号{}时,把大括号中的内容解释为XAML标记扩展。

XAML本身也定义了一些内置的标记扩展,这类扩展包括:

x:Type:在XAML中取对象的类型,相当于C#中的typeof操作,这种操作发生在编译的时候。

x:Static:是用来把某个对象中的属性或域的值赋给目标对象的相关属性。

x:null:是一种最简单的扩展,自作用就是把目标的属性设置为null。

x:Array:表示一个.NET数组。x:Array元素的子元素都是数组元素,它必须与x:Type一起使用,用于定义数组类型。

6.事件

大多数Windows 10 应用都是由标记和后台代码组成,在一个项目中,XAML作为.xaml文件来编写,然后用C#语言来编写后台代码文件。当XAML文件被编译时,通过XAML页面的根元素的x:Class属性指定的命名空间和类来表示每个XAML页对应的后台代码的位置。事件是XAML中常用的语法。

事件在XAML中的基础语法如下:

<元素对象 事件名称 = "事件处理"/>

XAML原理

1.XAML页面的编译

通过Visual Studio完成XAML页面的编译,在程序运行时会通过直接链接操作加载和解析XAML,将XAML和过程代码自动连接起来。用户不需要将XAML文件和过程代码融合,只需要将它添加到项目中,通过Build动作完成编译。

通常把与XAML文件关联的XAML.CS文件称为代码隐藏文件。如果在XAML添加任何一个时间处理程序,在XAML.CS上就会生成时间的处理代码。在类定义中有一个 partial 关键字,这个关键字很重要 ,因为类的实现是分布在多个文件中的。因为在项目里面看到 MainPage.xaml.cs 文件定义了MainPage类,其实在另一个地方也定义了,只是在项目工程里面隐藏了。当编译完  Windows 10 项目时,会在项目的obj\Debug文件夹下看到Visual Studio 创建的以g.cs为扩展名的文件,对于每一个XAML文件,可以找到一个对应的g.cs文件。

从.g.cs文件中可以看到MainPage类还定义了一些控件和相关的方法,并且InitializeComponent()方法里面加载和解析了MainPage.xaml文件。在xaml页面中声明的控件,通常会在.g.cs中生成相应的控件的内部不字段。取决于控件是否有x:Name属性。

在项目的obj\Debug文件夹下,还有g.i.cs为扩展名的文件,这些文件并不是在编译的时候生成的,而是当创建了XAML文件的时候就马上生成,或者修改了XAML文件g.i.cs文件也会跟着改变,而g.cs文件则是必须要成功变了项目之后才会生成的。

g表示generated产生的意思

i表示intellisense智能感知的意思

2.动态加载XAML

动态加载XAML是指在程序运行时通过解析XAML格式的字符创或者文件在动态生成UI的效果。

在应用程序里面动态加载XAML需要使用到XamlReader.Load方法来实现,XamlReader类是为分析XAML和创建相应的windows 10 对象树提供XAML处理器引擎,XamlReader.Load方法可以分析格式良好的XAML片段并创建相应的Windows 10 对相树,然后返回该对象树的根。大部分可以在XAML页面中编写代码,都可以通过动态加载XAML的形式来实现,不仅仅是普通的UI控件,动画等其他的XAML代码一样可以动态加载。

动态加载XAML对XAML的字符串有一定的要求:

  1. XAML内容字符串必须定义当个根元素,使用XamlReader.Load创建的内容只能赋予一个 Windows 10 对象,它们是一对一的关系。
  2. 内容字符串XAML必须是格式良好的XML,并且必须是可分析的XAML。
  3. 所需的根元素还需要指定某一默认的XML命名空间值。这通常是命名空间

xmls=“http://schemas.microsoft.com/winfx/2006/xaml/presentation”

例:

MainPage.xaml

<StackPanel x:Name="sp_show">
          <Button x:Name="bt_addXAML" Content="加载xaml按钮" Click="bt_addXAML_Click">
          </Button>
</StackPanel>

MainPage.xaml.cs

        private void bt_addXAML_Click(object sender, RoutedEventArgs e)
        {
            string buttonXAML = "<Button xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'" +
                " Content = \"加载XAML文件\" Foreground=\"Red\" ></Button>";
            Button btnRed = (Button)XamlReader.Load(buttonXAML);
            btnRed.Click += btnRed_Click;
            sp_show.Children.Add(btnRed);
        }
        async void btnRed_Click(object sender, RoutedEventArgs e)
        {
            string xaml = string.Empty;
            StorageFile fileRead = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync("Rectangle.xaml");
            xaml = await FileIO.ReadTextAsync(fileRead);

            Rectangle rectangle = (Rectangle)XamlReader.Load(xaml);
            sp_show.Children.Add(rectangle);
        }

Rectangle.xaml 修改属性为Content

<Rectangle 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            Height="100" Width="200">
    <Rectangle.Fill>
        <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="Black" Offset="0" />
            <GradientStop Color="Red" Offset="0.5" />
            <GradientStop Color="Black" Offset="1" />
        </LinearGradientBrush>
    </Rectangle.Fill>
</Rectangle>

XAML树结构

XAML是界面编程语言,用来呈现用户界面,它具有层次化的特性,它的元素的组成就是一种树的结构类型。XAML编程元素之间通常以某种形式的“树”关系存在,它XAML中创建的应用程序UI可以抽象一个对象树,也称元素树,可以进一步将对象树分为两个离散但有时会并行的树:逻辑树和可视化树。

逻辑树:是根据父控件和子控件来构造而成的,在路由事件中将会按照这样的一种层次结构来触发。

可视化树是XAML中可视化空间极其子控件组成的一个树形的控件元素结构图。

1.可视化树

可视化树中包含应用程序的用户界面所使用的所有可视化元素,并通过了树形的数据按照父子元素的规则来把这些可视化元素排列起来。可视化树概念指的是较大的对象树经过编辑或筛选后的表示形式。所应用的筛选器是在可视化树中只存在具有呈现含义的对象。

通过可视化树,可以确定Windows 10 可视化对象和绘图对象的呈现顺序。从顶层元素根开始遍历,然后按照从左到右的顺序遍历。先遍历子级,后遍历同级。

2.VisualTreeHelper类

可视化树针对XAML的现实操作实在应用程序内部使用。编写或替换控制模板或在运行时分析控件的结构或部分。

VisualTreeHelper类常用的静态方法

FindElementsInHostCoordinates

GetChild

GetChildrenCount

GetParent

遍历可视化树

        <StackPanel x:Name="stackPanel">
            <TextBlock>我的应用程序</TextBlock>
            <TextBlock>xxx</TextBlock>
            <Rectangle Height="20" StrokeThickness="2" Stroke="Black" ></Rectangle>
            <TextBlock></TextBlock>
            <Button Content="遍历"  Click="Button_Click"></Button>
        </StackPanel>

     

        string visualTreeStr = string.Empty
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            visualTreeStr = "";
            GetChildType(stackPanel);
            MessageDialog messageDialog = new MessageDialog(visualTreeStr);
            await messageDialog.ShowAsync();

        }
        public void GetChildType(DependencyObject reference)
        {
            int count = Windows.UI.Xaml.Media.VisualTreeHelper.GetChildrenCount(reference);
            if(count > 0)
            {
                for (int i = 0; i  <= Windows.UI.Xaml.Media.VisualTreeHelper.GetChildrenCount(reference) - 1; i++)
                {
                    var child = Windows.UI.Xaml.Media.VisualTreeHelper.GetChild(reference, i);
                    visualTreeStr += child.GetType().ToString() + " " + count + " ";
                    GetChildType(child);
                }
            }

        }

框架和页面

Windows 10 的应用程序里面包含一个框架多个页面,框架相当于是应用程序的最外层的一个容器,然后这个容器里面包含了很多个页面。这些页面都是存在于导航堆栈上。

Windows 10 应用程序平台提供了框架和页面类,框架类为Frame,页面类为Page。Windows 10 应用程序的框架是一个*容器控件,该控件可托管Page,page页面有包含应用程序中不同部分的内容,也就是程序界面UI的内容。在Windows 10 里面可以创建任何数目的页面。

在App.xaml.cs页面包含下面的代码:

Frame rootFrame = Window.Current.Content as Frame;

Windows 类的单利对象的Content属性就是当前Windows 10 应用程序最顶层的元素,应用程序的主框架,一个Windows 10 应用程序只有一个主框架,Window.Current.Content属性的值是与应用关联的Frame,每个应用都有一个Frame。当用户导航到该页面时,导航框架会将应用的每个页面或Page的实例设置为框架的Content。

this.Frame.Navigate(typeof(BlankPage1));