今天我們先來看一下在WP8.1開發中最長見到的幾個文件之間的關系。比較論證,在看這個問題之前我們簡單看看.NET平台其他兩個不同的框架:
Windows Forms
先看看Window Forms中的情況,下圖為在VS中創建的默認Windows Forms項目結構:
分別回顧一下每個文件以及它們之間的關系:
┣━ Properties------------------------------------------- 項目屬性文件夾
┣━━━━━ AssemblyInfo.cs----------------------------------- 程序集信息聲明
┣━ App.config------------------------------------------- 應用程序配置文件
┣━ Form1.cs--------------------------------------------- 窗體Form1 類文件
┣━━━━━ Form1.Designer.cs--------------------------------- 窗體Form1設計 類文件
┗━ Program.cs------------------------------------------- 程序入口類文件
這里我們主要關心的就是Form1.cs、Form1.Designer.cs和Program.cs三個文件,下面我用Visio圖表示一下執行流程
也就是說,Form1.cs和Form1.Designer.cs最終在編譯階段形成了一個類型,所有的控件的定義和初始化(大多是由於開發者的拖拽和屬性編輯操作產生)全部在Form1.Designer.cs這個部分類中完成,代碼我就不用貼出來了。我們在開發的時候只需要關心如何在Form1.cs文件中操作部分類中定義的控件成員和編寫一些邏輯代碼,從而減少開發者的編碼量。
說白了,也就是大家常說的前台UI(Form1.Designer.cs)和后台代碼(Form1.cs)是部分類的關系,通過partial關鍵字實現。
Web Forms
再來看看Web Form中又是怎樣的一種形式:
這里我們主要是看看WebForm1.aspx、WebForm1.aspx.cs和WebForm1.aspx.designer.cs這三個文件的關系:
我們都應該知道WebForm1.aspx文件最終也是編譯成為一個類存放於一個臨時的程序集,對於這個類型來講,它派生自WebForm1.aspx.cs文件中定義的類,也就是說前台UI(WebForm1.aspx)是后台代碼(WebForm1.aspx.cs)的子類。那么WebForm1.aspx.designer.cs又是個啥?這里就和WinForms一樣了,它和WebForm1.aspx.cs最終也是編譯成為一個類型,在WebForm1.aspx.designer.cs也都是定義了一些控件,這也是當年號稱很厲害的CodeBehind,目的是將表現和邏輯隔離,當然我們這里不需要評價CodeBehind,本身也不在今天討論的范疇之中。
Window Phone / WPF
最后來看看WP中怎么設計的:
以上是Visual Studio 2013 Update 4中創建的空白Windows Phone 8.1應用,其中有一個MainPage.xaml和MainPage.xaml.cs文件,那它兩又是什么關系呢?難道是和Windows Forms又或是Web Forms一樣嗎?
答案自然是否定的,首先XAML文件中寫的XAML代碼實際上就是XML語法,官方的說法:它是一個聲明對象的語言,為我們創建對象提供便捷的一種方式。與HTML類似,特點是用來描述用戶接口(UI)內容。
通常我們把與xaml文件關聯的xaml.cs文件叫作代碼隱藏文件。如果你引用xaml中的任何一個事件處理程序(通過事件特性,如Button的Click事件),這里就是我們定義這些事件處理程序的地方。
我們先看看后台代碼

1 namespace Demo1 2 { 3 /// <summary> 4 /// 可用於自身或導航至 Frame 內部的空白頁。 5 /// </summary> 6 public sealed partial class MainPage : Page 7 { 8 public MainPage() 9 { 10 this.InitializeComponent(); 11 12 this.NavigationCacheMode = NavigationCacheMode.Required; 13 } 14 15 /// <summary> 16 /// 在此頁將要在 Frame 中顯示時進行調用。 17 /// </summary> 18 /// <param name="e">描述如何訪問此頁的事件數據。 19 /// 此參數通常用於配置頁。</param> 20 protected override void OnNavigatedTo(NavigationEventArgs e) 21 { 22 // TODO: 准備此處顯示的頁面。 23 24 // TODO: 如果您的應用程序包含多個頁面,請確保 25 // 通過注冊以下事件來處理硬件“后退”按鈕: 26 // Windows.Phone.UI.Input.HardwareButtons.BackPressed 事件。 27 // 如果使用由某些模板提供的 NavigationHelper, 28 // 則系統會為您處理該事件。 29 } 30 31 private void btnHello_Click(object sender, RoutedEventArgs e) 32 { 33 txtResult.Text = "Hello World"; 34 var temp = (TextBlock)base.FindName("txtResult"); 35 temp.Text = "Hello World2"; 36 } 37 } 38 }
對於后台代碼文件中定義的類同樣也有個partial ,貌似跟Windows Phone有點類似。但是我們找了找整個解決方案並沒有發現有一個與之對應的部分類,但是根據CodeLens的提示,我們能發現確實有部分類的存在而且是兩個類文件MainPage.g.cs和MainPage.g.i.cs
分別雙擊打開這個類文件
MainPage.g.cs

1 namespace Demo1 2 { 3 partial class MainPage : global::Windows.UI.Xaml.Controls.Page, global::Windows.UI.Xaml.Markup.IComponentConnector 4 { 5 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")] 6 [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 7 8 public void Connect(int connectionId, object target) 9 { 10 switch(connectionId) 11 { 12 case 1: 13 #line 22 "..\..\MainPage.xaml" 14 ((global::Windows.UI.Xaml.Controls.Primitives.ButtonBase)(target)).Click += this.btnHello_Click; 15 #line default 16 #line hidden 17 break; 18 } 19 this._contentLoaded = true; 20 } 21 } 22 }
MainPage.g.i.cs

1 namespace Demo1 2 { 3 partial class MainPage : global::Windows.UI.Xaml.Controls.Page 4 { 5 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")] 6 private global::Windows.UI.Xaml.Controls.Button btnHello; 7 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")] 8 private global::Windows.UI.Xaml.Controls.TextBlock txtResult; 9 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")] 10 private bool _contentLoaded; 11 12 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Windows.UI.Xaml.Build.Tasks"," 4.0.0.0")] 13 [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 14 public void InitializeComponent() 15 { 16 if (_contentLoaded) 17 return; 18 19 _contentLoaded = true; 20 global::Windows.UI.Xaml.Application.LoadComponent(this, new global::System.Uri("ms-appx:///MainPage.xaml"), global::Windows.UI.Xaml.Controls.Primitives.ComponentResourceLocation.Application); 21 22 btnHello = (global::Windows.UI.Xaml.Controls.Button)this.FindName("btnHello"); 23 txtResult = (global::Windows.UI.Xaml.Controls.TextBlock)this.FindName("txtResult"); 24 } 25 } 26 }
從這兩個文件中我們可以看到,MainPage類在這里還定義了一些控件和相關的方法,並且InitializeComponent()方法里面加載和解析了MainPage.xaml文件MainPage.cs文件里面的MainPage()方面里面調用的InitializeComponent()方法就是在MainPage.g.cs文件里面定義的。在xaml頁面中聲明的控件,通常會在.g.cs中生成對應控件的內部字段。實際上這取決於控件是否有x:Name屬性,只要有這個屬性,都會自動調用FindName方法,用於把字段和頁面控件關聯。沒有x:Name屬性,則沒有字段,這種關聯會有一定的性能浪費,因為是在應用載入控件的時候,通過LoadComponents方法關聯的,而xaml也是在這個時候動態解析的。
由此我們就會萌生一個動態加載XAML的想法:
我在頁面上添加一個按鈕,當按鈕點擊時執行如下代碼:

1 int top = 100; 2 private void btnHello_Click(object sender, RoutedEventArgs e) 3 { 4 string temp = "<Button xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" " + 5 " Content=\"這是動態加載的按鈕\"/>"; 6 Button btnTemp = (Button)XamlReader.Load(temp); 7 // 設置水平對其方式 8 btnTemp.HorizontalAlignment = HorizontalAlignment.Center; 9 // 讓Margin每次都變一下 10 btnTemp.Margin = new Thickness(0, top-=100, 0, 0); 11 // 動態設置點擊事件 12 btnTemp.Click += btnHello_Click; 13 grid.Children.Add(btnTemp); 14 }
效果如下圖所示:
通過C#創建按鈕的形式:

1 /// <summary> 2 /// 在此頁將要在 Frame 中顯示時進行調用。 3 /// </summary> 4 /// <param name="e">描述如何訪問此頁的事件數據。 5 /// 此參數通常用於配置頁。</param> 6 protected override void OnNavigatedTo(NavigationEventArgs e) 7 { 8 // TODO: 准備此處顯示的頁面。 9 10 // TODO: 如果您的應用程序包含多個頁面,請確保 11 // 通過注冊以下事件來處理硬件“后退”按鈕: 12 // Windows.Phone.UI.Input.HardwareButtons.BackPressed 事件。 13 // 如果使用由某些模板提供的 NavigationHelper, 14 // 則系統會為您處理該事件。 15 16 Button btn = new Button(); 17 btn.Content = "代碼創建的按鈕"; 18 btn.Click += btnHello_Click; 19 grid.Children.Add(btn); 20 }
雖然我們可以這樣創建對象,但是這種形式就喪失我們XAML創建頁面元素對象的優勢了!
總結一下:XAML只是創建對象的一種便捷方式,類似於一種“命令”的形式,跟后台代碼沒有關系,只是在后台執行的時候鍵xaml文件當做資源去載入罷了!
結合這個幾個平台來看,認為微軟為開發者考慮的太多,有的時候反倒是形成一種“負擔”!