1. 程式人生 > >WPF ItemsControl深度解讀之Items和ItemsSource

WPF ItemsControl深度解讀之Items和ItemsSource

    相信不少WPF開發者對控制元件有一些瞭解,擺脫了早期微軟的MFC,發現WPF程式設計方式更加方便。但是仍然是浩如煙海般的資料需要了解。控制元件是WPF開發繞不開的話題。今天我們就從分析ItemsControl控制元件開始。

    ItemsControl可以包含多個項,神奇的就在於它可以包含字串或完全使用者自己定義的類物件,甚至可以包含Button按鈕、StackPanel控制元件,它是ListBox,ListView,TreeView等其他控制元件的父類,然而ItemsControl也可以直接作為WPF的控制元件使用。

首先我們看一下Items和ItemsSource兩個屬性在ItemsControl中的的定義:



1)下面講解一個例子,通過ItemsControl的Items屬性新增項:


效果如下:

這種用法是在XMAL檔案中直接新增<ItemsControl.Items>來達到新增項的目的。但是這種方式貌似只能夠新增一項。

2)下面講解第二個例子,如何通過ItemsControl的Items屬性新增多個項,需要通過程式碼來達到,如下為XMAL檔案的程式碼:


相應的對此ItemsControl新增項的原始碼如下:


結果如下:


可見ItemsControl的項中可以新增任何物件,可以是字串,也可以是Button等。

3)根據微軟官方的說明文件,指定ItemsSource屬性的源,也就是向ItemsSource屬性賦一個IEnumerable型別的物件,也可以實現項的新增。需要注意的是當您對ItemsSource設定了屬性值之後,則Items屬性將變成只讀,且Items大小也變為一個固定大小,這就意味著不能通過Items屬性新增項了。當ItemsSource屬性之前已經設定了一個IEnumerable型別物件,後面又通過程式碼將ItemsSource設定為null,將刪除整個集合項並且Items屬性將恢復使用,只不過此時Items是一個空的ItemCollection物件。

例子,XMAL中設定ItemsSource為{Binding Path=strlist}

原始檔中定義一個公開的strlist物件(屬於List<string>類,也可以是其他IEnumerable類):


效果如下:


現在,我們做個實驗,如下使用ItemsControl控制元件的Items屬性再新增一個項:


此時,執行之後會出現如下異常:


==================此處為分割線,熟悉繫結的兄弟姐妹可以不用再往下看=========================

講到這裡,稍微講一下題外話——繫結,ItemsControl控制元件的ItemsSource繫結的時候使用如下的繫結擴充套件表示式:

ItemsSource="{Binding path=strlist}"

這是Binding的一種用法,該寫法完全等價於

ItemsSource="{Binding strlist}"

Binding擴充套件語法表示式第一個屬性預設是Path,這個屬性可以省略。關於Path的官方解釋如下:


上面的意思是賦值給Path的必須是一個屬性,假如上面的例子裡strlist定義成如下普通成員:

public List<string> strlist;

也就是如果去掉了set,get(通過實驗,實際上是需要有get)那麼,那麼Path方式繫結無效。

另外就是WPF內部有一套繫結引擎在運轉,它可以自動通過給Path賦值的字串獲得某個物件的屬性,這些過程是自動完成的。

再舉個例子,假設有另外一個類叫MyData包含了一個List<string>屬性的物件strlist:


這個時候只要將XMAL改為如下即可:


效果一樣:


上例中mydata是屬性(Property),strlist也是屬性(Property),因此Binding寫為ItemsSource={Binding mdata.strlist}。

寫到這,另外需要指出的是雖然賦值Path必須是屬性才可以,貌似繫結源必須是屬性。然而,事實並非如此,實際上繫結源並不一定必須是屬性,如下例子(該例子來自官網):


這個例子告訴我們可以通過Source屬性來繫結一個源,此時繫結源並沒有特殊要求,可以不是屬性(Property)。因此結論是:

如果是通過Path來指定繫結源,那麼後面必須跟著的是一個屬性物件;

如果是通過Source指定繫結源,則可以不是屬性,可以是任何物件。