Windows Phone 7 - ListBox學習心得 - 自訂ItemTemplate與處理多資料lag問題

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. 顯示結果;

       2222

以上是針對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

As the platform evolves, so do the workarounds [Better SetterValueBindingHelper makes Silverlight Setters better-er!]

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入门开发问答三十则

Listbox – ScrollViewer performance improvement for Mango and how it impacts your existing application? (必讀)

http://zh.blog.plurk.com/archives/250