[C#][WPF]MVVM方式的Combobox資料繫結

  • 8308
  • 0
  • 2017-11-30

如何以MVVM的方式處理WPF的Combobox的資料繫結(Data Binding)?

(以下圖片請以右鍵選「在新分頁開啟圖片」會比較清楚)

建立專案
首先建一個WPF專案(命名為ComboboxDataBindingMVVM),在MainWindow的Grid內放一個Combobox。


建立放置Model與ViewModel的資料夾
在專案下加入「Models」和「ViewModels」兩個資料夾。


加入Model資料類別(POCO Class)命名為「Person」。
此類別為裝載資料的容器,只需要屬性,不需要方法。


加入ViewModel資料處理類別,命名為「PersonViewModel」。
ViewModel類別用來處理Xaml畫面所需要呈現的的資料。


Person類別加入 Name、Number 屬性。


PersonViewModel加入「People」屬性,作為Combobox可供選擇的資料列表,
此屬性用來繫結(Binding)至Combobox的「ItemsSource」屬性。
為了讓資料的變化可以主動反映到Combobox上,
所以選用ObservableCollection<T>作為「People」屬性的型別,
這裡的T以「Person」類別取代,使Combobox可以顯示「Person」的資料。

這裡需要加入兩個命名空間,分別為:
using ComboboxDataBindingMVVM.Models; //這也是本範例存Model的資料夾的名稱
using System.Collections.ObjectModel;



PersonViewModel加入建構式,並在建構式中填入People屬性的資料。


PersonViewModel加入「SelectedPerson」屬性,
用來繫結至Combobox的「SelectedItem」屬性,
儲存使用者所選中的項目。


Xaml的資料繫結設定
為了將ViewModel處理過的資料呈現在Xaml畫面中,
所以需要設置Window的DataContext屬性,
首先在Xaml的Window中加入「ComboboxDataBindingMVVM.ViewModels」命名空間:
xmlns:vm="clr-namespace:ComboboxDataBindingMVVM.ViewModels"」,
使Xaml知道有「PersonViewModel」類別可以使用,
這裡的vm可以自行命名,用以代表「ComboboxDataBindingMVVM.ViewModels」命名空間。
(為什麼需要「ComboboxDataBindingMVVM.ViewModels」命名空間?
 因為「PersonViewModel」就是在「ComboboxDataBindingMVVM.ViewModels」命名空間底下建立的類別)



在Xaml中的「Window.DataContext」屬性加入「vm:PersonViewModel」,
用以初始化「PersonViewModel」類別,
其實就是執行C#的「DataContext = new PersonViewModel();」。



在Xaml的Combobox的屬性中,加入「ItemsSource」、「SelectedItem」、「DisplayMemberPath」三個屬性設定。
「ItemsSource」為Combobox的資料來源,須繫結到「PersonViewModel」的「People」屬性。
「SelectedItem」為被使用者選中的資料,須繫結到「PersonViewModel」的「SelectedPerson」屬性。
「DisplayMemberPath」為Combobox所顯示出來的資料內容,在此設為「"Name"」。

ItemsSource的資料型別為複雜型別(含有基礎型別的類別)時,就需要設置DisplayMemberPath,用來指定要顯示出複雜型別內的哪一個屬性的資料。

由於在Xaml上有設定Window.DataContext為vm:PersonViewModel,
所以在寫Binding的時候會有智能提示(Intellisense),相當方便。
(若沒有智能提示,趕快按F6重新建置,應該就有了)


到此即完成MVVM方式處理Combobox的資料繫結。
可以發現到CodeBehind(即MainWindow.xaml.cs檔)完全沒有寫到任何程式碼。

需要注意的是:ObservablCollection有實作了INotifyCollectionChange介面,
只有在集合有Add、Remove、Move、Clear、Replace等動作才會觸發資料變更通知,通知Combobox顯示出變更後的資料。
若直接將資料集合指定給People(例如:People=new ObserverableCollecion(...)),
則只有第一次指定才有用(如本例在PersonViewModel的建構式中直接指定),
之後再設定為新的集合都不會通知UI,畫面上的Combobox不會有任何反應,
請改用Add、Remove、Move、Clear、Replace等方法改變集合資料,
例如:People.Add(new Person() { Name = "Arvin", Number = 3 });  。

若一定要使用指派的方式,則必須自行實作通知機制,亦即在PersonViewModel實作INotifyPropertyChange介面,並在People屬性的set下撰寫PropertyChange的事件觸發: