轉(zhuǎn)帖|其它|編輯:郝浩|2010-11-02 13:49:58.000|閱讀 605 次
概述:這篇課程主要是對上幾次課程的回顧和簡單深化,所以沒有講什么比較新的概念,不過掌握好了這篇,對后面的很多文章都有幫助,同時這一篇文章做Demo、構(gòu)思、研究等也花費了不少時間,所以希望對大家有所幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
一 摘要
首先很高興這個系列能得到大家的關(guān)注和支持,前端時間身體狀況不適,所以暫停了更新,對此表示非常抱歉,以后會逐漸加快進度,不過由于這是一個很長的系列,我也想把它寫好,所以以后也會慢慢來,在這個系列的過程中也會穿插發(fā)一些其他文章,比如Windows Azure、設(shè)計模式、WCF、Silverlight等,同時也會發(fā)一些自己的技術(shù)隨感和心得,反正只要自己寫得開心且對大家有幫助就行。由于自己才疏學淺且是對這些技術(shù)的使用總結(jié)和心得體會,錯誤之處在所難免,懷著技術(shù)交流的心態(tài),在這里發(fā)表出來,所以希望大家能夠多多指點,這樣在使一部分人受益的同時也能糾正我的錯誤觀點,以便和各位共同提高。
這篇課程主要是對上幾次課程的回顧和簡單深化,所以沒有講什么比較新的概念,不過掌握好了這篇,對后面的很多文章都有幫助,同時這一篇文章做Demo、構(gòu)思、研究等也花費了不少時間,所以希望對大家有所幫助。
二 本文提綱
1.摘要
2.本文提綱
3.前篇回顧
4.Xaml基礎(chǔ)
5.脫離VS工具CSC編譯WPF
6.XamlReader與XamlWriter
7.本文總結(jié)
8.系列進度
三 前篇回顧
在我們?nèi)粘5拈_發(fā)中,軟件企業(yè)的開發(fā)人員一般會有兩種類型的工作:
1,一類是用戶界面設(shè)計人員,他們關(guān)心的是軟件和用戶之間的交互,就是如何讓用戶體驗更好;
2,另一類是軟件開發(fā)人員,他們關(guān)心的是軟件的架構(gòu)設(shè)計、業(yè)務(wù)邏輯的處理和軟件功能的實現(xiàn);
在BS中,用戶界面設(shè)計人員使用HTML及其工具來設(shè)計界面,開發(fā)人員使用Java,C#,VB或其他語言來實現(xiàn)其中的邏輯,HTML網(wǎng)頁可以用到最終的產(chǎn)品中。
在CS中,過去我們一直沒有分開這兩種不同性質(zhì)的工作。用戶界面設(shè)計人員通常和開發(fā)人員使用不同的工具,當界面設(shè)計人員設(shè)計好用戶界面時,他們的工作并沒有用到最終的產(chǎn)品中,而只是用來展現(xiàn)某種概念或工作流程。
XAML實現(xiàn)了互聯(lián)網(wǎng)應(yīng)用程序和桌面應(yīng)用程序的統(tǒng)一,界面設(shè)計人員可以使用XAML或基于XAML的工具(如微軟的Design和 Blend) 來設(shè)計CS或BS應(yīng)用程序的界面。程序開發(fā)人員則可以在此基礎(chǔ)上使用C#或VB.NET等來開發(fā)相應(yīng)的功能,這樣,界面設(shè)計人員的工作便自然過渡到最終產(chǎn)品中。
在XAML中,用戶界面用XML的元素或?qū)傩詠肀硎?。WPF引擎把XAML描述的UI元素解釋為相應(yīng)的.NET對象,從而在桌面程序或Silverlight網(wǎng)頁上創(chuàng)建相應(yīng)的控件。如下圖所示:
上面這副就是傳統(tǒng)的WinForm開發(fā)模式,這兩種人沒有分離開來,所以在很多企業(yè)里就形成了開發(fā)人員既要做UI也要做程序的境地。
上圖就是現(xiàn)在的WPF和Silverlight程序的開發(fā)模式,這兩類人可以分開來工作,他們都可以對Window1.xaml進行修改和加載,所以這樣就使分工更專業(yè)了,由于大家專注于某一個方面,分工協(xié)作的同時,質(zhì)量和效率也逐漸提高了。
前幾篇介紹了一些基礎(chǔ)知識,那么這篇也簡單的回顧一下,下面第一幅圖是WPF的執(zhí)行順序,第二副圖是WPF的一個項目的構(gòu)成,第三幅圖是WPF所對應(yīng)的IL代碼(這些圖處理得不好,還望各位見諒)。
WPF的執(zhí)行順序
WPF的一個項目的構(gòu)成
WPF所對應(yīng)的IL代碼,通過Reflector查看
四 Xaml基礎(chǔ)
這個部分要講的東西就太多了,由于這篇文章篇幅有限,同時我覺得用代碼詮釋能讓大家可以更清晰地理解,所以就講得隨意一些,通過一個Demo介紹WPF對資源、類、控件的調(diào)用和處理,對Dictionary資源、Application資源、window資源以及控件資源的應(yīng)用等,如下圖所示(本篇所有代碼在評論的第一條):
由于這些概念比較簡單并且較多,如果全部寫完,也得專門寫一長篇,還好大家都喜歡看代碼,所以我就不花費大的篇幅來講它們,感興趣或者對這些知識還有不清楚的朋友可以下載這個Demo進行查看或調(diào)試,我覺得對初學者很有幫助。
五 脫離VS工具CSC編譯WPF
為了更好的認識WPF的編譯和執(zhí)行過程,我們可以暫時棄用我們熟悉的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 開始編譯,
這樣你就更能看清楚編譯器背后的秘密,同時也能跟蹤每一步執(zhí)行的操作,同時對一些簡單的內(nèi)存泄露問題也比較容易察覺到。當然現(xiàn)在也有很多工具可以跟蹤這些問題,我這里只是寫一種思路,大家可以根據(jù)自己的愛好取舍。
六 XamlReader與XamlWriter
System.Windows.Markup 命名空間中提供了 XamlReader、XamlWriter 兩個類型,允許我們手工操控 XAML和BAML 文件。
XamlReader類除了定義Load的實時加載之外,也定義了異步方法,可以異步解析XAML中的內(nèi)容。我們可以在XamlReader對象的實例里調(diào)用它們。如果在讀取一個大文件時要保持用戶UI的響應(yīng)性,就可以使用異步讀取的方法。和異步讀取方法匹配的還有一個CancelAsync方法,用于停止讀取操作。XamlReader 還定義了LoadCompleted事件,在讀取完成后會觸發(fā)該事件,那么我們就可以把讀完后要做的事情都在這里進行處理。
XamlWriter 供一個靜態(tài) Save 方法(多次重載),該方法可用于以受限的 XAML 序列化方式,將所提供的運行時對象序列化為 XAML 標記。這句話似乎有點難懂,其實簡單的說就是把它序列化為我們需要的類型。
具體功能代碼如下:
通過XamlReader 動態(tài)構(gòu)建并實例化一個Window
//XamlReader
StringBuilder strXMAL = new StringBuilder("<Window ");
strXMAL.Append("xmlns=\"//schemas.microsoft.com/winfx/2006/xaml/presentation\" ");
strXMAL.Append("xmlns:x=\"//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="//schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="//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="//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 的動態(tài)載入在使用動態(tài)換膚以及運行時加載等場景頗為有用,以后也會慢慢接觸。
由于使用XamlReader和XamlWriter有很多限制,比如我想把一批Baml轉(zhuǎn)化為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 });
}
}
上面的代碼,大家可以試一下運行效果?;蛘哂懈玫姆绞揭舱埜嬷?/p>
七 本文總結(jié)
本篇主要對前幾次的課程進了一些簡單的回顧,同時用一個比較全的Demo介紹了Xaml中引用各種控件和類等,另外對脫離VS工具CSC編譯WPF以及XamlReader與XamlWriter 做了比較詳細的介紹。下篇我們將進入WPF布局的世界進行漫游,爭取和布局控件及應(yīng)用來一個全接觸!
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:博客轉(zhuǎn)載自圣殿騎士