當我們在設計 Windows Phone 7 程式時, 對於一個習慣於 Windows Form 和 Web Form 的程式設計師而言, 可能會覺得有點納悶: 為什麼找不到 ComboBox? 其實 ComoBox 仍然是可以用的, 只是它並未列在工具箱裡面而已...
當我們在設計 Windows Phone 7 程式時, 對於一個習慣於 Windows Form 和 Web Form 的程式設計師而言, 可能會覺得有點納悶: 為什麼找不到 ComboBox?
其實 ComoBox 仍然是可以用的, 只是它並未列在工具箱裡面而已。如果你一定要用的話, 把以下程式打進去就行了:
<ComboBox Width="400" Height="110">
<ComboBoxItem Content="Johnny" />
<ComboBoxItem Content="Tommy" />
<ComboBoxItem Content="Andy" />
</ComboBox>
不過, 如果你也覺得它很不好用的話, 那麼你應該就會了解它為什麼已經不被放在預設的工具箱裡了。
當然, 我們也可以採用 ListBox 來取代 ComboBox 的功能, 而且我認為這也是微軟如此設計的原意。
但是當我昨天看到 Silverlight for Windows Phone Toolkit 之後, 我就把它下載並且安裝了。在這組工具裡有一個 ListPicker, 我將在這篇文章裡解說它的使用方法。
基本上 ListPicker 的用法幾乎跟傳統的 ComboBox 一模一樣, 此外其操作方式還有幾個特色:
- 可以加上 Header 這個 attribute 以加入標題
- 選按項目之後將會開啟下拉式選單以供選擇
- 如果選項超過原始大小, 會開啟全螢幕, 在全螢幕之下可以以手指上下滑動
- 在全螢幕畫面中可以按 Back 按鈕回到未開啟選單的畫面, 不必再另外寫程式處理
一個最簡單的範例如下 (XAML):
<toolkit:ListPicker Header="Categories">
<toolkit:ListPickerItem Content="Johnny" />
<toolkit:ListPickerItem Content="Tommy" />
<toolkit:ListPickerItem Content="Alumi" />
</toolkit:ListPicker>
以上是把下拉式選單打開時的畫面。
你可以把 toolkit:ListPickerItem 的項目多加幾個。但是很不幸的, 如果你加入太多項目, 以至於超過原來規畫的大小尺寸時, 程式就會當掉了!
正當我深感失望並打算放棄這個控制項時, 我的心裡突然浮現一個想法: 為什麼不把死馬當作活馬醫, 再來試試動態的資料繫結呢? 搞不好這樣不會當掉! 況且, 我本來就是打算把它加上資料繫結的。
結果當然是不會當掉的, 否則怎麼會有這篇文章的出現? 以下就是我把它改成資料繫結的寫法:
<toolkit:ListPicker Height="377" HorizontalAlignment="Left" Margin="25,185,0,0" Name="lp" VerticalAlignment="Top" Width="325" Header="Categories">
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}" Margin="5" Foreground="Red" VerticalAlignment="Center" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
</toolkit:ListPicker>
如果你眼尖的話, 你也許發現它的 Template 寫法和 ListBox 一模一樣。是的, 因為我原本懷疑這個控制項是從 ListBox 繼承而來的, 所以我試著把 ListBox 的碼搬過來用, 結果竟然可行! 雖然說 ListPicker 其實是繼承自 ItemsControl 控制項。
不過如果我們想運用 ListPicker 的特殊功能的話, 我們還是必須把上面的 XAML 改成如下的樣子:
<Grid.Resources>
<DataTemplate x:Name="PickerItemTemplate" >
<StackPanel Orientation="Horizontal" Opacity="0.8">
<TextBlock Text="{Binding Id}" Margin="5" Foreground="Red" VerticalAlignment="Center" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="PickerFullModeItemTemplate">
<StackPanel Orientation="Horizontal" Opacity="0.8">
<Image Margin="5" Source="/PhysicalExamValues;component/Assets/appbar.feature.settings.rest.png" VerticalAlignment="Center" Opacity="1" />
<TextBlock Text="{Binding Id}" Margin="5" Foreground="Red" VerticalAlignment="Center" />
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
...
<toolkit:ListPicker x:Name="lp" Height="556" HorizontalAlignment="Left" Margin="6,6,0,0"
ListPickerMode="Full" VerticalAlignment="Top" Width="434" ItemCountThreshold="3"
Header="Choose Category" SelectionChanged="lp_SelectionChanged"
FullModeHeader="Choose Category" Background="#FF8ECFFB"
ItemTemplate="{StaticResource PickerItemTemplate}"
FullModeItemTemplate="{StaticResource PickerFullModeItemTemplate}" />
上面的 <Grid.Resources> 是在 LayoutRoot 的裡面。而之所以要區分為 ItemTemplate 和 FullModeItemTemplate 兩種 Template, 是為了能夠適用在資料繫結項目少與項目多的兩種情況。如果項目不多 (例如只有兩、三項), 那麼下拉式選單會直接開在原來那一頁。如果項目多 (你可以透過設定 ItemCountThreshold 的值來決定多少以上算是「多」), 那麼選單會開啟在新頁, 並且以全頁方式展開。你可以讓 ItemTemplate 和 FullModeItemTemplate 長得不一樣。
我再講得白話一點好了。例如, 由於我們或許不知道資料繫結的來源到底會有多少項目 (可能多, 可能少), 所以我們設計了 ItemTemplate 這個樣板, 萬一繫結的項目很少 (例如只有兩項), 那麼就讓下拉式選單直接開在原來的地方 (就和 Windows 程式中做法一樣), 其排列就如同 ItemTemplate 的設計。萬一繫結來源的項目多於三個 (因為我把 ItemCountThreshold 的值設定為 3), 那麼選單會開在新的視窗, 而它的排列就如同 FullModeItemTemplate 的設計, 而在此頁中, 當使用者選好項目之後, 必須使用 Back 按鈕回到原來畫面。你可以讓這兩種 Template 長得完全不一樣, 端看你如何設計它們。而且, 當然了, 如果你允許下拉式選單的項目在當頁可以列出三個, 那麼你就必須在設計頁面中讓 ListPicker 的高度足夠容納三個項目。在 VS2010 中, 它不會告訴你這個控制項的高度是不是足夠容納三個項目, 你只能使用目測。
以下則是 xaml.cs 的原始程式:
public class wawa
{
public int Id { get; set; }
public string Name { get; set; }
}
public List<wawa> categories = new List<wawa>();
...
categories.Add(new wawa() { Id = 0, Name = "Johnny" });
categories.Add(new wawa() { Id = 0, Name = "Tommy" });
categories.Add(new wawa() { Id = 0, Name = "Alumi" });
categories.Add(new wawa() { Id = 0, Name = "Johnny" });
categories.Add(new wawa() { Id = 0, Name = "Tommy" });
categories.Add(new wawa() { Id = 0, Name = "Alumi" });
categories.Add(new wawa() { Id = 0, Name = "Johnny" });
categories.Add(new wawa() { Id = 0, Name = "Tommy" });
categories.Add(new wawa() { Id = 0, Name = "Alumi" });
lp.ItemsSource = categories;
以下則是執行後展開下拉式選單的畫面 :
至於項目選取之後所觸發的事件與處理方式就和 ListBox 一模一樣了。如果你不熟悉的話, 可以參考以下的程式範例:
private void lp_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
wawa wa = (wawa)lp.SelectedItem;
MessageBox.Show(wa.Name);
}
接著, 我要繼續介紹 Control Toolkit 裡面另一個好用的控制項 DatePicker。
DatePicker 在使用上其實非常的簡單, 簡單到根本無需介紹。你只要把控制項拉進去就可了, 在 XAML 裡面會自動產生如下的碼:
<toolkit:DatePicker HorizontalAlignment="Left" Margin="148,108,0,0" Name="datePicker1" VerticalAlignment="Top" Height="74" />
不過當你拿去使用之後, 就會遇到問題了。因為在日期選取畫面中, Application Bar 會自動跑出來, 它有兩個按鈕, 左邊是「確定」, 右邊是「取消」。麻煩的是這兩個按鈕都沒有文字, 也沒有圖, 而只是兩個大肉包。
要怎麼把圖補上去呢? 首先, 你必須在你自己的電腦裡面找到 WP7 Icons Pack :
當你安裝好 WP7 的 Developer Tool 之後, 這些圖就已經存在你的電腦裡了, 路徑是 %ProgramFiles (x86)%\Microsoft SDKs\Windows Phone\v7.0\Icons 。在此資料夾中你可以找到 dark 跟 light 兩個子資料夾, 裡面分別存放適用黑底或白底的 icons。我們現在需要的是 appbar.check.rest.png 和 appbar.cancel.rest.png 兩個檔案 (我的畫面是黑底的, 所以要從 dark 子目錄選出來), 然後在 VS2010 的方案總管中, 在專案裡新建一個名為 Toolkit.Content 的子目錄, 把這兩個圖檔拷貝過去, 然後把它們分別重新命名為 ApplicationBar.Check.png 跟 ApplicationBar.Cancel.png 即可。
然後我們不需要再做什麼事, 這兩個圖案就會自動出現在應該出現的地方了。