WPF 基础到企业应用系列5——WPF千年轮回 续前缘
一。摘要
首先非常高兴这个系列能得到大家的关注和支持,前端时间身体状况不适,所以暂停了更新,对此表示非常抱歉,以后会逐渐加快进度。只是因为这是一个非常长的系列,我也想把它写好,所以以后也会慢慢来,在这个系列的过程中也会穿插发一些其它文章,比方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 開始编译,
这样你就更能看清楚编译器背后的秘密,同一时候也能跟踪每一步运行的操作,同一时候对一些简单的内存泄露问题也比較easy察觉到。
当然如今也有非常多工具能够跟踪这些问题,我这里仅仅是写一种思路。大家能够依据自己的爱好取舍。
六,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
WPF 基础到企业应用系列5——WPF千年轮回 续前缘的更多相关文章
- WPF 基础到企业应用系列2——WPF前世今生
1.开篇前言 非常多时候了解一项新技术的历史和趋势往往比这项技术的本身价值还要重要.WPF作为一项新技术(已经三年多了.或者应该叫老技术了).我们都有必要了解它的来龙去脉,尤其是公司的CT ...
- WPF基础到企业应用系列6——布局全接触
本文转自:http://knightswarrior.blog.51cto.com/1792698/365351 一. 摘要 首先很高兴这个系列能得到大家的关注和支持,这段时间一直在研究Windows ...
- WPF 基础到企业应用系列索引
转自:http://www.cnblogs.com/zenghongliang/archive/2010/07/09/1774141.html WPF 基础到企业应用系列索引 WPF 基础到企业应用系 ...
- WPF 基础到企业应用系列1——开篇故意
參考资料 提到參考资料,大家第一感觉就是MSDN,当然我也不例外.这个站点基本上是学习微软技术的首选站点,除了这个站点以外,我还參考了非常多其它的社区和站点,基本上都在.NET 技术社区之我见(英文篇 ...
- WPF基础到企业应用系列7——深入剖析依赖属性(WPF/Silverlight核心)
一. 摘要 首先圣殿骑士非常高兴这个系列能得到大家的关注和支持.这个系列从七月份開始到如今才第七篇,上一篇公布是在8月2日,掐指一算有二十多天没有继续更新了,最主要原因一来是想把它写好,二来是由于近期 ...
- C# WPF基础巩固
时间如流水,只能流去不流回. 学历代表你的过去,能力代表你的现在,学习能力代表你的将来. 学无止境,精益求精. 一.写作目的 做C# WPF开发,无论是工作中即将使用,还是只应付跳槽面试,开发基础是非 ...
- WPF 基础面试题及答案(一)
一 · WPF由哪两部分组成? wpf 由两个主要部分 组成:引擎和编程框架. 1 引擎.wpf引擎是基于窗体的应用程序 图形 视频 音频和文档提供了一个单一的运行时库.重要的是WPF基于矢量的呈现引 ...
- WPF笔记(1.1 WPF基础)——Hello,WPF!
原文:WPF笔记(1.1 WPF基础)--Hello,WPF! Example 1-1. Minimal C# WPF application// MyApp.csusing System;using ...
- 浏览器扩展系列————在WPF中定制WebBrowser快捷菜单
原文:浏览器扩展系列----在WPF中定制WebBrowser快捷菜单 关于如何定制菜单可以参考codeproject上的这篇文章:http://www.codeproject.com/KB/book ...
随机推荐
- Spring4.0实战 rest相关
package com.paic.pay.merchant.web; import com.paic.pay.merchant.entity.MerchantUser; import com.paic ...
- Log4j官方文档翻译(六、日志的级别)
org.apache.log4j.Level 类提供了下面几种日志级别,你也可以通过继承这些类,自定义级别 ALL 所有日志级别都包括 DEBUG 指定信息事件的粒度是DEBUG,在调试应用的时候会有 ...
- 个人环境搭建——搭建jenkins持续构建集成环境
---恢复内容开始--- 搭建jenkins持续构建集成环境 要搭建jenkins持续构建集成环境,首先要安装tomcat和JDK: 第一部分,基本说明: 敏捷(Agile) 在软件工程领域 ...
- bzoj 4131: 并行博弈 (parallel)
bzoj 4131: 并行博弈 (parallel) Description lyp和ld在一个n*m的棋盘上玩翻转棋,游戏棋盘坐标假设为(x, y),1 ≤ x ≤ n,1 ≤ y ≤ m,这个游戏 ...
- 安装最新版本的cocoapods
因为公司的iOS项目使用了cocoapods来管理第三方库,所以要求所有组员的cocoapods版本一致.一般的就是执行: $ sudo gem install -n /usr/local/bin c ...
- 集成 Union Pay - 银联支付--ios
请看这个网址,谢谢谢 http://www.cnblogs.com/oc-bowen/p/6000389.html
- 序列统计(bzoj 4403)
Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案对10^6+3取模的结果. Input 输入第一行包含一个整数T,表示数据组 ...
- lightgbm 学习资料汇总
操作实例:https://blog.csdn.net/luoyexuge/article/details/72956491 中文文档:https://lightgbm.apachecn.org/cn/ ...
- 【字符集及字符编码】UTF-8、UTF-16和UTF-32
UTF-32 用 4 个字节存储每一个字符,以保证能把 UCS 完全表达出来.但实际上 UCS 的字符数量根本不需要用 32 位表示,UTF-32 极大地浪费了空间.另外,由于组合字符的存在,定长表示 ...
- 通过命令编译的项目 导入 到eclipse
通过命令编译的项目 导入 到eclipse后,需要 1.设置 sdk和ndk 的路径 2.设置 AndroidManifest.xml 中的版本为当前版本:<uses-sdk android:m ...