天天看點

Silverlight執行個體秀——可切換視圖的DataTemplate(做網站必備技術)

小序:

靈活開發也是要有個度的。搞靈活,最起碼的限度是程式員要對手裡使用的工具比較精通。

相信大家都見過這個場景:

問:“你在做什麼?”

程式員:“我在靈活開發。”

問:“這樣設計不對吧……”

程式員:“沒事兒,我可以重構!”

拜托,手裡使用的工具都不了解,程式中到處都是詭異的方法……怎麼重構?天生就是一恐龍,再怎麼重構也變不成人呀!這時候,唯一能做的就是——重寫。

正文:

今天的例子就是一個由錯誤程式重寫而來的結果。至于那個錯誤程式,下周我将另寫一文《WPF的典型誤用》。

客戶的需求是這樣的:要求用Silverlight寫一個留言闆,打開界面後,可以看到一個留言清單,每條留言隻顯示标題、發言人和發言時間。每條留言有一個切換按鈕,可以顯示和隐藏留言的詳細資訊。

實作這個功能很簡單。用一個ListBox加上一個DataTemplate就搞定了。這裡着重提示一句:DataTemplate就是“資料的外衣”,隻有了解了DataTemplate才能明白WPF的精髓——資料驅動UI,也才能可能準确地使用MVVM模式。

下面讓我們看代碼。

頁面的設計很簡單——Title和ListBox。Load按鈕用來加載模拟資料。模拟資料的類型是自定義類Message。

<UserControl x:Class="SilverlightApplicationBBS.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

    Width="600" Height="366">

    <StackPanel x:Name="LayoutRoot" Background="LightBlue">

        <!--Title-->

        <StackPanel Orientation="Horizontal">

            <TextBlock Text="Silverlight Mini BBS" FontSize="24" Margin="5" VerticalAlignment="Bottom"/>

            <TextBlock Text="Powered by: 水之真谛" Width="200"  VerticalAlignment="Bottom" Margin="10"/>

            <Button Content="Load"  Height="23" Width="75" VerticalAlignment="Bottom" Margin="10" Click="LoadButton_Click" />

        </StackPanel>

        <!--Content-->

        <ListBox x:Name="listBox" Margin="10" Height="300" />

    </StackPanel>

</UserControl>

自定義Message類:

    public class Message

    {

        public string Title { get; set; }

        public string OpenedBy { get; set; }

        public string OpenTime { get; set; }

        public string Content { get; set; }

    }

運作起來是這樣:

讓我們看看Load按鈕的Click事件處理器:

        private void LoadButton_Click(object sender, RoutedEventArgs e)

        {

            // 造些假資料。項目中資料來自資料庫

            List<Message> msgList = new List<Message>();

            for (int i = 0; i < 30; i++)

            {

                Message msg = new Message()

                {

                    Title = "Message Title " + i.ToString(),

                    OpenedBy = (i % 2 == 0) ? "Tom" : "Tim",

                    OpenTime = DateTime.Now.ToShortDateString(),

                    Content = (i % 2 == 0) ? "水之真谛" : @"http://blog.csdn.net/FantasiaX"

                };

                msgList.Add(msg);

            }

            this.listBox.ItemsSource = msgList;

        }

點選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代碼:

    <UserControl.Resources>

        <!--DataTemplate-->

        <DataTemplate x:Key="messageTemplate">

            <StackPanel>

                <StackPanel Orientation="Horizontal" Height="23">

                    <TextBlock Text="Title:" Width="40" VerticalAlignment="Center" />

                    <TextBox Text="{Binding Path=Title}" Width="180"/>

                    <TextBlock Text="By:" Width="30" VerticalAlignment="Center" />

                    <TextBox Text="{Binding Path=OpenedBy}" Width="80"/>

                    <TextBlock Text="At:" Width="30" VerticalAlignment="Center" />

                    <TextBox Text="{Binding Path=OpenTime}" Width="80"/>

                    <Button Content="Switch" Width="75" Margin="20, 0,0 0" Click="Button_Click"/>

                </StackPanel>

                <StackPanel x:Name="detailPanel" Orientation="Horizontal" Height="60" Visibility="Collapsed">

                    <TextBox Margin="40,5,10,5" Text="{Binding Path=Content}" Width="400"/>

            </StackPanel>

        </DataTemplate>

    </UserControl.Resources>

        <ListBox x:Name="listBox" Margin="10" Height="300" ItemTemplate="{StaticResource messageTemplate}"/>

點選Load,這回看到的界面就對了!

然後嘗試點選每個Switch按鈕——視圖能夠切換:

這一點是怎麼做到的呢?

原來,秘密是在DataTemplate裡Switch按鈕的處理函數中:

        // 切換視圖

        private void Button_Click(object sender, RoutedEventArgs e)

            // Silverlight裡的VisualTreeHelper功能受限,是以隻能這樣做。WPF裡的就友善多了。

            Button b = sender as Button;

            StackPanel p = VisualTreeHelper.GetParent(b) as StackPanel;

            p = VisualTreeHelper.GetParent(p) as StackPanel;

            p = p.FindName("detailPanel") as StackPanel;

            if (p.Visibility == Visibility.Collapsed)

                p.Visibility = Visibility.Visible;

            else

                p.Visibility = Visibility.Collapsed;

隻是Silverlight為了“減肥”,把很多VisualTreeHelper的功能都給砍了,這樣我們就隻能手動地去找到需要顯示/隐藏的UI元素了。

你可能會問:那麼多記錄,每條上都有一個Switch按鈕,是不是需要寫一個循環,把它們的Click事件與Button_Click函數關聯起來呀?

答案是:No!當你把一列資料指派給ListBox.ItemsSource時,ListBox會按照自己的ItemTemplate(即我們設計的DataTemplate)逐個處理自己的Item。

到此,功能就已經實作了。如果覺得UI不是很漂亮,那就交給我們的designer,他們會給整個程式穿上漂亮的外衣。

下面的圖是我請團隊主力設計師之一Owen進行美化後的結果,請大家欣賞!

本文轉自 水之真谛 51CTO部落格,原文連結:http://blog.51cto.com/liutiemeng/121346,如需轉載請自行聯系原作者

繼續閱讀