一起谈.NET技术,WPF 基础到企业应用系列5——WPF千年轮回2
一,摘要
首先很高興這個系列能得到大家的關注和支持,前端時間身體狀況不適,所以暫停了更新,對此表示非常抱歉,以后會逐漸加快進度,不過由于這是一個很長的系列,我也想把它寫好,所以以后也會慢慢來,在這個系列的過程中也會穿插發一些其他文章,比如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。
//XamlReaderStringBuilder 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();
同時我們還可以從文件流中讀取并操作。
//XamlReaderusing (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了,具體代碼如下:
//XamlWritervar 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的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: [转载]C 指针
- 下一篇: win8 关于Adobe CS6系列软件
