WPF感悟(3)——關於向窗體動態添加控件

WPF感悟(3)——關於向窗體動態添加控件

這是一個很有意思的話題。

首先,雖然在講課的時候,我時常會講到一些關於動態地向窗體中添加控件的例子,但在實際工作中我卻很少用用到要這個技術。一般情況下,控件在窗體上是寫好的,只是根據需要顯示與隱藏。

其次,也是最重要的——我標題用的是“窗體”沒有用Window,這是爲什麼呢?因爲同樣看上去是窗體,WinForm編程對應的類是Form,WPF編程對應的類是Window。雖然在運行時(run time)它們都是Windows API用CreateWindowEx函數創建出來的Window Class,但在它們還是.NET類的時候,卻有着巨大的區別——特別是體現在內部控件的組織形式上。

WinForm

WinForm窗體裏的按鈕、文本框等供用戶操作的對象稱爲“控件”(controls)。這些控件可以分爲兩類,一類是非容器控件,這類控件的內部結構是固定不變的,比如一個Button內部只能是一串文字(還可以設置Button的背景圖片),如果你想在Button內顯示一個圖標後跟上一串文字,要麼你寫一個自定義控件(派生自Button、再來點兒GDI+的技術)、要麼你把文字寫在圖片上整個作爲Button的背景圖片;另一類是容器控件,它的內部可以裝一些其他控件,這類控件的一個特點就是有一個Controls屬性,這是一個ControlCollection。

你可以把Form也看成是一個容器控件。我們說的動態添加控件也就是向容器控件內添加控件了——方法就是先聲明一個與控件類型相對應的變量、爲它創建一個控件類型的實例、把這個實例初始化好之後再調用Contols.Add方法,把這個變量添加進容器控件就好了。看起來大概是這樣:

private void button1_Click(object sender, EventArgs e)
{
	Button button = new Button();
	button.Size = new Size(80, 20);
	button.Text = "OK";
	groupBox1.Controls.Add(button);
}

這裏有兩點非常重要——

  • WinForm的控件組織是“平面化”的,也就是說,在一個容器控件內,它們處在同一個ControlCollection內、不再有包含關係(除非它是一個容器控件)。如果我們把目光放的宏觀一些,那麼WinForm窗體在包含容器控件時,可以稱之爲一棵以容器控件(也只能以容器控件)爲結點的、邏輯上的樹——但實際工作中我們誰也不會去使用這棵樹,因爲它沒什麼用處。後面你會看到,WPF裏也有“樹”——那是真正的樹,WPF幾乎一切事件消息路由都依賴於這棵樹。
  • 要想向Controls裏添加一個初始化完備的控件,你就幾乎總要聲明一個變量——在WPF裏就不用這麼做,因爲XAML本身的樹狀結構,再加上新版本.NET支持“對象初始化”語法,使代碼變得非常簡單。當然,.NET的方便的功能並非WPF所獨享的——我們完全可以在WinForm編程中也使用它,上面的代碼會簡化成這樣
private void button1_Click(object sender, EventArgs e)
{
	groupBox1.Controls.Add(new Button { Text = "OK", Size = new Size(80,20) });
}

這種語法叫做“對象初始化器”,這也是我要在下一篇文章——《WPF感悟(4)——對象初始化器傳奇》——裏將要介紹的內容。

WPF

WPF窗體裏的按鈕、文本框等UI組件稱爲“元素”(Element),更確切地說是“UI元素”(與UIElement類對應)。UI元素這個詞裏隱含了一點,那就是:它一定是“可視”的(Visual),不然怎麼讓用戶去使用呢?

WPF UI元素與WinForm控件最大的不同就是WPF UI元素不再以“容器”和“非容器”作爲區分,而是以“內容元素”和“非內容元素”來區分。所謂內容元素,就是說它有一個名爲Content的屬性——它是Object類型的!要知道,Object類是所有.NET類的父類,這就意味着對於一個內容元素來說,隨便你往它裏面裝什麼都可以!裝一個UI元素可以、裝一組UI元素也可以——把這組元素組合在一個集合裏就OK了。

如果內容元素的內容仍然是內容元素呢?一棵真正的、可視化的“樹”就形成了。這就是WPF中聲明赫赫的Visual Tree,WPF窗體上的事件消息也是沿着這棵可視化樹傳遞的——消息經過每個可視化樹上的結點(UIElement)時稱爲“路由”(Route),這時候我們可以對消息進行處理和控制。這方面的知識我將在《深入淺出WPF》系列文章裏仔細介紹。

你可能會問,WPF裏有哪些UIElement是Content Element呢?呃……真問住我了。太多了!以至於我只記得幾個非Content Element——比如TextBlock、TextBox。在WPF中,非Content Element的表現功能是很弱的,因爲它們肚子裏的內容太單一了。就拿TextBlock和TextBox來說,它們的內容只能是文本。

Content Element的內容就非常多了!Button就是一個Content元素。在WPF中,Button搖身一變,肚子裏可就“別有洞天”了。

……打會兒遊戲,晚上接着寫。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章