6 August 2011 0 Comments

WP7.5 でリストボックスのスクロールエンドで圧縮されるときのイベントを取る

Windows Phone のリストボックスでは、上下にスクロールしたのち端まで行くと一瞬圧縮されます。アプリケーションによってはこれをトリガーにしているアプリケーションもあります。 Windows Phone 7.5(Mango)では、この瞬間を(直接ではないですが)イベントとして取得する事ができます。 ■Mangoにはスクロール圧縮が状態定義されている! からくりを一言でいうと、Windows Phone 7.5(Mango)では、ScrollViewerのVisualStateに"Scrolling"や"NotScrolling"以外に、以下のVisualStateが定義されているのです。 VerticalCompression VisualStateGroup CompressionTop CompressionBottom NoVerticalCompression HorizontalCompression VisualStateグループ CompressionLeft CompressionRight NoHorizontalCompression つまり、このVisualStateGroupの変化を取得し、その時の状態を確認してみればスクロールエンドの状態を取得する事ができるのです。 そして、 ListboxはVisualTreeを紐解けば(中の構造を開いてみると)ScrollViewer が使われています。 ですから、Listboxのスクロールエンドの状態ももちろん取り出すことができます。 ■処理の流れ 手順はこんな感じ VisualStateが把握できるよう再定義 ListboxからScrollViewerを取り出す ScrollViewerからVisualStateGroupを取り出す VisualStateGroupの変化に対するイベントを取得(CurrentStateChanging) VisualStateの状態を見て必要なState(例 CompressionTop)に合わせて処理を実行する という感じ。   ■実装してみよう まずは新しくプロジェクトを作ってみます。DataBound Application が簡単でしょうね。 ① VisualStateの再定義 そして、MainPage.Xaml の17行目あたりに以下のVisualStateの再定義コードを追加(1) 複雑に見えますが、デフォルトのScrollViewerとの定義の違いは青い部分だけ。 <phone:PhoneApplicationPage.Resources>     <Style TargetType="ScrollViewer">         <Setter Property="VerticalScrollBarVisibility" Value="Auto"/>         <Setter Property="HorizontalScrollBarVisibility" Value="Disabled"/>         <Setter Property="Background" Value="Transparent"/>         <Setter Property="Padding" Value="0"/>         <Setter Property="BorderThickness" Value="0"/>         <Setter Property="BorderBrush" Value="Transparent"/>         <Setter Property="Template">             <Setter.Value>                 <ControlTemplate TargetType="ScrollViewer">                     <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">                         <VisualStateManager.VisualStateGroups>                             <VisualStateGroup x:Name="ScrollStates">                                 <VisualStateGroup.Transitions>                                     <VisualTransition GeneratedDuration="00:00:00.5"/>                                 </VisualStateGroup.Transitions>                                 <VisualState x:Name="Scrolling">                                     <Storyboard>                                         <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VerticalScrollBar"/>                                         <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="HorizontalScrollBar"/>                                     </Storyboard>                                 </VisualState>                                 <VisualState x:Name="NotScrolling"/>                             </VisualStateGroup>                             <VisualStateGroup x:Name="VerticalCompression">                                 <VisualState x:Name="NoVerticalCompression"/>                                 <VisualState x:Name="CompressionTop"/>                                 <VisualState x:Name="CompressionBottom"/>                             </VisualStateGroup>                             <VisualStateGroup x:Name="HorizontalCompression">                                 <VisualState x:Name="NoHorizontalCompression"/>                                 <VisualState x:Name="CompressionLeft"/>                                 <VisualState x:Name="CompressionRight"/>                             </VisualStateGroup>                         </VisualStateManager.VisualStateGroups>                         <Grid Margin="{TemplateBinding Padding}">                             <ScrollContentPresenter x:Name="ScrollContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}"/>                             <ScrollBar x:Name="VerticalScrollBar" HorizontalAlignment="Right" Height="Auto" IsHitTestVisible="False" IsTabStop="False" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Opacity="0" Orientation="Vertical" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{TemplateBinding VerticalOffset}" ViewportSize="{TemplateBinding ViewportHeight}" VerticalAlignment="Stretch" Width="5"/>                             <ScrollBar x:Name="HorizontalScrollBar" HorizontalAlignment="Stretch" Height="5" IsHitTestVisible="False" IsTabStop="False" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Opacity="0" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{TemplateBinding HorizontalOffset}" ViewportSize="{TemplateBinding ViewportWidth}" VerticalAlignment="Bottom" Width="Auto"/>                         </Grid>                     </Border>                 </ControlTemplate>             </Setter.Value>         </Setter>     </Style> </phone:PhoneApplicationPage.Resources>   ② VisualStateの変化をハンドリング 続けて、MainPage.xaml.cs に、ListboxからScrollViewerを取り出し、その中のVisualStateの変化をハンドリングする関数を追加 private void ListBoxCompressionHandling(ListBox targetlistbox) {     VisualStateGroup vgroup = new VisualStateGroup();     // ListBox の初めに定義されている ScrollViewerを取り出す     ScrollViewer ListboxScrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(targetlistbox, 0);     // Visual State はコントロールテンプレートの常に最上位に定義されている     FrameworkElement element = (FrameworkElement)VisualTreeHelper.GetChild(ListboxScrollViewer, 0);     // Visual State を取り出しその中から 縦横Compression のVisualStateを取り出す     foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(element))         if (group.Name == "VerticalCompression") vgroup = group;     //縦横Compressionの状態が変わった時のイベントハンドラ     vgroup.CurrentStateChanging += new EventHandler<VisualStateChangedEventArgs>(ScrollViewer_CurrentStateChanging); } ③ イベント発生時の処理はご自由に♪ void ScrollViewer_CurrentStateChanging(object sender, VisualStateChangedEventArgs e) {     ApplicationTitle.Text = e.NewState.Name; //switch (e.NewState.Name) //{ //    case "CompressionTop": //        break; //    case "CompressionBottom": //        break; //    case "NoVerticalCompression": //        break; //    default: //        break; //} }   ④ Listboxとの紐づけ 最後に、おなじく、MainPage.xaml.cs の中の MainPage_Loaded イベントの中で、リストボックスをハンドリングするように、作成した関数を呼ぶ。 private void MainPage_Loaded(object sender, RoutedEventArgs e) { :     ListBoxCompressionHandling(MainListBox); }   ■まとめ 以上で完了です。Xamlの定義と、ListBoxCompressionHandling 関数だけコピペして使えば、簡単に利用できますし、ScrollViewerで使えば、縦以外に横のスクロールエンドも定義できます。

Continued here: 
WP7.5 でリストボックスのスクロールエンドで圧縮されるときのイベントを取る

If you liked this post, buy me a Coffee.

Leave a Reply