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”

详细信息请参考文章: http://blogs.msdn.com/b/slmperf/archive/2011/06/13/off-thread-decoding-of-images-on-mango-how-it-impacts-you-application.aspx 

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  运行效果一样,下图显示两中做法的共同效果

 

可以看出两种做法的运行结果完全一样,但是数据结构比较复杂时第二种做法就提现了缓存的优势。

 

posted @ 2012-06-14 15:06  vvGO  阅读(834)  评论(1编辑  收藏  举报