2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WPFのComboBoxでIsEditable=TrueにするとIsTabStop=Falseにしてもタブストップしてしまう

Last updated at Posted at 2021-02-02

はじめに

WPFで開発をしている時に、コントロールによってタブでフォーカスが移らないようにIsTabStopをFalseにすることがあります。
ところが、ComboBoxでIsTabStopをFalseにしても、IsEditableをTrueにしてしまうと、タブで移動してしまうという現象が発生します。
開発当時、まだWPFを勉強し始めたころは、もうチンプンカンプンで、何が起きているのかわかりませんでした。
とりあえず慌ててググッて、対策を・・・ということをしてきましたが、今なら落ちついて(笑)考察できるようになったので、原因と対策を書き留めておこうと思います。

原因

ComboBoxでIsTabStopを設定した場合、当然ComboBox自体にこのプロパティがセットされるのですが、どうやらIsEditable=Trueにすると、ComboBox内のPART_EditableTextBoxが使用されるみたいです。
この時問題なのが、ComboBoxのControlTemplateで、MicrosoftのComboBox のスタイルとテンプレートをみるとこうなっています。

<TextBox x:Name="PART_EditableTextBox"
                   Style="{x:Null}"
                   Template="{StaticResource ComboBoxTextBox}"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Bottom"
                   Margin="3,3,23,3"
                   Focusable="True"
                   Background="Transparent"
                   Visibility="Hidden"
                   IsReadOnly="{TemplateBinding IsReadOnly}" />

なんと、IsTabStopの項目がないです。
だから、IsEditable=Trueにすると、IsTabStopはもう関係なしということで、何をしても必ずタブが移ってしまいます。

対策1 ControlTemplate

一つ目の対策としては、Window.Resourcesとか、App.xamlでリソースを設定して、ControlTemplateを書きます

//~中略~
<TextBox x:Name="PART_EditableTextBox"
                   Style="{x:Null}"
                   Template="{StaticResource ComboBoxTextBox}"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Bottom"
                   Margin="3,3,23,3"
                   Focusable="True"
                   Background="Transparent"
                   Visibility="Hidden"
                   IsReadOnly="{TemplateBinding IsReadOnly}" 
                   IsTabStop="{Binding IsTabStop, RelativeSource={RelativeSource TemplatedParent}}"/>
//~中略~

でも、これだととにかく長いリソースを書かないといけないのでめんどいです。
以前、他にもいじりたいところがあったので、ComboBoxExというカスタムコントロールを作って、そこでGeneric.xamlにリソースを書いて利用しました。
だけど、本当に面倒でした。また新規に開発するときに・・・と思うと嫌です(~_~;)

対策2 コードビハインド

二つ目の対策としては、コードビハインドに書いてしまうという方法です。
Window_Loadedに以下のようなコードを書きます。

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var textbox = combobox1.Template.FindName("PART_EditableTextBox", combobox1) as TextBox;
            if (textbox != null)
                textbox.IsTabStop = combobox1.IsTabStop;
        }

これで、ComboBoxのIsTabStopと連携して、タブで移動してこなくなります。

対策3 ビヘイビア(Behavior)

最後に、ビヘイビアを作るという方法です。
コードビハインドと同じようなコードでBehaviorを作ります

    public class ComboBoxBehavior : Behavior<ComboBox>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Loaded += AssociatedObjectLoaded;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Loaded -= AssociatedObjectLoaded;
        }
        void AssociatedObjectLoaded(object sender, System.Windows.RoutedEventArgs e)
        {
            ComboBox comboBox = sender as ComboBox;
            var textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox;
            if (textBox == null) return;

            textBox.IsTabStop = comboBox.IsTabStop;
        }
    }

でこれをコントロールに当てはめる

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:behavior="clr-namespace:ControlTest.Behaviors"  // この名前は任意で

<ComboBox x:Name="combobox1"
            ItemsSource="{Binding Items}"
            IsEditable="True"
            IsTabStop="False">
    <i:Interaction.Behaviors>
        <behavior:ComboBoxBehavior/>
    </i:Interaction.Behaviors>
</ComboBox>

だいたいこんな感じでうまくいきました。
何か他にも方法をご存じの方がいましたら、教えていただけるとありがたいです。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?