下拉框是一個很經(jīng)典的控件,,網(wǎng)上也有不少對于下拉框控件的擴展,其中包括與TreeView結(jié)合,,做成樹形選擇,;與DataGrid結(jié)合,做成列表選擇,;又或增加幾個按鈕來達到快捷編輯集合,,選中項特殊顯示等等。 對于復雜的組合控件,,我這里就不必多說,,只說說原生ComboBox的一些應用。
原文鏈接:http:///blog/2013/03/29/winform-wpf-2/
綁定數(shù)據(jù)源
簡單的給Items添加項我就不說了,,比如一些類型的選擇多數(shù)使用這種,,如一個員工的職位,是程序猿呢,,還是項目經(jīng)理,。 但往往這種職位,是需要考慮擴展的,,也就是說這個職位也要可維護的,,所以一般的軟件做法,在數(shù)據(jù)庫中以字典表的形式去保存這類情況,,而數(shù)據(jù)庫設(shè)計中又有這么一個要求,,每個表都要有不重復的ID做主鍵,所以經(jīng)??吹饺绱说谋斫Y(jié)構(gòu):
- GUID varchar(50)
- Name varchar(50)
- ...
GUID varchar(50)
Name varchar(50)
...
那么,,將該數(shù)據(jù)展示在ComboBox中,可能就需要展示的是Name,,而你只想獲取選擇的GUID,。 所幸不管在WinForm還是WPF中,更或是在web開發(fā)中,,即使純Html的ComboBox,,都有這種選擇的一個值,而可能實際獲得的是另一個值,。 WinForm中指定DisplayMember 與ValueMember 屬性,,WPF中指定DisplayMemberPath 與SelectedValuePath 屬性,可以很簡單的實現(xiàn)上述要求,。 而如果當這個字典表很大,,或者客戶需要給這種職位、類別之類的東西編號的時候,這時可能需要在顯示的時候既顯示編號,,又顯示名稱,,這時的表結(jié)構(gòu)可能會這樣:
- GUID varchar(50)
- No varchar(50)
- Name varchar(50)
- ...
GUID varchar(50)
No varchar(50)
Name varchar(50)
...
如果不拘于形式而言,一般完全可以使用No替換GUID,,不管怎樣,,現(xiàn)在就是想要既獲得主鍵列的值,又想顯示No
+ Name 的形式,。
重寫ToString的一種實現(xiàn)方式
一般如此數(shù)據(jù),,都會有一個實體層(Model/Entity),比如上例,,這個實體層可能看起來像這樣:
- public class UserModel
- {
- public string GUID { get; set; }
- public string No { get; set; }
- public string Name { get; set; }
- }
public class UserModel
{
public string GUID { get; set; }
public string No { get; set; }
public string Name { get; set; }
}
假設(shè)我們從數(shù)據(jù)源中獲取了一個UserModel 的集合(如List<UserModel> ),,將該集合直接綁定倒ComboBox中,而不指定它的那幾個屬性,,那么他可能顯示的是UserModel 的類名全稱,而為什么顯示的是類的全名而不是其他呢,,其實這里調(diào)用的是UserModel 的ToString 方法,,而現(xiàn)在UserModel 的ToString 繼承自object ,object 的ToString 方法正是返回當前類的全名,。 知道了這點,,我們想讓顯示No
+ Name 的形式就好辦的多了,我們重寫UserModel 的ToString 方法,,不指定ComboBox的上述幾個屬性,,直接綁定數(shù)據(jù)源,ToString 方法可能會這樣:
- public void ToString()
- {
- return No + "---" + Name;
- }
public void ToString()
{
return No + "---" + Name;
}
但隨即你就會發(fā)現(xiàn)WinForm有一個問題,,如果你沒有指定DisplayMember 屬性,,而是只指定ValueMember 屬性,那么他會將ValueMember 屬性也當成DisplayMember 屬性去處理,,而不會調(diào)用ToString 方法,。
因為WinForm的這個問題,我們可能會使用另一種萬能 方式去獲取選擇項的某列值——使用SelectedItem 屬性,。之所以現(xiàn)在才說,,是因為SelectedItem 屬性是一個object 類型,這樣在我這個程序里,,可能是UserModel ,,在另一個程序里,可能是DataViewRow ,,雖然萬能 ,,但實現(xiàn)不夠優(yōu)雅。
添加一個屬性
這點很簡單,很正常,,但是有些人認為不應該修改Model層的屬性,,Model層應該和數(shù)據(jù)庫字段一一對應,而且堂而言之,,為工具生成Model層替換方便... 這里我也表示你下自己的觀點,,本人十分反感如此說法,正如在使用MVVM時不能在后臺寫代碼一樣反感,,將原本一個事件,,一行的代碼,復雜的弄在xaml文件中去實現(xiàn),。 添加一個屬性,,這種方式?jīng)]有任何錯誤,如果使用MVVM,,這個屬性可以寫在VM中,,這個屬性可能是這樣:
- public string DisplayName
- {
- get
- {
- return ToString();
- }
- }
public string DisplayName
{
get
{
return ToString();
}
}
也可以不重寫ToString ,而是把ToString 中的代碼移過來,。
自動提示(AutoComplete)
關(guān)于自動提示,,ComboBox其實都是天生就支持的,只是WinForm里做的功能多一點,,而WPF功能少一點(只是定位),。 當然,這只能說WPF比WinForm靈活,,擴展方便,。
WinForm中的自動提示有專門的屬性去做,如果你按類型排序,,這幾個類型都在雜項中,,都以AutoComplete 為前綴。 其實這里的AutoCompleteSource 屬性定的很雞肋,,我用的基本也只有ListItems 和CustomSource 兩個選項,,而且本人認為CustomSource 使用有點重復的概念,幾乎沒有人想在提示的時候使用一個數(shù)據(jù)源,,而選擇的時候使用另一個數(shù)據(jù)源,。 當然,也不排除各種變態(tài)的需求,,但多做一點總比少做一點要好么,,而也正是這點想法的分歧,鑄就了WPF的反其道而行之,。
本來想寫專文來說說這個,,但是自己WPF所知甚淺,,惟恐誤人子弟,這里就隨便扯兩句,,以WPF的ComboBox為例,,也不算脫離主題。
WPF的ComboBox其實是一個復雜控件,,有一個ToggleButton 用來表示下拉按鈕,,一個Popup 用來表示下拉框,在編輯狀態(tài)(IsEditable="True"),,還會有一個TextBox ,,所以,如果WPF沒有提供一個ComboBox,,照道理來說,,是很容易自己寫一個ComboBox的。 WPF中很多控件都是這樣,,可能都是使用Primitives 命名控件下的控件組合而成,。
在WPF中如果自帶的自動提示功能有點簡單,只要設(shè)置3個屬性即可:IsEditable ,,StayOpenOnEdit ,,IsTextSearchEnabled ,而這種自動提示只是簡簡單單的一個定位功能,,很多時候我們要的是篩選,,而不是定位,。
要實現(xiàn)WPF中ComboBox的自動提示,,方式可以有很多,假設(shè)咱們不考慮如何去實現(xiàn)對于數(shù)據(jù)源的篩選,,而只是實現(xiàn)界面中當ComboBox的Text改變時,,讓其篩選,并展示下拉框(Popup )也不是一個簡單的事情,。 其中一個原因是由于WPF中一個問題:
當設(shè)置ComboBox的IsDropDownOpen屬性為True時(讓ComboBox展開下拉框),,TextBox中的文本被全選。
其實WPF中的問題很多,,又何止這一個,。 當然,正式因為WPF的簡單性,,才使得這些問題(Bug)都可以自己解決,,所以很多東西,其實根本不是問題,。
|