一,摘要

  首先很高兴这个系列能得到大家的关注和支持,前端时间身体状况不适,所以暂停了更新,对此表示非常抱歉,以后会逐渐加快进度,不过由于这是一个很长的系列,我也想把它写好,所以以后也会慢慢来,在这个系列的过程中也会穿插发一些其他文章,比如Windows Azure、设计模式、WCF、Silverlight等,同时也会发一些自己的技术随感和心得,反正只要自己写得开心且对大家有帮助就行。由于自己才疏学浅且是对这些技术的使用总结和心得体会,错误之处在所难免,怀着技术交流的心态,在这里发表出来,所以希望大家能够多多指点,这样在使一部分人受益的同时也能纠正我的错误观点,以便和各位共同提高。

  这篇课程主要是对上几次课程的回顾和简单深化,所以没有讲什么比较新的概念,不过掌握好了这篇,对后面的很多文章都有帮助,同时这一篇文章做Demo、构思、研究等也花费了不少时间,所以希望对大家有所帮助。

二,本文提纲

· 1.摘要

· 2.本文提纲

· 3.前篇回顾

· 4.Xaml基础

· 5.脱离VS工具CSC编译WPF

· 6.XamlReader与XamlWriter

· 7.本文总结

. 8.系列进度

三,前篇回顾

  在我们日常的开发中,软件企业的开发人员一般会有两种类型的工作:

    1,一类是用户界面设计人员,他们关心的是软件和用户之间的交互,就是如何让用户体验更好;

    2,另一类是软件开发人员,他们关心的是软件的架构设计、业务逻辑的处理和软件功能的实现;

  在BS中,用户界面设计人员使用HTML及其工具来设计界面,开发人员使用Java,C#,VB或其他语言来实现其中的逻辑,HTML网页可以用到最终的产品中。

  在CS中,过去我们一直没有分开这两种不同性质的工作。用户界面设计人员通常和开发人员使用不同的工具,当界面设计人员设计好用户界面时,他们的工作并没有用到最终的产品中,而只是用来展现某种概念或工作流程。

  XAML实现了互联网应用程序和桌面应用程序的统一,界面设计人员可以使用XAML或基于XAML的工具(如微软的Design和 Blend) 来设计CS或BS应用程序的界面。程序开发人员则可以在此基础上使用C#或VB.NET等来开发相应的功能,这样,界面设计人员的工作便自然过渡到最终产品中。

  在XAML中,用户界面用XML的元素或属性来表示。WPF引擎把XAML描述的UI元素解释为相应的.NET对象,从而在桌面程序或Silverlight网页上创建相应的控件。如下图所示:

  上面这副就是传统的WinForm开发模式,这两种人没有分离开来,所以在很多企业里就形成了开发人员既要做UI也要做程序的境地。

  上图就是现在的WPF和Silverlight程序的开发模式,这两类人可以分开来工作,他们都可以对Window1.xaml进行修改和加载,所以这样就使分工更专业了,由于大家专注于某一个方面,分工协作的同时,质量和效率也逐渐提高了。

  前几篇介绍了一些基础知识,那么这篇也简单的回顾一下,下面第一幅图是WPF的执行顺序,第二副图是WPF的一个项目的构成,第三幅图是WPF所对应的IL代码(这些图处理得不好,还望各位见谅)。

WPF的执行顺序

WPF的一个项目的构成

WPF所对应的IL代码

四,Xaml基础

  这个部分要讲的东西就太多了,由于这篇文章篇幅有限,同时我觉得用代码诠释能让大家可以更清晰地理解,所以就讲得随意一些,通过一个Demo介绍WPF对资源、类、控件的调用和处理,对Dictionary资源、Application资源、window资源以及控件资源的应用等,如下图所示(本篇所有代码在评论的第一条):

  由于这些概念比较简单,所以我就不花费大的篇幅来讲这些它们,感兴趣或者对这些知识还有不清楚的朋友可以下载这个Demo进行查看或调试,我觉得对初学者很有帮助。

五,脱离VS工具CSC编译WPF

  为了更好的认识WPF的编译和执行过程,我们可以暂时弃用我们熟悉的VS工具,选用记事本写如下的代码:

using System;
using System.Windows;
namespace KnightsWarrior.HelloWorld
{
class HelloWorld
{
[STAThread]
public static void Main()
{
Window win = new Window();
win.Height = 300;
win.Width = 400;
win.Title = "Hello,KnightsWarrior!";
win.Show();

Application app = new Application();
app.Run();
}
}
}

  然后保存到D:\HelloWorld.cs 这个位置,通过CMD或者VS cmomand Line中输入以下编译命令:

csc.exe /out:D:\HelloWorld.exe D:\HelloWorld.cs /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\presentationframework.dll"  /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\windowsbase.dll"  /reference:"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\presentationcore.dll"

  然后就可以手动编译成功了。

  那么通过 可以查看到它的IL代码,如果感兴趣的朋友也可以进行详细的分析。

  如果对MSIL比较熟悉的朋友,也可以用记事本写同样功能的IL代码,由于没有对WPF窗体的IL做具体研究,所以用Console程序代替,等过一段时间再研究WPF控件的IL代码.

.assembly extern mscorlib { auto }
.assembly HelloApp {}
.module HelloApp.exe

.namespace HelloApp
{
.class public Program extends [mscorlib]System.Object
{
.method static private void Main(string[] args)
{
.entrypoint

ldstr "Hello, KnightsWarrior!"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
}
}

  然后打开 Visual Studio Command Prompt,使用 ILASM 开始编译。   这样你就更能看清楚编译器背后的秘密,同时也能跟踪每一步执行的操作,同时对一些简单的内存泄露问题也比较容易察觉到。当然现在也有很多工具可以跟踪这些问题,我这里只是写一种思路,大家可以根据自己的爱好取舍。

六,XamlReader与XamlWriter

  System.Windows.Markup 命名空间中提供了 XamlReader、XamlWriter 两个类型,允许我们手工操控 XAML和BAML 文件。

  XamlReader类除了定义Load的实时加载之外,也定义了异步方法,可以异步解析XAML中的内容。我们可以在XamlReader对象的实例里调用它们。如果在读取一个大文件时要保持用户UI的响应性,就可以使用异步读取的方法。和异步读取方法匹配的还有一个CancelAsync方法,用于停止读取操作。XamlReader 还定义了LoadCompleted事件,在读取完成后会触发该事件,那么我们就可以把读完后要做的事情都在这里进行处理。

  XamlWriter 供一个静态 Save 方法(多次重载),该方法可用于以受限的 XAML 序列化方式,将所提供的运行时对象序列化为 XAML 标记。这句话似乎有点难懂,其实简单的说就是把它序列化为我们需要的类型。

  具体功能代码如下:

  通过XamlReader 动态构建并实例化一个Window。

//XamlReader
StringBuilder strXMAL = new StringBuilder("<Window ");
strXMAL.Append("xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" ");
strXMAL.Append("xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" ");
strXMAL.Append("Title=\"Window2\" Height=\"600\" Width=\"600\">");
strXMAL.Append("</Window>");
var window = (Window)XamlReader.Parse(strXMAL.ToString());
window.ShowDialog();

  同时我们还可以从文件流中读取并操作。

//XamlReader
using (var stream = new FileStream(@"Window2.xaml", FileMode.Open))
{
var window2 = (Window)XamlReader.Load(stream);

var button = (Button)window2.FindName("btnTest");
button.Click += (x, y) => MessageBox.Show("Knights Warrior");

window2.ShowDialog();
}

  Window2.xaml 的代码:

<Window x:Class="XamlReaderWriterDemo.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
<Button Height="23" Name="btnTest" Margin="98,72,105,0" VerticalAlignment="Top">Button</Button>
</Grid>
</Window>

  这里我们需要特别注意的是 XamlReader 载入的 XAML 代码不能包含任何类型(x:Class)以及事件代码(x:Code),也就是说要XAML自身的代码才受支持(这个也在WPF揭秘这本书讲到过)。那么我们可以用 XamlWriter 将一个编译的 BAML 还原成 XAML了,具体代码如下:

//XamlWriter
var xaml = XamlWriter.Save(new Window2());
MessageBox.Show(xaml);

  输出的Message如下(为了效果更好看一些,我粘贴到了VS):

<Window2 Title="Window2" Width="300" Height="300" xmlns="clr-namespace:XamlReaderWriterDemo;assembly=XamlReaderWriterDemo" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<av:Grid>
<av:Button Name="btnTest" Height="23" Margin="98,72,105,0" VerticalAlignment="Top">Button</av:Button>
</av:Grid>
</Window2>

  XAML 的动态载入在使用动态换肤以及运行时加载等场景颇为有用,以后也会慢慢接触。

  由于使用XamlReader和XamlWriter有很多限制,比如我想把一批Baml转化为Xaml,再比如我想指定Baml的路径,然后通过Load的方式载入,那么这些场景就无法通过XamlReader和XamlWriter完成了,这个让我也做过不少的Demo,也跟踪了很长时间的IL代码,在百思不得其解之后和周永恒、Virus等讨论了一下,最后终于找到了一个方案,如下代码所示:

public static class BamlWriter
{
public static void Save(object obj, Stream stream)
{
string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(path);

try
{
string xamlFile = Path.Combine(path, "input.xaml");
string projFile = Path.Combine(path, "project.proj");

using (FileStream fs = File.Create(xamlFile))
{
XamlWriter.Save(obj, fs);
}

Engine engine = new Engine();
engine.BinPath = RuntimeEnvironment.GetRuntimeDirectory();
Project project = engine.CreateNewProject();
BuildPropertyGroup pgroup = project.AddNewPropertyGroup(false);
pgroup.AddNewProperty("AssemblyName", "temp");
pgroup.AddNewProperty("OutputType", "Library");
pgroup.AddNewProperty("IntermediateOutputPath", ".");
pgroup.AddNewProperty("MarkupCompilePass1DependsOn", "ResolveReferences");

BuildItemGroup igroup = project.AddNewItemGroup();
igroup.AddNewItem("Page", "input.xaml");
igroup.AddNewItem("Reference", "WindowsBase");
igroup.AddNewItem("Reference", "PresentationCore");
igroup.AddNewItem("Reference", "PresentationFramework");

project.AddNewImport(@"$(MSBuildBinPath)\Microsoft.CSharp.targets", null);
project.AddNewImport(@"$(MSBuildBinPath)\Microsoft.WinFX.targets", null);
project.FullFileName = projFile;

if (engine.BuildProject(project, "MarkupCompilePass1"))
{
byte[] buffer = new byte[1024];
using (FileStream fs = File.OpenRead(Path.Combine(path, "input.baml")))
{
int read = 0;
while (0 < (read = fs.Read(buffer, 0, buffer.Length)))
{
stream.Write(buffer, 0, read);
}
}
}
else
{
throw new System.Exception("Baml compilation failed.");
}
}
finally
{
Directory.Delete(path, true);
}
}
}

public static class BamlReader
{
public static object Load(Stream stream)
{
ParserContext pc = new ParserContext();
return typeof(XamlReader)
.GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static)
.Invoke(null, new object[] { stream, pc, null, false });
}
}

  上面的代码,大家可以试一下运行效果。或者有更好的方式也请告知。

七,本文总结

  本篇主要对前几次的课程进了一些简单的回顾,同时用一个比较全的Demo介绍了Xaml中引用各种控件和类等,另外对脱离VS工具CSC编译WPF以及XamlReader与XamlWriter 做了比较详细的介绍。下篇我们将进入WPF布局的世界进行漫游,争取和布局控件及应用来一个全接触!

  最后圣殿骑士 会尽心尽力写好这个系列,同时由于是自己对这些技术的使用总结和心得体会,错误之处在所难免,怀着技术交流的心态,在博客园和51CTO发表出来,所以希望大家能够多多指点,这样在使一部分人受益的同时也能纠正我的错误观点,以便和各位共同提高,后续文章敬请关注!

八,系列进度(红色标示已发布)

· 1. WPF 基础到企业应用系列1——开篇有益

· 2. WPF 基础到企业应用系列2——WPF前世今生

· 3. WPF 基础到企业应用系列3——WPF开发漫谈

· 4. WPF 基础到企业应用系列4——WPF千年轮回

· 5. WPF 基础到企业应用系列5——WPF千年轮回 续前缘

· 6. 使用面板做布局(几种布局控件的XAML及CS代码,综合布局等)

· 7. 依赖属性、附加属性(基本、继承、元数据)

· 8. 路由事件、附加事件

· 9. 命令

· 9. WPF控件分类介绍与使用技巧(ContentControl、HeaderedContentControl…… Decorator)

· 10. 尺寸缩放、定位与变换元素

· 11. 资源

· 12. 数据绑定(基本、值转换、验证、集合的筛选、排序、分组、主从、数据提供者)

· 13. 样式

· 14. 模板

· 15. 多语言、皮肤和主题

· 16. 2D图形

· 17. 3D图形

· 18. 动画(几种动画的应用)

· 19. 音频、视频、语音

· 20. 文档、打印、报表

· 21. 用户控件和自定义控件

· 22. Win32、Windows Form以及ActiveX之间的互用性

· 23. 构建并部署应用程序(ClickOnce部署、微软setup /InstallShield+自动更新组件)

· 24. WPF的模式讲解及实例(MVC Demo)

· 25. WPF的模式讲解及实例(MVP Demo)

· 26. WPF的模式讲解及实例(MVVM Demo)

· 27. 性能优化(WPF项目的瓶颈)

· 28.一个完整WPF项目(普通架构版)

· 39. 一个完整WPF项目(MVVM架构版)

· 30. WPF 4.0新功能

一起谈.NET技术,WPF 基础到企业应用系列5——WPF千年轮回2相关推荐

  1. WPF 基础到企业应用系列2——WPF前世今生

    1.开篇前言       很多时候了解一项新技术的历史和趋势往往比这项技术的本身价值还要重要.WPF作为一项新技术(已经三年多了,或者应该叫老技术了),我们都有必要了解它的来龙去脉,尤其是公司的CTO ...

  2. WPF 基础到企业应用系列5——WPF千年轮回 续前缘

    一,摘要 首先很高兴这个系列能得到大家的关注和支持,前端时间身体状况不适,所以暂停了更新,对此表示非常抱歉,以后会逐渐加快进度,不过由于这是一个很长的系列,我也想把它写好,所以以后也会慢慢来,在这个系 ...

  3. WPF基础到企业应用系列8——依赖属性之“风云再起”

    一. 摘要 首先圣殿骑士很高兴"WPF 基础到企业应用系列" 能得到大家的关注.支持和认可.看到很多朋友留言希望加快速度的问题,我会尽力的,对你们的热情关注也表示由衷的感谢.这段时 ...

  4. WPF 基础到企业应用系列1——开篇故意

    參考资料 提到參考资料,大家第一感觉就是MSDN,当然我也不例外.这个站点基本上是学习微软技术的首选站点,除了这个站点以外,我还參考了非常多其它的社区和站点,基本上都在.NET 技术社区之我见(英文篇 ...

  5. WPF基础到企业应用系列7——深入剖析依赖属性(三)

    八. 只读依赖属性 我们以前在对简单属性的封装中,经常会对那些希望暴露给外界只读操作的字段封装成只读属性,同样在WPF中也提供了只读属性的概念,如一些 WPF控件的依赖属性是只读的,它们经常用于报告控 ...

  6. 一起谈.NET技术,.NET并行(多核)编程系列之七 共享数据问题和解决概述

    之前的文章介绍了了并行编程的一些基础的知识,从本篇开始,将会讲述并行编程中实际遇到一些问题,接下来的几篇将会讲述数据共享问题. 本篇的议题如下: 1.数据竞争 2.解决方案提出 3.顺序的执行解决方案 ...

  7. C#-WPF基础入门和进阶系列课程1 运算符封装和案例

    创建控制台项目,主函数中定义创建如下: 任何复杂的业务,都是在此基础上面去增加扩展出来的! 根基基础扎实了,变化的业务输出也才会是水到渠成的事情: 否则您仍然会寸步难行: #region 运算符封装基 ...

  8. WPF基础学习笔记(一)Dependency Object 和 Dependency Property

    .依赖属性是WPF个人觉得对精彩和最有特色的部分.所以特地先拿出来. 首先要实现Dependency Property 则必须要继承Dependency Object.如果看下WPF的基础控件其实都间 ...

  9. WPF基础之几何图形

     之前的总结 01 WPF基础分享之布局 02 WPF基础之路由事件 03 WPF基础之内容控件 04 WPF基础之元素绑定 05 WPF基础之命令 06 WPF基础之资源 07 WPF基础之样式 0 ...

最新文章

  1. Python使用matplotlib可视化时间序列堆叠的面积图、堆叠面积图给出了多个时间序列的贡献程度的可视化表示,以便于相互比较(Stacked Area Chart)
  2. python装饰器类-Python 装饰器、类装饰器、属性装饰器
  3. 实用算法实现-第6篇 线段树
  4. 格式化css文件,css文件格式化脚本的方法
  5. linux查看进程调用接口,查看某个程序都调用哪些api函数
  6. 每天进步一点点《ML - Sklearn库简单学习》
  7. php smarty配置文件,Smarty配置文件
  8. 计算机指令集编程教程,PLC编程语言入门,常用指令集汇总分享
  9. 计算机技术一直在变吗,计算机软考分数线一直是45吗
  10. 计算机mod函数,MOD函数的公式语法及使用方法实例
  11. 《机器人爱好者(第1辑)》——机器人和人工智能
  12. 完美世界:你病了,要么离职,要么996,要么小黑屋三选一
  13. 运营商开始悄悄火拼5G价格战,19元套餐开始涌现
  14. 最火Android开源项目LoopViewPage使用
  15. Acwing 第四章模板及详解(数学知识)
  16. fedora下载工具
  17. Ncut算法(Normalized cuts and image segmentation)
  18. matlab fprintf输出矩阵
  19. DM(达梦)数据库简介
  20. 快速学习-“幽灵”(GHOST)协议

热门文章

  1. 机器学习知识总结系列- 知识图谱(0-0)
  2. 轻松理解牛顿迭代法且用其求平方根
  3. C++ primer第十八章 18.1小结 异常处理
  4. 云数据中心选址PK:微软第一,IBM第二,谷歌最少
  5. 安装OpenCL和AMD驱动程序
  6. 基于SIMD的AVS整数反变换算法设计与优化
  7. Linux ps命令、Linux top命令
  8. Json与List的相互转换
  9. fresco使用中圆角出现了黑边
  10. 结对项目 刘静 201303014059 计科高职13-2