上文解决了虚拟化的问题,使得类Grid的多列布局ListBox也能实现虚拟化,可以说性能已经有了飞跃
但我的书中圣在使用过程中,仍然发现滑动起来卡卡的,上文的Demo大家可能注意到,即使是WrapPanel也仅是加载的时候很慢,滑动的时候也是流畅的,本文的内容就是关于ListBoxItem的结构复杂度问题。
注意观察上文的Demo,大家可以发现,ListBox的ItemTemplete非常简单,一个简单的色块加一行文字,这种情况下,排除加载速度,那么滑动性能是我们能接受的,但是,书中圣是这样的情况:
1)使用图片
2)相对复杂的布局
结果就使得列表滑动起来跳帧非常严重
这里有几种解决方案,Alexis有一篇文章很好的总结了几种提高ListBox性能体验的方式:http://www.cnblogs.com/alexis/archive/2011/06/12/2040565.html
经过权衡,我决定采用LazyListBox,但是在使用过程中发现:
1)可能是因为图片的关系,导致简单模板和复杂模板在切换过程中非常生硬
2)只要出发滚动/滑动事件,那么就会重新渲染一次
所以最终令我哭笑不得的是,书中圣使用了该项技术后,体验反而不如原来的。这里要指出的是,如果你是纯文本的项,那么还是可以用LazyListBox的,我并不是否定他,而是说要因地制宜,根据自身的情况选用。
最终只能放弃使用,同时我注意到,当我不使用图片,或者将ListBox的ItemTemplete结构变得简单时,ListBox的性能大幅度提升,所以我决定精简模板结构。
这是原来的模板:
<Grid CacheMode="BitmapCache" Height="200" Margin="{StaticResource PhoneMargin}" Width="190">
<Border Margin="{StaticResource AppMainBookProjectionMargin}" Background="Transparent">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu IsZoomEnabled="False" Opened="ContextMenu_Opened" Closed="ContextMenu_Closed">
<toolkit:MenuItem Header="{Binding Strings.ContextMenuDelete, Source={StaticResource ApplicationResources}}" Click="BookshelfBoxMenuItem_Click_Delete"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="Book_Tapped"/>
</toolkit:GestureService.GestureListener>
<Grid Margin="8,0,0,0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding BookName}"
TextWrapping="Wrap" FontSize="{StaticResource PhoneFontSizeMediumLarge}" d:LayoutOverrides="GridBox" Margin="{StaticResource AppMainBookInfoMargin}"/>
<TextBlock Text="{Binding Author, Converter={StaticResource WriterFotmatConverter}}"
Style="{StaticResource PhoneTextSubtleStyle}" Foreground="{StaticResource PhoneSubtleBrush}" Grid.Row="1" TextAlignment="Right" FontFamily="{StaticResource AppFont}" Margin="{StaticResource AppMainBookInfoHorizontalMargin}" TextWrapping="Wrap"/>
</Grid>
</Border>
<Button x:Name="Bookmark" CacheMode="BitmapCache" Visibility="{Binding Bookmarks.Count, Converter={StaticResource BookmarkVisibilityConverter}}" Style="{StaticResource SimpleButton}" Click="BookmarkButton_Click_Show" FontFamily="{StaticResource AppFont}" Margin="{StaticResource AppMainBookmarkButtonMargin}" HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="{StaticResource AppBookmarkButtonBackground}" BorderBrush="{x:Null}" d:LayoutOverrides="HorizontalAlignment">
<Border Background="{StaticResource AppBookmarkButtonBackground}" Height="80" Width="55" />
</Button>
</Grid>
可以看到其实也不是很复杂,无非就是几个Grid嵌套,这里是改进后的模板:
<Border Background="Transparent">
<Canvas CacheMode="BitmapCache"
Margin="{StaticResource PhoneMargin}"
Height="200" Width="190">
<Rectangle x:Name="Background" CacheMode="BitmapCache" Fill="{StaticResource AppBookSingleBackground}" Height="200" Width="190" StrokeThickness="0"/>
<Button Visibility="{Binding Bookmarks.Count, Converter={StaticResource BookmarkVisibilityConverter}}"
x:Name="Bookmark" CacheMode="BitmapCache"
Style="{StaticResource ButtonStyleForBookmark}"
Background="{StaticResource AppBookmarkButtonBackground}"
Canvas.Left="138" Canvas.Top="96"
Width="50" Height="80"/>
<TextBlock Text="{Binding BookName}"
TextWrapping="Wrap" FontSize="{StaticResource PhoneFontSizeMediumLarge}"
Canvas.Left="20" Canvas.Top="14"
Width="108" Height="147"/>
<Border Height="170" Width="108"
Canvas.Left="20" Canvas.Top="14">
<TextBlock Text="{Binding Author}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneSubtleBrush}"
TextAlignment="Right"
TextWrapping="Wrap"
VerticalAlignment="Bottom"/>
</Border>
<Border Visibility="{Binding ManageState, Converter={StaticResource BookStateConverter}}"
Height="32" Width="32" Background="{StaticResource AppMainBooksStateDeleteBrush}" Canvas.Left="-10" Canvas.Top="-8"/>
</Canvas>
</Border>
变化在于:
1)取消Grid布局,改用Canvas,将嵌套结构尽量拉平,精简复杂度
2)取消对单个Item的手势和右键菜单监听,在ListBox外围放置统一的监听
经过这两个改造,列表在滑动时性能有少许上升,已经跳帧没有那么厉害了
一点小经验,欢迎大侠扔砖头
我的另一个产品博客,关于桌面小工具和Windows Phone 7应用作品的,欢迎访问:http://mohoo.cc