Silverlight實例秀——可切換視圖的DataTemplate(做網站必備技術)

小序:
敏捷開發也是要有個度的。搞敏捷,最起碼的限度是程序員要對手裏使用的工具比較精通。
相信大家都見過這個場景:
問:“你在做什麼?”
程序員:“我在敏捷開發。”
問:“這樣設計不對吧……”
程序員:“沒事兒,我可以重構!”
拜託,手裏使用的工具都不瞭解,程序中到處都是詭異的方法……怎麼重構?天生就是一恐龍,再怎麼重構也變不成人呀!這時候,唯一能做的就是——重寫。
 
正文:
 
今天的例子就是一個由錯誤程序重寫而來的結果。至於那個錯誤程序,下週我將另寫一文《WPF的典型誤用》。
客戶的需求是這樣的:要求用Silverlight寫一個留言板,打開界面後,可以看到一個留言列表,每條留言只顯示標題、發言人和發言時間。每條留言有一個切換按鈕,可以顯示和隱藏留言的詳細信息。
 
實現這個功能很簡單。用一個ListBox加上一個DataTemplate就搞定了。這裏着重提示一句:DataTemplate就是“數據的外衣”,只有理解了DataTemplate才能明白WPF的精髓——數據驅動UI,也才能可能準確地使用MVVM模式。
 
下面讓我們看代碼。
 
頁面的設計很簡單——Title和ListBox。Load按鈕用來加載模擬數據。模擬數據的類型是自定義類Message。
  1. <UserControl x:Class="SilverlightApplicationBBS.Page"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     Width="600" Height="366">
  5.     <StackPanel x:Name="LayoutRoot" Background="LightBlue">
  6.         <!--Title-->
  7.         <StackPanel Orientation="Horizontal">
  8.             <TextBlock Text="Silverlight Mini BBS" FontSize="24" Margin="5" VerticalAlignment="Bottom"/>
  9.             <TextBlock Text="Powered by: 水之真諦" Width="200"  VerticalAlignment="Bottom" Margin="10"/>
  10.             <Button Content="Load"  Height="23" Width="75" VerticalAlignment="Bottom" Margin="10" Click="LoadButton_Click" />
  11.         </StackPanel>
  12.         <!--Content-->
  13.         <ListBox x:Name="listBox" Margin="10" Height="300" />
  14.     </StackPanel>
  15. </UserControl>
自定義Message類:
  1.     public class Message
  2.     {
  3.         public string Title { getset; }
  4.         public string OpenedBy { getset; }
  5.         public string OpenTime { getset; }
  6.         public string Content { getset; }
  7.     }
運行起來是這樣:
 
 
 
讓我們看看Load按鈕的Click事件處理器:
 
  1.         private void LoadButton_Click(object sender, RoutedEventArgs e)
  2.         {
  3.             // 造些假數據。項目中數據來自數據庫
  4.             List<Message> msgList = new List<Message>();
  5.             for (int i = 0; i < 30; i++)
  6.             {
  7.                 Message msg = new Message()
  8.                 {
  9.                     Title = "Message Title " + i.ToString(),
  10.                     OpenedBy = (i % 2 == 0) ? "Tom" : "Tim",
  11.                     OpenTime = DateTime.Now.ToShortDateString(),
  12.                     Content = (i % 2 == 0) ? "水之真諦" : @"http://blog.csdn.net/FantasiaX"
  13.                 };
  14.                 msgList.Add(msg);
  15.             }
  16.             this.listBox.ItemsSource = msgList;
  17.         }
點擊Load後,效果是這樣的:
 
 
咦?怎麼顯示的是數據類型呢?
是啊!你不給數據穿好“衣服”,人家怎麼知道如何show給你呢?
讓我們給Message數據穿上一身合適的衣服!也就是給ListBox配上合適的ItemTemplate。注意:ListBox的Item是Message,而不是ListBoxItem控件。當你把一列Message設置爲ListBox的ItemsSource時,ListBox會自動爲每個Message生成一個容器(ListBoxItem)——WPF中所有ItemsControl都有自己對應的Item容器,比如ListView的Item容器是ListViewItem。特別提醒一點:一個好的數據驅動UI的程序,你完全用不着顯式地爲ItemsControl添加Item容器,如果你發現有這樣的代碼,那八成是沒理解“數據驅動UI”,或者說又拿WPF當WinForm使了
 
這是添加好DataTemplate後的XAML代碼:
  1. <UserControl x:Class="SilverlightApplicationBBS.Page"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     Width="600" Height="366">
  5.     <UserControl.Resources>
  6.         <!--DataTemplate-->
  7.         <DataTemplate x:Key="messageTemplate">
  8.             <StackPanel>
  9.                 <StackPanel Orientation="Horizontal" Height="23">
  10.                     <TextBlock Text="Title:" Width="40" VerticalAlignment="Center" />
  11.                     <TextBox Text="{Binding Path=Title}" Width="180"/>
  12.                     <TextBlock Text="By:" Width="30" VerticalAlignment="Center" />
  13.                     <TextBox Text="{Binding Path=OpenedBy}" Width="80"/>
  14.                     <TextBlock Text="At:" Width="30" VerticalAlignment="Center" />
  15.                     <TextBox Text="{Binding Path=OpenTime}" Width="80"/>
  16.                     <Button Content="Switch" Width="75" Margin="20, 0,0 0" Click="Button_Click"/>
  17.                 </StackPanel>
  18.                 <StackPanel x:Name="detailPanel" Orientation="Horizontal" Height="60" Visibility="Collapsed">
  19.                     <TextBox Margin="40,5,10,5" Text="{Binding Path=Content}" Width="400"/>
  20.                 </StackPanel>
  21.             </StackPanel>
  22.         </DataTemplate>
  23.     </UserControl.Resources>
  24.     <StackPanel x:Name="LayoutRoot" Background="LightBlue">
  25.         <!--Title-->
  26.         <StackPanel Orientation="Horizontal">
  27.             <TextBlock Text="Silverlight Mini BBS" FontSize="24" Margin="5" VerticalAlignment="Bottom"/>
  28.             <TextBlock Text="Powered by: 水之真諦" Width="200"  VerticalAlignment="Bottom" Margin="10"/>
  29.             <Button Content="Load"  Height="23" Width="75" VerticalAlignment="Bottom" Margin="10" Click="LoadButton_Click" />
  30.         </StackPanel>
  31.         <!--Content-->
  32.         <ListBox x:Name="listBox" Margin="10" Height="300" ItemTemplate="{StaticResource messageTemplate}"/>
  33.     </StackPanel>
  34. </UserControl>
點擊Load,這回看到的界面就對了!
 
 
然後嘗試點擊每個Switch按鈕——視圖能夠切換:
 
 
這一點是怎麼做到的呢?
原來,祕密是在DataTemplate裏Switch按鈕的處理函數中:
 
  1.         // 切換視圖
  2.         private void Button_Click(object sender, RoutedEventArgs e)
  3.         {
  4.             // Silverlight裏的VisualTreeHelper功能受限,所以只能這樣做。WPF裏的就方便多了。
  5.             Button b = sender as Button;
  6.             StackPanel p = VisualTreeHelper.GetParent(b) as StackPanel;
  7.             p = VisualTreeHelper.GetParent(p) as StackPanel;
  8.             p = p.FindName("detailPanel"as StackPanel;
  9.             if (p.Visibility == Visibility.Collapsed)
  10.             {
  11.                 p.Visibility = Visibility.Visible;
  12.             }
  13.             else
  14.             {
  15.                 p.Visibility = Visibility.Collapsed;
  16.             }
  17.         }
只是Silverlight爲了“減肥”,把很多VisualTreeHelper的功能都給砍了,這樣我們就只能手動地去找到需要顯示/隱藏的UI元素了。
 
你可能會問:那麼多記錄,每條上都有一個Switch按鈕,是不是需要寫一個循環,把它們的Click事件與Button_Click函數關聯起來呀?
答案是:No!當你把一列數據賦值給ListBox.ItemsSource時,ListBox會按照自己的ItemTemplate(即我們設計的DataTemplate)逐個處理自己的Item。
 
到此,功能就已經實現了。如果覺得UI不是很漂亮,那就交給我們的designer,他們會給整個程序穿上漂亮的外衣。
下面的圖是我請團隊主力設計師之一Owen進行美化後的結果,請大家欣賞!
 
 
 
最後,祝大家週末快樂!(這裏是源碼[url]http://download.csdn.net/source/885340[/url],感謝Tom上傳!)
 
=====================================================
友情鏈接:
Owen同學是我們團隊裏的主力designer之一,我的一些程序就是由Owen同學美化的。謝謝Owen!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章