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