WP7 性能优化系列 (1)
1. Image
默认情况下所有的图片的解码过程都是在UI线程同步进行,所以如果用如下方式显示图片将会阻塞UI线程:
<Image Source=”{Binding ImageUrl}”/>
以上方式UI线程将对图片解码,此过程中UI会一直阻塞直到图片解码结束。
解决方式如下:
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImgUrl}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
这两种显示图片方式在模拟器上验证时,不会对应用产生有明显的效果差别,因为在模拟器中对手机处理器的速度没有模拟
注意:用第二种种方式显示图片时在Blend中会提示“Invalid xaml”
2. ListBox(ItemsControl)
需要在一个集合中显示不同类型的数据时,例如新鲜事、日志、状态等,往往会采用自定集合控件,然后在控件里根据数据类型采用不同的数据模板(具体做法将在错误用法里谈到)。这样的做法最大的影响就是放弃ListBox的缓冲机制,当ListBox发现它缓存的模板不能满足数据的需要时就会放弃缓存,这样做的结果就是只有在列表项Loaded时才匆忙的读取数据、寻找模板、加载到集合容器中,会造成很糟的用户体验。
正确的做法是把需要显示的所有模板放到一个数据模板中,然后使用例如Converter的方式(Converter的系统资源很小)决定显示/隐藏相应的模板。
下面将分别介绍两种做法:
首先准备必要数据:
数据类 A、B (即要显示的不同数据类型), 数据源
private ObservableCollection<object> dataSource = new ObservableCollection<object>(); public ObservableCollection<object> DataSource { get { return dataSource; } set { dataSource = value; if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs("DataSource")); } } } public MainPage() { InitializeComponent(); this.DataContext = this; this.DataSource.Add(new A() { ID = 1, Name = "John", Department = "Product" }); this.DataSource.Add(new B() { Title = "PM", Comment = "this is me" }); this.DataSource.Add(new A() { ID = 1, Name = "John", Department = "Product" }); this.DataSource.Add(new B() { Title = "Dev", Comment = "this is he" }); this.DataSource.Add(new B() { Title = "Designer", Comment = "this is cat" }); this.DataSource.Add(new A() { ID = 1, Name = "John", Department = "Product" }); }
错误用法:
u 在资源中定义不同的样式
<DataTemplate x:Key="Tp1"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> <TextBlock Text="{Binding ID}" Width="50"></TextBlock> <TextBlock Text="{Binding Name}" Margin="0 5" Width="100"></TextBlock> <TextBlock Text="{Binding Department}"></TextBlock> </StackPanel> </DataTemplate> <DataTemplate x:Key="Tp2"> <StackPanel Orientation="Horizontal" > <TextBlock Text="{Binding Title}" Width="100" Foreground="Orange"></TextBlock> <TextBlock Text="{Binding Comment}" Foreground="Orange"></TextBlock> </StackPanel> </DataTemplate>
u 自定义集合控件,并在控件中寻找不同的数据模板
public class MyListBox : ItemsControl { protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { base.PrepareContainerForItemOverride(element, item); var container = (element as ContentPresenter); var tmp = (App.Current as App).Resources["Tp1"] as DataTemplate; if (item is B) { tmp = (App.Current as App).Resources["Tp2"] as DataTemplate; } container.ContentTemplate = tmp; } }
u 使用时没有区别
<ctr:MyListBox ItemsSource="{Binding DataSource}"> <ctr:MyListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"></StackPanel> </ItemsPanelTemplate> </ctr:MyListBox.ItemsPanel> </ctr:MyListBox>
以上就是普通的错误用法。
下面展示正确的做法:
u 在资源中定义数据模板
<DataTemplate x:Key="TP"> <Grid> <StackPanel x:Name="AT" Orientation="Horizontal" HorizontalAlignment="Left" Visibility="{Binding Converter={StaticResource DataTypeToVisibilityConverter}, ConverterParameter=AT}"> <TextBlock Text="{Binding ID}" Width="50"></TextBlock> <TextBlock Text="{Binding Name}" Margin="0 5" Width="100"></TextBlock> <TextBlock Text="{Binding Department}"></TextBlock> </StackPanel> <StackPanel x:Name="BT" Orientation="Horizontal" Visibility="{Binding Converter={StaticResource DataTypeToVisibilityConverter}, ConverterParameter=BT}"> <TextBlock Text="{Binding Title}" Width="100" Foreground="Orange"></TextBlock> <TextBlock Text="{Binding Comment}" Foreground="Orange"></TextBlock> </StackPanel> </Grid> </DataTemplate>
u 做转换器Converter
public class DataTypeToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (null == parameter || value == null) { return Visibility.Collapsed; } if (value is A && "AT".Equals(parameter.ToString())) { return Visibility.Visible; } if (value is B && "BT".Equals(parameter.ToString())) { return Visibility.Visible; } return Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
u 使用时无区别
<ListBox Margin="0 20 0 0" ItemTemplate="{StaticResource TP}" ItemsSource="{Binding DataSource}"></ListBox>
u 运行效果一样,下图显示两中做法的共同效果
可以看出两种做法的运行结果完全一样,但是数据结构比较复杂时第二种做法就提现了缓存的优势。