Observable 示例之 Windows Phone 列表内项目逐个加载

 

在写 Windows phone 应用性能优化(一)的时候,在 ListBox 的项加载的时候,添加了一些简单的动画。

其实在 Windows Phone 的应用中使用 Blend 设计动画是很容易的,并且在程序的交互中,增加一些动画

效果,用户会感觉用户体验非常的好,从而提升了用户对应用的印象评分。

 

本文的 demo 演示如何逐项的加载列表中的每一项。对于延时迭代加载列表中的项,通常会考虑使用 DispatherTimer,

但是如果设计的逻辑较多,需要的代码量会比较多,并且不好维护。这里使用 Rx(Reactive Extensions) 中的

Observable 类进行对 IObservable<T> 的创建。在 Rx 中 IObservable<T> (可观察序列)和 IObserver<T> (观察者)

是两个核心的元素,我研究了一段时间,感觉它在  .NET 平台是可以大有作为的,它的使用并不难,很多操作使用是以 LINQ

的扩展方法而使用的,重点是理解 (IObservable)的 “推”数据 和 (IEnumerable)的 “拉”数据的 数据源数据流向的不同。

以后还会继续研究的。之前翻译的有关 Rx 一篇文章

 

 

 

这个示例在页面中使用一个 Pivot 控件,两个 PivotItem 项都是使用 ListBox 作为模版,区别是:

1)第一个 PivotItem 项中的 ItemsPanel 模版使用默认的,在第二个 PivotItem 中

的 ListBox 中, 把 ItemsPanel 设置为了 WrapPanel,从而使 Item 可以流动布局:

 <ListBox ItemsSource="{Binding}" >

     <ListBox.ItemsPanel>

         <ItemsPanelTemplate>

             <Controls:WrapPanel />

         </ItemsPanelTemplate>

     </ListBox.ItemsPanel>


2)两个 ListBox 中的 ItemTemplate 中的 StackPanel 在触发 Loaded 事件时,开始的动画不同。

 

MainPage 页面中 Pivot 控件的全部代码:

    <phone:Pivot SelectionChanged="Pivot_SelectionChanged">

            <phone:PivotItem  Header="Stack">

                <ListBox ItemsSource="{Binding}" >

                    <ListBox.ItemTemplate>

                        <DataTemplate>

                            <StackPanel x:Name="stack" Orientation="Horizontal" Margin="10,30,0,0">

                                <StackPanel.Triggers>

                                    <EventTrigger RoutedEvent="StackPanel.Loaded">

                                        <BeginStoryboard>

                                            <Storyboard x:Name="Storyboard1">

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="-180"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuinticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="106"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuinticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationZ)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="0"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuinticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="246"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="0">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuinticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="0.4"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="1">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuinticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="0.4"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:3" Value="1">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuinticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                            </Storyboard>

                                        </BeginStoryboard>

                                    </EventTrigger>

                                </StackPanel.Triggers>

                                <StackPanel.RenderTransform>

                                    <CompositeTransform/>

                                </StackPanel.RenderTransform>

                                <StackPanel.Projection>

                                    <PlaneProjection/>

                                </StackPanel.Projection>

                                <Image VerticalAlignment="Top" Source="{Binding Photo}" Width="150"/>

                                <TextBlock Text="{Binding Title}" Width="250" Foreground="Wheat" FontSize="25" Margin="10,0,0,0" TextWrapping="Wrap"/>

                            </StackPanel>

                        </DataTemplate>

                    </ListBox.ItemTemplate>

                </ListBox>

            </phone:PivotItem>

            <phone:PivotItem  Header="Wrap">

                <ListBox ItemsSource="{Binding}" >

                    <ListBox.ItemsPanel>

                        <ItemsPanelTemplate>

                            <Controls:WrapPanel />

                        </ItemsPanelTemplate>

                    </ListBox.ItemsPanel>

                    <ListBox.ItemTemplate>

                        <DataTemplate>

                            <StackPanel x:Name="stack" Orientation="Horizontal" Margin="10,30,0,0">

                                <StackPanel.Triggers>

                                    <EventTrigger RoutedEvent="StackPanel.Loaded">

                                        <BeginStoryboard>

                                            <Storyboard x:Name="Storyboard1">

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="1"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:2" Value="1">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuarticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="stack">

                                                    <EasingDoubleKeyFrame KeyTime="0" Value="96"/>

                                                    <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0">

                                                        <EasingDoubleKeyFrame.EasingFunction>

                                                            <QuarticEase EasingMode="EaseOut"/>

                                                        </EasingDoubleKeyFrame.EasingFunction>

                                                    </EasingDoubleKeyFrame>

                                                </DoubleAnimationUsingKeyFrames>

                                            </Storyboard>

                                        </BeginStoryboard>

                                    </EventTrigger>

                                </StackPanel.Triggers>

                                <StackPanel.Projection>

                                    <PlaneProjection/>

                                </StackPanel.Projection>

                                <Image VerticalAlignment="Top" Source="{Binding Photo}" Width="200"/>

                            </StackPanel>

                        </DataTemplate>

                    </ListBox.ItemTemplate>

                </ListBox>

            </phone:PivotItem>

        </phone:Pivot>
View Code


程序的运行效果:

 

在 MainPage 的 C# 页面的主要代码就不贴出来了,和 Windows phone 应用性能优化(一) 中的代码基本相同。

 

重点的代码,是当 Pivot 触发  Pivot_SelectionChanged 事件的时候,逐项加载 ObservableCollection 集合:

  private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)

  {

      ObservableCollection<News> NewsList2 = new ObservableCollection<News>();

      this.DataContext = NewsList2;



      #region 实现 1

      //IObservable<long> obser = Observable.Interval(TimeSpan.FromSeconds(0.3)).ObserveOnDispatcher();



      //obser.Subscribe((i) =>

      //{

          

      //    NewsList2.Add(NewsList[(int)i]);

      //});

      #endregion





      #region 实现 2



      // 方法含义:

      // GenerateWithTime(初始值, 循环条件, 传递给 Observer‘观察者’的值, 延迟时间, 迭代)

      //

      // 类似于 for循环:for(初始值;循环条件;迭代)

      IObservable<int> source = Observable.GenerateWithTime(0,

          i => i < NewsList.Count,

          i => i,

          i => TimeSpan.FromSeconds(.3),

          i => i + 1);

      

      // 在 Dispather 线程,每次接受 source 传递来的 i 值,即下面的 x

      source.ObserveOnDispatcher().Subscribe(x =>

      {

          NewsList2.Add(NewsList[x]);

          Debug.WriteLine(x);

      });



      #endregion

  }

 

把上面的 Observable.GenerateWithTime(...); 方法可以理解成:

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

  {

      // 当然,Observable 的时间延迟是在异步线程中完成的

      Thread.Sleep(TimeSpan.FromSeconds(.3));



      // 逻辑

  }


 

 

工程 demo 下载

你可能感兴趣的:(windows phone)