Enter キーを押すと次のコントロールに移動する添付ビヘイビア

はじめに

私が仕事で作成しているアプリケーションの UI では、Enter キーを押すと次のコントロールにフォーカスを移動するコードをよく書きます。昔からそういう仕様みたいなので。

ただ、何度も同じコードを記述するのは面倒です。かといって、その機能のためだけに、新しいコントロールを作るのもイマイチ。

そこで添付ビヘイビアに目を付けました。

添付ビヘイビアについて

添付ビヘイビアとは、添付プロパティを上手く使って、コントロールに機能を後から付ける手法です。

さっそく添付ビヘイビアを作成してみます

using System.Windows;
using System.Windows.Input;

namespace AttachedBehaviorSample
{
    public static class UIElementBehavior
    {
        // 添付プロパティの初期値は false。
        // コールバックを指定しておく。
        public static readonly DependencyProperty EnterCommand = DependencyProperty.RegisterAttached("EnterCommand",
            typeof(bool),
            typeof(UIElementBehavior),
            new UIPropertyMetadata(false, EnterCommandChanged));

        public static bool GetEnterCommand(DependencyObject obj)
        {
            return (bool)obj.GetValue(EnterCommand);
        }

        public static void SetEnterCommand(DependencyObject obj, bool value)
        {
            obj.SetValue(EnterCommand, value);
        }

        // EnterCommand の値が変更されたときに呼び出される。
        // KeyDown イベントハンドラの登録&解除を行う。
        public static void EnterCommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            UIElement element = sender as UIElement;
            if (element == null)
            {
                return;
            }

            if (GetEnterCommand(element))
            {
                element.KeyDown += textBox_KeyDown;
            }
            else
            {
                element.KeyDown -= textBox_KeyDown;
            }
        }

        // Enter キーが押されたら、次のコントロールにフォーカスを移動する
        private static void textBox_KeyDown(object sender, KeyEventArgs e)
        {
            if ((Keyboard.Modifiers == ModifierKeys.None) && (e.Key == Key.Enter))
            {
                UIElement element = sender as UIElement;
                element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
        }
    }
}

添付ビヘイビアを使ってみます

<Window x:Class="AttachedBehaviorSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:AttachedBehaviorSample"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <!-- フォーカスがある TextBox の背景色を変更するスタイル -->
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Background" Value="SkyBlue"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" local:UIElementBehavior.EnterCommand="True"/>
        <TextBox Grid.Row="1" local:UIElementBehavior.EnterCommand="True"/>
        <TextBox Grid.Row="2" local:UIElementBehavior.EnterCommand="True"/>
    </Grid>
</Window>

Window の上に配置した TextBox 全てに設定。フォーカスがあるコントロールが一目で分かるよう、トリガーで背景色を変更するようにしています。

作成したサンプルの実行画面

f:id:griefworker:20090811203123p:image

Enter キーを押すと

f:id:griefworker:20090811203118p:image

下の TextBox に移動します。

まとめ

何度も記述するのは面倒、かといってカスタムコントロールを作るまでもない。そんな「ちょっとした機能」を使いまわせるよう実装するのに、添付ビヘイビアは適してると思います。

添付ビヘイビアって便利!