【WPF学习】第四章 加载和编译XAML

  前面已经介绍过,尽管XAML和WPF这两种技术具有相互补充的作用,但他们也是相互独立的。因此,完全可以创建不使用XAML和WPF应用程序。

  总之,可使用三种不同的编码方式来创建WPF应用程序:

  • 只使用代码。这是在Visual Studio中为Windows窗体应用程序使用的传统方法。它通过代码语句生成用户界面。
  • 使用代码和未经编译的标记(XAML)。这种具体方式对于某些特殊情况是很有意义的,例如创建高度动态化的用户界面。这种方式在运行时使用System.Windows.Markup名称空间中的XamlReader类,从XAML文件中加载部分用户界面。
  • 使用代码和编译过的标记(BAML)。对于WPF而言这是一种更好的方式,也是Visual Studio支持的一种方式。这种方式为每个窗口创建了一个XAML模板,这个XAML模板被编译为BAML,并嵌入到最终的程序集中。编译过的BAML在运行时被提取出来,用于重新生成用户界面。

一、只使用代码

  对于编写WPF应用程序,只使用代码进行开发而不适用任何XAML的做法并不常见(但是仍然完全支持)。只使用代码进行开发的明显缺点在于,可能会使编写WPF应用程序成为极端乏味的工作。WPF控件没有包含参数化的构造函数,因此即使为窗口添加一个简单按钮也需要编写几行代码。

  只使用代码进行开发的一个潜在的有点是可以随意定制应用程序。例如,可根据数据库记录中的信息生成充满输入控件的窗体,或可根据当前的用户酌情添加或替换控件。需要的所有内容只不过是少量的条件逻辑。相比之下,如果使用XAML文档,它们只能作为固定不变的资源嵌入到程序集中。

  下面代码用于生成一个普通窗体,该窗体包含一个按钮和一个时间处理程序。在创建窗口时,构造函数调用InitializeComponent()方法,该方法实例化并配置这个按钮和窗体,并连接(hook up)事件处理程序.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace WPFCompileByCode
{
    public class Window1:Window
    {
        private Button button1;
        public Window1()
        {
            InitializeComponent();
        }
        private void InitializeComponent()
        {
            this.Width = 300;
            this.Height = 300;
            this.Left = 100;
            this.Top = 100;
            this.Title = "Code Only Window";

            DockPanel panel = new DockPanel();
            button1 = new Button();
            button1.Content = "Click Me";
            button1.Margin = new Thickness(30);
            button1.Click += button1_Click;
            IAddChild container = panel;
            container.AddChild(button1);

            container = this;
            container.AddChild(panel);
        }

        void button1_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Click Me");
        }
    }
}

  从概念上讲,本例中的Windows1类更像传统的Windows窗体硬功程序中的窗体。它继承自Window基类,并为每个控件添加一个私有程序变量。为了清晰起见,该类在专门的InitializeComponent()方法中执行初始化操作。

  为启动该应用程序,可在Main()方法中添加如下代码:

public class Program:Application
    {
        [STAThread]
        public static void Main()
        {
            Program app = new Program();
            app.MainWindow = new Window1();
            app.MainWindow.ShowDialog();
        }
    }

  运行效果图如下所示:

 二、使用代码和未编译的XAML

  使用XAML最有趣的方式之一是使用XamlReader类随时解析它。例如,假设创建一个Window1.xaml的文件,且内容如下所示:

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <Button Name="button1" Margin="30">Click Me</Button>
</DockPanel>

   编写一个类,用来加载xaml文件。如下代码所示:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace WPFCompileByXaml
{
    public class Window1:Window
    {
        private Button button1;
        public Window1(string xamlFile)
        {
            this.Width = 300;
            this.Height = 300;
            this.Left = 100;
            this.Top = 100;

            DependencyObject rootElement;
            using (FileStream fs = new FileStream(xamlFile, FileMode.Open))
            {
                rootElement = (DependencyObject)XamlReader.Load(fs);
            }

            this.Content = rootElement;

            button1 = (Button)LogicalTreeHelper.FindLogicalNode(rootElement, "button1");

            /*
            FrameworkElement frameworkElement = (FrameworkElement)rootElement;
            button1 = (Button)frameworkElement.FindName("button1");
             */

            button1.Click += button1_Click;
        }

        void button1_Click(object sender, RoutedEventArgs e)
        {
            //MessageBox.Show("Hello ,you click me!");
            button1.Content = "Thank you!";
        }
    }
}

  在此,构造函数接收XAML文件名作为参数。然后构造函数打开一个FileStream对象,并使用XamlReader.Load()方法将这个文件中的内容转换为DependencyObject对象,DependencyObject是所有WPF控件继承的基类。DependencyObject对象可放在任意类型的容器中,但在这个示例中它被用作整个窗体的内容。

  为操作元素——如Windows1.xaml文件中的按钮,需要在动态加载的内容中查找相应的控件对象。LogicalTreeHelper类可达到该目的,因为它具有查找一颗完整控件对象的能力,它可以查找所需的许多层,直到找到具有指定名称的对象。然后将一个事件处理程序关联到Button.Click事件。

  另外一种方法是使用FrameworkElement.FindName()方法,在这个示例中,根元素是DockPanel对象,与WPF窗口中的所有控件一样,DockPanel类继承自FrameworkElment类,这意味着可使用如下等效的方法:

FrameworkElement frameworkElement = (FrameworkElement)rootElement;
button1 = (Button)frameworkElement.FindName("button1");

代替下面的代码:

button1 = (Button)LogicalTreeHelper.FindLogicalNode(rootElement, "button1");

  在这个示例中,Window1.xaml文件和可执行的应用程序位于同一文件夹中,并一同发布。然而,尽管该文件没有被编译为应用程序的一部分,但仍可以将其添加到Visual Studio项目中。这样可以更方便地管理文件,并使用Visual Studio设计用户界面(假定使用.xaml文件扩展名,从而使用Visual Studio能够识别出该文档是XAML文档)。

  如果使用这种情况,确保松散的XAML文件不会像传统的XAML文件那样被编译或嵌入到项目中。将文件添加到项目后,在解决方案中选中该文件,然后使用属性窗口,将Build Action设置为None,并将Copy to Output Directory 设置为Copy Always。

  显然,先将XAML编译为BAML,再在运行时加载BAML,比动态加载XAML的效率高,当用户界面比较复杂时尤其如此。然而,这种编码模式为构建动态的用户界面提供了多种可能。例如,可创建通用的检测应用程序,从Web服务中读取窗体文件,然后显示相应的检测控件(标签、文本框和复选框等)。窗体文件可以是具有WPF标签的普通XML文件,使用XamlReader类将该文档加载到一个已经存在的窗体中。检测之后,为了收集结果,只需要枚举所有输入控件并提取他们的内容即可。

三、使用代码和编译过的XAML

  当编译WPF应用程序时,Visual Studio使用分为两个阶段的编译处理过程。第一阶段将XAML文件编译为BAML。例如,如果项目中包含名为Window1.xaml的文件,编译器将创建名为Window1.baml的临时文件,并将该文件放在项目文件夹的obj/Debug字文件夹中。同时,使用选择的语言为窗口创建部分类。例如,如果使用C#语言,编译器将在obj/Debug文件夹中创建名为Window1.g.cs的文件。g代表生产的(generated)。

  部分类包括如下三部分内容:

  • 窗口中所有控件的字段。
  • 从程序集中加载BAML的代码,由此创建对象树。当构造函数调用InitializeComponent()方法时将发生这种情况。
  • 将恰当的控件对象指定给各个字段以及连接所有事件处理程序的代码。该过程是在名为Connect()的方法中完成,BAML解析器在每次发现一个已经命名的对象时调用该方法一次。

  部分类不包含实例化和初始化控件的代码,因为这项任务由WPF引擎在使用Application.LoadComponent()方法处理BAML时执行。

  具体实例,可以查看Visual Studio编译后的WPF应用程序。

原文地址:https://www.cnblogs.com/Peter-Luo/p/12150734.html

时间: 2024-10-10 09:36:06

【WPF学习】第四章 加载和编译XAML的相关文章

加载和编译Xaml(宝典2)

三个方式来实现wpf的应用程序 1/只使用代码 好处:就是随意的定制应用程序,相比之下xaml文档,它们只能作为固定的不变的资源嵌入到程序集中 坏处:因为wpf控件包含没有参数的构造函数,所以一个简单的控件就可写很多代码 demo: 新建一个普通类(不是窗口类) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; us

Activity四种加载模式

android activity四种加载模式,有 >>>standard: 标准模式,这是默认的加载方式 >>>singleTop : task顶单例模式 >>>singleTask : Task内单列模式 >>>singleInstance :全局单列模式 <1>standard: 标准模式,这是默认的加载方式 public class StandardTest extends Activity { @Override

RX系列四 | RxAndroid | 加载图片 | 提交表单

RX系列四 | RxAndroid | 加载图片 | 提交表单 说实话,学RxJava就是为了我们在Android中运用的更加顺手一点,也就是RxAndroid,我们还是先一步步来,学会怎么去用的比较好,之前的三篇算是铺垫,让你有一点认识,那Rx在Android中有什么好处呢?我们先模拟一些原始功能和他对比下 一.加载图片 很多人说Rx出来之后,是编程思想的一种进阶,实际上我学习了这种思想之后,确实是觉得有了很大的改变,不过,需要一点学习成本再加上,需要对原先的思想有些改观,使得我依旧有点不适应

《Entity Framework 6 Recipes》中文翻译系列 (22) -----第五章 加载实体和导航属性之延迟加载

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第五章 加载实体和导航属性 实体框架提供了非常棒的建模环境,它允许开发人员可视化地使用映射到数据库中的表.视图.存储过程以及关系中的实体类型.本节将向你展示如何控制查询操作中的关联实体的加载. 实体框架的默认行为是只加载应用程序直接需要的实体.通常情况下,这正是你需要的.如果实体框架通过一个或多个关联积极地加载关联实体,最终,你很有可能得到超过你需求的实体.这不但增加了内存占用,而且还影响了

thinkphp学习笔记9—自动加载

1.命名空间自动加载 在3.2版本中不需要手动加载类库文件,可以很方便的完成自动加载. 系统可以根据类的命名空间自动定位到类库文件,例如定义了一个类Org\Util\Auth类: namespace Org\Util; class Auth { } 保存到ThinkPHP/Library/Org/Util/Auth.class.php 这样我们就可以直接实例化了, new \Org\Util\Auth(); 实例化之后系统会自动加载 ThinkPHP/Library/Org/Util/Auth.

四种加载React数据的技术对比(Meteor 转)

1.四种加载React数据的技术对比(Meteor 转) : https://sanwen8.cn/p/31e4kdE.html 2. Meteor + Appolo   TelescopeJS/Telescope    https://github.com/TelescopeJS/Telescope/tree/devel http://nova-docs.telescopeapp.org/architecture.html

ios网络学习------4 UIWebView的加载本地数据的三种方式

UIWebView是IOS内置的浏览器,可以浏览网页,打开文档  html/htm  pdf   docx  txt等格式的文件.  safari浏览器就是通过UIWebView做的. 服务器将MIME的标识符等放入传送的数据中告诉浏览器使用那种插件读取相关文件. uiwebview加载各种本地文件(通过loadData方法): - (void)viewDidLoad { [super viewDidLoad]; [self setupUI]; NSString *path = [[NSBund

activity的四种加载模式介绍

  四种加载模式的介绍: a) Standard : 系统默认模式,一次跳转即会生成一个新的实例:    b) SingleTop : 和 standard 类似,唯一的区别就是当跳转的对象是位于栈顶的activity时,程序将不会生成一个新的activity实例,而是直接跳到现在存于栈顶的那个activity实例:    c) SingleTask: singleTask 模式和后面的singleInstance 模式都只是创建一个实例:该模式下,无论调转的对象是不是位于栈顶的activity

singleTop和singleTask有什么区别?(活动 Activity 四种加载模式)

singleTop要求如果创建intent的时候栈顶已经有要创建的Activity的实例,则将intent发送给该实例,而不发送给新的实例.(注意是栈顶,不在栈顶照样创建新实例!) singleTask模式:当intent到来,需要创建singleTask模式Activity的时候,系统会检查栈里面是否已经有该Activity的实例.如果有直接将intent发送给它. Activity的四种加载模式: 1.standard :系统的默认模式,一次跳转即会生成一个新的实例.假设有一个activit