マウス利用時に FlipView の左右に表示されるナビゲーションボタン
タッチ操作時には表示されないのですが、フリックでページめくりができることが気づかれないこともあるのでこのボタンを常時表示したい
ということで作ってみたのがカスタマイズした FlipView
<Style TargetType="ctrl:NavigationButtonAlwaysShowFlipView"> <Setter Property="Background" Value="Transparent" /> <Setter Property="BorderThickness" Value="0" /> <Setter Property="TabNavigation" Value="Once" /> <Setter Property="IsTabStop" Value="False" /> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" /> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" /> <Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="False" /> <Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="False" /> <Setter Property="ScrollViewer.IsHorizontalScrollChainingEnabled" Value="True" /> <Setter Property="ScrollViewer.IsVerticalScrollChainingEnabled" Value="True" /> <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" /> <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" /> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <VirtualizingStackPanel AreScrollSnapPointsRegular="True" Orientation="Horizontal" /> </ItemsPanelTemplate> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ctrl:NavigationButtonAlwaysShowFlipView"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Focused"> <Storyboard> <DoubleAnimation Duration="0" Storyboard.TargetName="FocusVisualWhite" Storyboard.TargetProperty="Opacity" To="1" /> <DoubleAnimation Duration="0" Storyboard.TargetName="FocusVisualBlack" Storyboard.TargetProperty="Opacity" To="1" /> </Storyboard> </VisualState> <VisualState x:Name="Unfocused" /> <VisualState x:Name="PointerFocused" /> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border Margin="3" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Border.Resources> <ControlTemplate x:Key="HorizontalNextTemplate" TargetType="Button"> <Border x:Name="Root" Background="{ThemeResource FlipViewButtonBackgroundThemeBrush}" BorderBrush="{ThemeResource FlipViewButtonBorderThemeBrush}" BorderThickness="{ThemeResource FlipViewButtonBorderThemeThickness}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Path x:Name="Arrow" Width="9.67" Height="10.94" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M4.12,0 L9.67,5.47 L4.12,10.94 L0,10.88 L5.56,5.47 L0,0.06 z" Fill="{ThemeResource FlipViewButtonForegroundThemeBrush}" Stretch="Fill" UseLayoutRounding="False" /> </Border> </ControlTemplate> <ControlTemplate x:Key="HorizontalPreviousTemplate" TargetType="Button"> <Border x:Name="Root" Background="{ThemeResource FlipViewButtonBackgroundThemeBrush}" BorderBrush="{ThemeResource FlipViewButtonBorderThemeBrush}" BorderThickness="{ThemeResource FlipViewButtonBorderThemeThickness}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Path x:Name="Arrow" Width="9.67" Height="10.94" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M5.55,0 L9.67,0.06 L4.12,5.47 L9.67,10.88 L5.55,10.94 L0,5.48 z" Fill="{ThemeResource FlipViewButtonForegroundThemeBrush}" Stretch="Fill" UseLayoutRounding="False" /> </Border> </ControlTemplate> <ControlTemplate x:Key="VerticalNextTemplate" TargetType="Button"> <Border x:Name="Root" Background="{ThemeResource FlipViewButtonBackgroundThemeBrush}" BorderBrush="{ThemeResource FlipViewButtonBorderThemeBrush}" BorderThickness="{ThemeResource FlipViewButtonBorderThemeThickness}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Path x:Name="Arrow" Width="10.94" Height="9.67" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M0.06,0 L5.47,5.56 L10.88,0 L10.94,4.12 L5.48,9.67 L0,4.12 z" Fill="{ThemeResource FlipViewButtonForegroundThemeBrush}" Stretch="Fill" UseLayoutRounding="False" /> </Border> </ControlTemplate> <ControlTemplate x:Key="VerticalPreviousTemplate" TargetType="Button"> <Border x:Name="Root" Background="{ThemeResource FlipViewButtonBackgroundThemeBrush}" BorderBrush="{ThemeResource FlipViewButtonBorderThemeBrush}" BorderThickness="{ThemeResource FlipViewButtonBorderThemeThickness}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPointerOverForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBackgroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Root" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedBorderThemeBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Arrow" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource FlipViewButtonPressedForegroundThemeBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Path x:Name="Arrow" Width="10.94" Height="9.67" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M5.63,0 L11.11,5.55 L11.05,9.67 L5.64,4.12 L0.23,9.67 L0.17,5.55 z" Fill="{ThemeResource FlipViewButtonForegroundThemeBrush}" Stretch="Fill" UseLayoutRounding="False" /> </Border> </ControlTemplate> </Border.Resources> <Grid> <ScrollViewer x:Name="ScrollingHost" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalSnapPointsType="MandatorySingle" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsTabStop="False" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" VerticalSnapPointsType="MandatorySingle" ZoomMode="Disabled"> <ItemsPresenter /> </ScrollViewer> <Grid IsHitTestVisible="False" Opacity="0"> <Button x:Name="PreviousButtonHorizontal" Width="70" Height="40" HorizontalAlignment="Left" VerticalAlignment="Center" IsTabStop="False" Template="{ThemeResource HorizontalPreviousTemplate}" /> <Button x:Name="NextButtonHorizontal" Width="70" Height="40" HorizontalAlignment="Right" VerticalAlignment="Center" IsTabStop="False" Template="{StaticResource HorizontalNextTemplate}" /> <Button x:Name="PreviousButtonVertical" Width="70" Height="40" HorizontalAlignment="Center" VerticalAlignment="Top" IsTabStop="False" Template="{StaticResource VerticalPreviousTemplate}" /> <Button x:Name="NextButtonVertical" Width="70" Height="40" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsTabStop="False" Template="{StaticResource VerticalNextTemplate}" /> </Grid> <Button x:Name="AlwaysShowPreviousButtonHorizontal" Width="70" Height="40" HorizontalAlignment="Left" VerticalAlignment="Center" IsTabStop="False" Template="{ThemeResource HorizontalPreviousTemplate}" Visibility="{Binding Visibility, ElementName=PreviousButtonHorizontal, RelativeSource={RelativeSource Mode=TemplatedParent}}" /> <Button x:Name="AlwaysShowNextButtonHorizontal" Width="70" Height="40" HorizontalAlignment="Right" VerticalAlignment="Center" IsTabStop="False" Template="{StaticResource HorizontalNextTemplate}" Visibility="{Binding Visibility, ElementName=NextButtonHorizontal, RelativeSource={RelativeSource Mode=TemplatedParent}}" /> </Grid> </Border> <Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1" StrokeDashOffset="1.5" StrokeEndLineCap="Square" /> <Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1" StrokeDashOffset="0.5" StrokeEndLineCap="Square" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
ただ単に本来のナビゲーションボタンとは別に Hosizontal のナビゲーションボタンを追加しただけ!
/// <summary> /// ナビゲーションボタンを常に表示する FlipView /// </summary> [TemplatePart(Name = "AlwaysShowPreviousButtonHorizontal", Type = typeof(Button))] [TemplatePart(Name = "AlwaysShowNextButtonHorizontal", Type = typeof(Button))] public class NavigationButtonAlwaysShowFlipView : FlipView { #region Privates /// <summary> /// 次へボタン /// </summary> private Button nextButton; /// <summary> /// 前へボタン /// </summary> private Button prevButton; #endregion //Privates /// <summary> /// コンストラクタ /// </summary> public NavigationButtonAlwaysShowFlipView() : base() { this.DefaultStyleKey = typeof(NavigationButtonAlwaysShowFlipView); this.Loaded += this.OnLoaded; } /// <summary> /// 読み込み完了イベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnLoaded(object sender, RoutedEventArgs e) { this.nextButton = this.GetTemplateChild("AlwaysShowNextButtonHorizontal") as Button; if (this.nextButton != null) { this.nextButton.Click += this.OnNextClick; } this.prevButton = this.GetTemplateChild("AlwaysShowPreviousButtonHorizontal") as Button; if (this.prevButton != null) { this.prevButton.Click += this.OnPrevClick; } this.UpdateNavigationButtonState(); this.SelectionChanged += this.OnSelectionChanged; } /// <summary> /// 選択アイテム更新イベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) { this.UpdateNavigationButtonState(); } /// <summary> /// アイテム情報更新イベントハンドラ /// </summary> /// <param name="e">イベント引数</param> protected override void OnItemsChanged(object e) { base.OnItemsChanged(e); this.UpdateNavigationButtonState(); } /// <summary> /// 前へボタンクリックイベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnPrevClick(object sender, RoutedEventArgs e) { this.SelectedIndex--; this.UpdateNavigationButtonState(); } /// <summary> /// 次へボタンクリックイベントハンドラ /// </summary> /// <param name="sender">イベント発行者</param> /// <param name="e">イベント引数</param> private void OnNextClick(object sender, RoutedEventArgs e) { this.SelectedIndex++; this.UpdateNavigationButtonState(); } /// <summary> /// ナビゲーションボタンの表示状態更新 /// </summary> private void UpdateNavigationButtonState() { if (this.nextButton != null) { if (this.Items == null || this.Items.Count < 1 || this.Items.Count <= this.SelectedIndex + 1) { this.nextButton.Visibility = Visibility.Collapsed; } else { this.nextButton.Visibility = Visibility.Visible; } } if (this.prevButton != null) { if (this.Items == null || this.Items.Count < 1 || this.SelectedIndex < 1) { this.prevButton.Visibility = Visibility.Collapsed; } else { this.prevButton.Visibility = Visibility.Visible; } } } /// <summary> /// 子要素を破棄する /// </summary> protected override void OnDisconnectVisualChildren() { this.Loaded -= this.OnLoaded; this.SelectionChanged -= this.OnSelectionChanged; if (this.nextButton != null) { this.nextButton.Click -= this.OnNextClick; } if (this.prevButton != null) { this.prevButton.Click -= this.OnPrevClick; } base.OnDisconnectVisualChildren(); } }
これでできました
同じ問題で困っている人はいるのに意外と解決策は提案されていませんでした・・・なぜ?!