モチベーション
この記事ではボタンに対するフライアウト操作のアクション数を圧縮する方法について説明します。
ユーザーに求めるアクション数は可能な限り減らせること望ましく、それが頻繁に利用するものであればあるほどユーザーの手間が減ることによる時短効果は大きい。
前提条件
- ボタンに設定したフライアウトを表示して
- フライアウト内の項目を選択変更して
- フライアウトを閉じる
この操作を完了させるにはそのままだと3アクション必要ですが、
これを1クリック以内に完了させたい。
実装方針
ButtonのPointerPressedでフライアウト表示し、フライアウト上の選択項目に対するPointerReleasedで項目選択しフライアウトを非表示にしたい。
課題と対策
ButtonのPointerPressedは反応しない
Clickイベント+ClickMode="Press" を利用する
ButtonのPointerReleasedは反応しない
Clickイベント+ClickMode="Release" を利用したかったが、Pressした状態で DragEnter した場合の PointerRelease が反応しないため別の回避策が必要。
そこで Window.Current.PointerReleased イベントを利用する。
ウィンドウのポインターイベントではクリック位置の要素は PointerEventArgs に含まれないため自前で取得する必要がある。
実装例
<Grid.Resources>
<Flyout x:Name="ImageLayerSelectorFlyout"
Opened="ImageLayerSelectorFlyout_Opened"
Closed="ImageLayerSelectorFlyout_Closed" >
</Flyout>
</Grid.Resources>
<Button x:Name="LayerSelectorButton"
Click="LayerSelectorButton_Click"
ClickMode="Press" >
<!-- 省略 -->
</Button>
private void LayerSelectorButton_Click(object sender, RoutedEventArgs e)
{
ImageLayerSelectorFlyout.ShowAt((FrameworkElement)sender);
}
private void ImageLayerSelectorFlyout_Opened(object sender, object e)
{
Window.Current.CoreWindow.PointerReleased -= OnLayerSelectorButton_CoreWindow_PointerReleased;
Window.Current.CoreWindow.PointerReleased += OnLayerSelectorButton_CoreWindow_PointerReleased;
}
private void ImageLayerSelectorFlyout_Closed(object sender, object e)
{
Window.Current.CoreWindow.PointerReleased -= OnLayerSelectorButton_CoreWindow_PointerReleased;
}
private void OnLayerSelectorButton_CoreWindow_PointerReleased(CoreWindow sender, PointerEventArgs args)
{
Window.Current.CoreWindow.PointerReleased -= OnLayerSelectorButton_CoreWindow_PointerReleased;
var pointerPosition = args.CurrentPoint.Position;
var elements = VisualTreeHelper.FindElementsInHostCoordinates(pointerPosition, ImageLayerSelectorFlyout.Content);
foreach (var item in elements)
{
if (item is ButtonBase button)
{
button.Command.Execute(null);
ImageLayerSelectorFlyout.Hide();
break;
}
}
}