一,摘要
首先很高兴这个系列能得到大家的关注和支持,前端时间身体状况不适,所以暂停了更新,对此表示非常抱歉,以后会逐渐加快进度,不过由于这是一个很长的系列,我也想把它写好,所以以后也会慢慢来,在这个系列的过程中也会穿插发一些其他文章,比如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代码,通过Reflector查看
四,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"
然后就可以手动编译成功了。
那么通过Reflector可以查看到它的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发表出来,所以希望大家能够多多指点,这样在使一部分人受益的同时也能纠正我的错误观点,以便和各位共同提高,后续文章敬请关注!
本文所有代码下载:DemoWithXAML.zip
八,系列进度(红色标示已发布)
前篇
· 1. WPF 基础到企业应用系列1——开篇有益
· 2. WPF 基础到企业应用系列2——WPF前世今生
· 3. WPF 基础到企业应用系列3——WPF开发漫谈
· 4. WPF 基础到企业应用系列4——WPF千年轮回
· 5. WPF 基础到企业应用系列5——WPF千年轮回 续前缘
· 6. WPF 基础到企业应用系列6——WPF布局全接触
· 7. WPF 基础到企业应用系列7——深入剖析依赖属性(核心篇)
· 8. WPF 基础到企业应用系列8——依赖属性之“风云再起”
· 9. WPF 基础到企业应用系列9——深入剖析WPF事件机制 (核心篇)
·10. WPF 基础到企业应用系列10——WPF事件机制之“刨根问底”
·11. WPF 基础到企业应用系列11——深入剖析WPF命令机制 (核心篇)
·12. WPF 基础到企业应用系列12——WPF命令之“庖丁解牛”
·13. WPF 基础到企业应用系列13——WPF Binding全接触 (核心篇)
·14. WPF 基础到企业应用系列14——WPF Binding之“面面俱到”
中篇
· 1. 资源、样式、模板
· 2. 尺寸缩放、定位与变换元素
· 3. WPF控件分类介绍与使用技巧
· 4. 用户控件和自定义控件开发
· 5. 多语言、皮肤和主题
· 6. 2D图形
· 7. 3D图形
· 8. 动画(几种动画的应用)
· 9. 音频、视频、语音
· 10. 文档、打印、报表
后篇
· 1. Win32、Windows Form以及ActiveX之间的互用性
· 2. 构建并部署应用程序(ClickOnce部署、微软setup /InstallShield+自动更新组件)
· 3. MVC、MVP、MVVM全解析
· 4. WPF的模式讲解及实例(MVC Demo)
· 5. WPF的模式讲解及实例(MVP Demo)
· 6. WPF的模式讲解及实例(MVVM Demo)
· 7. 性能优化(WPF项目的瓶颈)
· 8.一个完整WPF项目(普通架构版)
· 9. 一个完整WPF项目(MVVM架构版)
· 10. WPF 4.0新功能
分享到:
相关推荐
Windows Presentation Foundation (WPF) 是下一代显示系统,用于生成能带给用户震撼视觉体验的 Windows 客户端应用程序。使用 WPF,您可以创建广泛的独立应用程序以及浏览器承载的应用程序。 WPF 的核心是一个与...
WPF编程进阶书籍,在上一本入门书籍的基础上重点将WPF各个元素控件的使用和高级技巧,需要先学习入门篇。看完了基本可算掌握了WPF基本编程技术。
5. WPF基础之路由事件 33 6. WPF基础之布局系统 46 7. WPF基础之样式设置和模板化 51 8. 详谈WPF开发中的数据虚拟化 64 XAML语法 74 1. XAML语法术语 74 2. 代码隐藏和XAML 82 3. XAML和自定义类 83 4. 标记扩展和...
wpf 揭秘 一共两部分,请下载: wpf 揭秘 wpf揭秘——part1.rar wpf 揭秘 wpf揭秘——part2.rar 然后解压。
1. WPF基础之体系结2. WPF基础之 XAML3. WPF基础之基元素4. WPF基础之属性系统5. WPF基础之路由事件6. WPF基础之布局系7. WPF基础之样式设置和模板化8. 详谈WPF开发中的数据虚拟化1. WPF控件开发之控件概述2. 使用...
wpf编程基础教程,内容覆盖了所有基本知识,是初学者应该看的书。
WPF基础,有资料,和自己做的成功小例子,例子都是能运行的,环境是vs2008
WPF基础入门
葵花宝典 WPF自学手册 源代码VS2010 葵花宝典 WPF自学手册 源代码VS2010
wpf 揭秘 一共两部分,请下载: wpf 揭秘 wpf揭秘——part1.rar wpf 揭秘 wpf揭秘——part2.rar 然后解压。
在公司给手下程序员普及WPF时做的教程,系列教程中包含PPT的演示、Sample的学习、Homework的练习三部分。本人觉得WPF的发展前景正能体现市场的发展方向。希望在中国能尽快普及,忘日后能和更多的WPF高手合作。(WPF...
C# WPF 中嵌入其它应用程序窗口,调用Win32API 将其它应用程序窗口嵌入当前程序内部
在公司给手下程序员普及WPF时做的教程,系列教程中包含PPT的演示、Sample的学习、Homework的练习三部分。本人觉得WPF的发展前景正能体现市场的发展方向。希望在中国能尽快普及,忘日后能和更多的WPF高手合作。(WPF...
学习WPF目录树很好的例子,对初学都很有帮助
在公司给手下程序员普及WPF时做的教程,系列教程中包含PPT的演示、Sample的学习、Homework的练习三部分。本人觉得WPF的发展前景正能体现市场的发展方向。希望在中国能尽快普及,忘日后能和更多的WPF高手合作。(WPF...
WPF 基础视频教程(共50集)---3.只使用代码创建WPF应用程序
WPF编程宝典——使用C# 2012和.NET 4.5(第4版)源码,内含32个程序源码文件。
在公司给手下程序员普及WPF时做的教程,系列教程中包含PPT的演示、Sample的学习、Homework的练习三部分。本人觉得WPF的发展前景正能体现市场的发展方向。希望在中国能尽快普及,忘日后能和更多的WPF高手合作。(WPF...
在公司给手下程序员普及WPF时做的教程,系列教程中包含PPT的演示、Sample的学习、Homework的练习三部分。本人觉得WPF的发展前景正能体现市场的发展方向。希望在中国能尽快普及,忘日后能和更多的WPF高手合作。(WPF...
WPF火焰图像特效——效果实例,适合初学都学习