關於 WP 開發中.xaml 與.xaml.cs 的關系


今天我們先來看一下在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.csForm1.Designer.csProgram.cs三個文件,下面我用Visio圖表示一下執行流程

 

 

也就是說,Form1.csForm1.Designer.cs最終在編譯階段形成了一個類型,所有的控件的定義和初始化(大多是由於開發者的拖拽和屬性編輯操作產生)全部在Form1.Designer.cs這個部分類中完成,代碼我就不用貼出來了。我們在開發的時候只需要關心如何在Form1.cs文件中操作部分類中定義的控件成員和編寫一些邏輯代碼,從而減少開發者的編碼量。

 

說白了,也就是大家常說的前台UIForm1.Designer.cs)和后台代碼(Form1.cs)是部分類的關系,通過partial關鍵字實現。

 

Web Forms

再來看看Web Form中又是怎樣的一種形式:

這里我們主要是看看WebForm1.aspxWebForm1.aspx.csWebForm1.aspx.designer.cs這三個文件的關系:

我們都應該知道WebForm1.aspx文件最終也是編譯成為一個類存放於一個臨時的程序集,對於這個類型來講,它派生自WebForm1.aspx.cs文件中定義的類,也就是說前台UIWebForm1.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.xamlMainPage.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 }
MainPage.cs

對於后台代碼文件中定義的類同樣也有個partial ,貌似跟Windows Phone有點類似。但是我們找了找整個解決方案並沒有發現有一個與之對應的部分類,但是根據CodeLens的提示,我們能發現確實有部分類的存在而且是兩個類文件MainPage.g.csMainPage.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.cs

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.g.i.cs

從這兩個文件中我們可以看到,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 }
動態加載按鈕XAML

效果如下圖所示:

 

通過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 }
通過C#代碼創建控件

雖然我們可以這樣創建對象,但是這種形式就喪失我們XAML創建頁面元素對象的優勢了!

 

總結一下:XAML只是創建對象的一種便捷方式,類似於一種“命令”的形式,跟后台代碼沒有關系,只是在后台執行的時候鍵xaml文件當做資源去載入罷了!

結合這個幾個平台來看,認為微軟為開發者考慮的太多,有的時候反倒是形成一種“負擔”!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM