スマートフォンでSNS系のアプリを使っていて 「更新ボタン」を押しているとなんとなく未来感がない。 Twitterの公式アプリ等はそうだが、上側に引っ張るとリストが更新される。 WindowsPhoneでもこれを行なってみようと思ったら 高橋忍氏のブログや その書籍プログラミングWindowsPhoneでも紹介されています。 んじゃ書く必要ないじゃん。と思いましたけど少し書いてみます。 ListBoxの中身はScrollViewerで構成されているので、 ScrollViewerのVerticalCompressionというVisualStateGroupを利用して ListBoxの状態を把握しようってことですね。 上記のブログにはPageごとの設定とありますけど 私的にはアプリケーション内で指定したいのでApp.xmlにApplication.Resoucesとして定義しています。<Application.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="1"/> <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> </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> </Application.Resources>この記述によって、アプリケーションのすべてのScrollViewerで圧縮した場合のイベントの発生が可能になります。 ※私には縦の必要がないのでVerticalのみです。 上記ブログにある通り(そのままのコード)ListBoxからScrollViewerを取り出して 変更があったというイベントに登録します。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) { switch (e.NewState.Name) { case "CompressionTop": break; case "CompressionBottom": break; case "NoVerticalCompression": break; default: break; } }で、この関数をLoadなどのイベントで呼び出すのですが Loadは何度も呼び出されるので、画面遷移が多いような画面だったら重複して登録してしまうので 一度だけ登録するようにしておくのが良いでしょう。 これだと高橋忍氏のブログそのまま(アプリで登録した位の違い)です。 私的にはスクロールを「グッ」とした時にだけ、更新をしたいのです。 このままだと少しでも上にするだけでイベントが発生します。 んじゃ、圧縮イベントと圧縮が終わったイベントの時刻で処理してみよう!DateTime startTopTime = new DateTime(0); DateTime startBottomTime = new DateTime(0); DateTime endTime = new DateTime(0); private void InitCompression() { startTopTime = new DateTime(0); startBottomTime = new DateTime(0); endTime = new DateTime(0); } private Boolean IsCompressionTop() { if (!startTopTime.Equals(new DateTime(0))) { TimeSpan ts = endTime.Subtract(startTopTime); System.Diagnostics.Debug.WriteLine(ts.TotalSeconds); if (ts.TotalSeconds >= 0.9) { return true; } } return false; } void ScrollViewer_CurrentStateChanging(object sender, VisualStateChangedEventArgs e) { switch (e.NewState.Name) { case "CompressionTop": startTopTime = DateTime.Now; break; case "CompressionBottom": startBottomTime = DateTime.Now; break; case "NoVerticalCompression": endTime = DateTime.Now; if (IsCompressionTop()) { MessageBox.Show("できたよー"); } InitCompression(); break; default: break; } }こうしてみると、確かにグッとした後にイベント発生ができるんだけど リストを離して戻った時の判定になってしまう。 できれば、グッとしている間にイベントを発生したい。 。。。もっといい方法があるような気がする。
2011年12月5日月曜日
リストボックスを引っ張って更新
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿