Windows Phone 7 - ListBox學習心得 - 自訂ItemTemplate與處理多資料lag問題
為什麼會寫這一篇文章呢,主要是要幫忙把自己對於Silverlight學習過程中對Binding這件事做一個簡單的概念說明,
因為我過去太過於習慣動態使用自己的Code去產生畫面的內容,包括繪製線條、拉動控件、動態配置版面等等,造成
我對一些控件的基礎使用有些衝突。
本篇只要介紹二個我所遇到的問題,分別為:
(1) 透過ListBox的Bing後,ListItem中使用TextBlock的被選取時,沒有辦法變成手機預設的選擇色系;
針對這個問題,主要原因在於使用的TextBlock本身有自定的Foreground Color,造成今天透過ListBoxItem的色系在加上時,
以「Css設定屬性的觀念:愈靠近實體的設定才是有效用的(attribute>class)」來看,這樣是原理的。因此,為了解決這樣的問題,
就要使用自訂的Style去修改ListBoxItem中TextBlock的Foreground Color了。
根據參考來源:<Accent Colors for Styled TextBlocks in WP7 Selected ListBoxItems>的說明,讓我規納出以上的原由,接下來,
就直接透過程式碼與XAML檔的來加以說明如何做到:
1-1. 針對TextBlock在當天的Page或UserControl中,自訂一個新的Style;(以下用UserControl為例)
1: <UserControl.Resources>
2: <Style x:Key="PhoneTextBlockBaseWithoudForeground"
3: TargetType="TextBlock">
4: <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiLight}"/>
5: <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeLarge}"/>
6: <!-- 註解掉Foreground的Style,讓它可以套用ListBoxItem的Style -->
7: <!--<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}" />-->
8: </Style>
9: </UserControl.Resources>
1-2. 在ListBox建立ListBox.ItemTemplate,並指定1.1設定的Style Name;
1: <ListBox Width="410" Height="Auto" HorizontalAlignment="Left"
2: Name="lstStations" VerticalAlignment="Top" SelectionChanged="BusItemSelectionChanged">
3: <ListBox.ItemTemplate>
4: <DataTemplate>
5: <Grid Background="{StaticResource PhoneChromeBrush}" Margin="5">
6: <StackPanel HorizontalAlignment="Left" VerticalAlignment="Center" Width="390" Margin="5,0,0,0">
7: <!-- 使用Data binding並配合上述定義的Style: PhoneTextBlockBaseWithoudForeground -->
8: <TextBlock Text="{Binding BusName}"
9: Style="{StaticResource PhoneTextBlockBaseWithoudForeground}"
10: TextWrapping="Wrap" />
11: <TextBlock Text="{Binding BusValue}"
12: Visibility="Collapsed"></TextBlock>
13: </StackPanel>
14: </Grid>
15: </DataTemplate>
16: </ListBox.ItemTemplate>
17: </ListBox>
1.3. ListBoxItem的Data binding;
1.3.1 自訂Data Binding的資料類別:
1: public class BusLineItem
2: {
3: //屬性要與ItemTemplate中Data Binding定義的相同
4: public string BusName { get; set; }
5:
6: public string BusValue { get; set; }
7: }
1.3.2 將資料設定至ListBox中的ItemsSource屬性:
1: //取得資料集合
2: List<BusLineItem> tCollection = tBuslineObject.Single().Value as List<BusLineItem>;
3:
4: ListBox tUCBusLine = new ListBox();
5:
6: //指定資料集合至ItemsSource之中
7: tUCBusLine.ItemsSource = tCollection;
1.4. 顯示結果;
以上是針對ListBoxItem在Data Binding中有TextBlock的時候沒有被選取顏色改變的問題,但這個問題如果你是使用程式碼來產生
自訂的ListBoxItem(例如:利用User Control定義了相同的ListBoxItem控件),也一樣需要透過程式修改Foreground的Brush才能做到喔,
因此,既然可以透過Data Binding的方式,那不妨試看看這樣的做法。
(2) ListBox使用ItemSource匯入資料時,造成畫面停住的問題;
這個問題出現在大量資料匯入至ListBox時,造成整個畫面都不能動,如果你有使用ProgressBar的話,也會出現ProgressBar
停住不會變動的問題。依照WPF Thread的運作原理,因為ListBox是屬性UI Thread所控制,因此,造成ListBox動態加入Item時,
出現畫面Lag的問題也是可以被理解的,但這樣的問題沒有辦法被解決嗎?
事實上是可以,以我目前的例子來說:
「我使用了Panorama元件,裡面使用了多個PanoramaItem,每一個PanoramaItem裡有一個ListBox。當我動態為每一個ListBox
增加大量ListBoxItem時,造成整個畫面都停住了。」這樣原因,即使用了Dispatcher.BeginInvoke()其實還是造成lag的問題,主要在
於同一時間為多個ListBox動態填入大量的資料,造成使用UI Thread執行,也需要花太大的資源來處理。
因此,我的做法是「分散匯入大量ListBoxItem的時機」。做法:讓用戶進入在當前畫面(PanoramaItem)時,才載入ListBoxItem。
好處:這樣可以讓用戶快速進入主程式,並且在進入真正需要的畫面時再載入資料,省掉同時處理大量資料的的問題。
2-1. 結合ListBox的ItemsSource,並且註冊Panorama的SelectionChanged事件:
1: private void pamaCityBus_SelectionChanged(object sender, SelectionChangedEventArgs e)
2: {
3: // 取得目前要匯入的PanoramaItem
4: PanoramaItem tPamaItem = ((Panorama)sender).SelectedItem as PanoramaItem;
5: //使用Dispatcher的方式將畫面產生出來
6: Dispatcher.BeginInvoke(() =>
7: {
8: List<BusLineItem> tCollection = tBuslineObject.Single().Value as List<BusLineItem>;
9: ListBox tUCBusLine = new ListBox();
10: //匯入資料
11: ListBox.ItemsSource = tCollection;
12: //將ListBox加入PanoramaItem的Content中
13: tPamaItem.Content = tUCBusLine;
14: });
15: }
======
以上是分享自己使用ListBox元件時所遇到的問題,我想是因為我對於Silverlight在Data Binding這一段沒有好好學習的關係,
才會造成使用起來一直覺得很不順手,因為必竟在手機開發或是Silverlight上的開發,要求是用戶好的使用體驗,因此,針對
會造成App停止的部分,是需要花時間來好好處理的。
References:
‧Accent Colors for Styled TextBlocks in WP7 Selected ListBoxItems (必讀)
‧Windows Phone Tutorial:ListBox on Windows Phone 7
‧Changing a TextBox Foreground color to its own color when the TextBox is disabled
‧How to set a background image for your Silverlight control (必讀) & Programatically change background
‧SILVERLIGHT - PerformenceProgessBar and ObservableCollection (必讀)
‧PerformenceProgessBar and ObservableCollection (必讀)
‧ListBox and CollectionViewSource
‧WP7有约(三):课堂重点(2) & Windows Phone 7 开发教程汇总 & Windows phone入门开发问答三十则
‧http://zh.blog.plurk.com/archives/250