トップ回答者
ComboBox の IME を無効にする方法は?

質問
-
ComboBox の IME を完全に無効にする方法はあるでしょうか?
通常 Control の IME を無効にするには
InputMethod.IsInputMethodEnabled = False
もしくは
InputMethod.IsInputMethodSuspended = True
だと思うんですが、IsEditable="True" にした ComboBox は、XAML で IME を無効にしても半角/全角キーを押すと IME を ON にできてしまいます。
そこで調査したところ、ComboBox の編集時は要素である TextBox に対して設定すればいいのではとの記事を読み、さらに調べるうちに下記の記事を見つけました。MaxLength for editable ComboBox
以下は上記の記事を基に起こしたコードです。若干修正しています。
/// <summary> /// ComboBox 添付ビヘイビア /// </summary> public class ComboBoxBehaviors { public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.RegisterAttached("MaxLength", typeof(int), typeof(ComboBoxBehaviors), new UIPropertyMetadata(OnMaxLengthChanged)); public static int GetMaxLength(DependencyObject obj) { return (int)obj.GetValue(MaxLengthProperty); } public static void SetMaxLength(DependencyObject obj, int value) { obj.SetValue(MaxLengthProperty, value); } private static void OnMaxLengthChanged (DependencyObject obj, DependencyPropertyChangedEventArgs args) { var comboBox = obj as ComboBox; if (comboBox == null) return; comboBox.Loaded += (s, e) => { var textBox = comboBox.FindChild(typeof(TextBox), "PART_EditableTextBox"); if (textBox == null) return; textBox.SetValue(TextBox.MaxLengthProperty, args.NewValue); }; } } public static class UIChildFinder { public static DependencyObject FindChild (this DependencyObject reference, Type childType, string childName) { DependencyObject foundChild = null; if (reference != null) { int childrenCount = VisualTreeHelper.GetChildrenCount(reference); for (int i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(reference, i); // If the child is not of the request child type child if (child.GetType() != childType) { // recursively drill down the tree foundChild = FindChild(child, childType, childName); if (foundChild != null) break; } else if (!string.IsNullOrEmpty(childName)) { var frameworkElement = child as FrameworkElement; // If the child's name is set for search if (frameworkElement != null && frameworkElement.Name == childName) { // if the child's name is of the request name foundChild = child; break; } } else { // child element found. foundChild = child; break; } } } return foundChild; } }
XAML
<ComboBox pz:ComboBoxBehaviors.MaxLength="10" />この場合、MaxLength は有効になります。しかし上記コードを参考にして、以下のように IsInputMethodEnabled を定義しても、IME を無効にすることができません。何か根本的に間違っているでしょうか?
public static readonly DependencyProperty IsInputMethodEnabledProperty = DependencyProperty.RegisterAttached("IsInputMethodEnabled", typeof(bool), typeof(ComboBoxBehaviors), new UIPropertyMetadata(OnIsInputMethodEnabledChanged)); public static bool GetIsInputMethodEnabled(DependencyObject obj) { return (bool)obj.GetValue(IsInputMethodEnabledProperty); } public static void SetIsInputMethodEnabled(DependencyObject obj, bool value) { obj.SetValue(IsInputMethodEnabledProperty, value); } private static void OnIsInputMethodEnabledChanged (DependencyObject obj, DependencyPropertyChangedEventArgs args) { var comboBox = obj as ComboBox; if (comboBox == null) return; comboBox.Loaded += (s, e) => { var textBox = comboBox.FindChild(typeof(TextBox), "PART_EditableTextBox"); if (textBox == null) return; textBox.SetValue(InputMethod.IsInputMethodEnabledProperty, args.NewValue); }; }
ひらぽん http://d.hatena.ne.jp/hilapon/
回答
-
こんにちわ。
実装方法としてはComboBoxテンプレート内のTextBoxの「InputMethod.IsInputMethodEnabled」添付プロパティを操作してIMEを変更するので問題ありません。
今回問題なのは、ComboBoxBehaviorsで定義した「IsInputMethodEnabled」依存関係プロパティの方です。
依存関係プロパティの定義箇所にて、UIPropertyMetadataの第一引数を使用してコールバックメソッドを登録していますが、それを以下のようにするときちんと動作します。
public static readonly DependencyProperty IsInputMethodEnabledProperty =
DependencyProperty.RegisterAttached("IsInputMethodEnabled", typeof(bool),
typeof(ComboBoxBehaviors), new UIPropertyMetadata(true, new PropertyChangedCallback(OnIsInputMethodEnabledChanged)));
上記ではUIPropertyMetadataの第1引数で依存関係プロパティの初期値を定義しています。
原因だったのは依存関係プロパティの「初期値」です。bool型のdefault値は「false」ですので、XAML上で上記依存関係プロパティに対し「false」を設定してもプロパティ変更用のコールバックメソッドが呼ばれていないのが原因です。試しにコールバックメソッドでブレークポイントを設定すると呼ばれないのが分かると思います。
私の環境ではひらぽんさんのコードをそのまま拝借し、初期値を設定した所、問題なくIME制御が行えるようになっています。
★良い回答には回答済みマークを付けよう! kazuto Blog : http://blogs.wankuma.com/kzt/- 回答としてマーク ひらぽんModerator 2011年1月7日 1:38
すべての返信
-
こんにちわ。
実装方法としてはComboBoxテンプレート内のTextBoxの「InputMethod.IsInputMethodEnabled」添付プロパティを操作してIMEを変更するので問題ありません。
今回問題なのは、ComboBoxBehaviorsで定義した「IsInputMethodEnabled」依存関係プロパティの方です。
依存関係プロパティの定義箇所にて、UIPropertyMetadataの第一引数を使用してコールバックメソッドを登録していますが、それを以下のようにするときちんと動作します。
public static readonly DependencyProperty IsInputMethodEnabledProperty =
DependencyProperty.RegisterAttached("IsInputMethodEnabled", typeof(bool),
typeof(ComboBoxBehaviors), new UIPropertyMetadata(true, new PropertyChangedCallback(OnIsInputMethodEnabledChanged)));
上記ではUIPropertyMetadataの第1引数で依存関係プロパティの初期値を定義しています。
原因だったのは依存関係プロパティの「初期値」です。bool型のdefault値は「false」ですので、XAML上で上記依存関係プロパティに対し「false」を設定してもプロパティ変更用のコールバックメソッドが呼ばれていないのが原因です。試しにコールバックメソッドでブレークポイントを設定すると呼ばれないのが分かると思います。
私の環境ではひらぽんさんのコードをそのまま拝借し、初期値を設定した所、問題なくIME制御が行えるようになっています。
★良い回答には回答済みマークを付けよう! kazuto Blog : http://blogs.wankuma.com/kzt/- 回答としてマーク ひらぽんModerator 2011年1月7日 1:38
-
実装方法としてはComboBoxテンプレート内のTextBoxの「InputMethod.IsInputMethodEnabled」添付プロパティを操作してIMEを変更するので問題ありません。今回問題なのは、ComboBoxBehaviorsで定義した「IsInputMethodEnabled」依存関係プロパティの方です。
依存関係プロパティの定義箇所にて、UIPropertyMetadataの第一引数を使用してコールバックメソッドを登録していますが、それを以下のようにするときちんと動作します。
public static readonly DependencyProperty IsInputMethodEnabledProperty =DependencyProperty.RegisterAttached("IsInputMethodEnabled", typeof(bool),typeof(ComboBoxBehaviors), new UIPropertyMetadata(true, new PropertyChangedCallback(OnIsInputMethodEnabledChanged)));
上記ではUIPropertyMetadataの第1引数で依存関係プロパティの初期値を定義しています。
原因だったのは依存関係プロパティの「初期値」です。bool型のdefault値は「false」ですので、XAML上で上記依存関係プロパティに対し「false」を設定してもプロパティ変更用のコールバックメソッドが呼ばれていないのが原因です。試しにコールバックメソッドでブレークポイントを設定すると呼ばれないのが分かると思います。
私の環境ではひらぽんさんのコードをそのまま拝借し、初期値を設定した所、問題なくIME制御が行えるようになっています。
ありがとうございます。ご指摘どおり、UIPropertyMetadata のコンストラクタの第一パラメータに true を設定したら、こちらの想定どおりの動作をするようになりました!原因だったのは依存関係プロパティの「初期値」です。bool型のdefault値は「false」ですので、XAML上で上記依存関係プロパティに対し「false」を設定してもプロパティ変更用のコールバックメソッドが呼ばれていないのが原因です。試しにコールバックメソッドでブレークポイントを設定すると呼ばれないのが分かると思います。
試してみたら確かにそうでした。この辺りは今後注意する必要はありそうです。貴重な回答有難うございました。しかし IME の挙動は WinForm と根本的に違っており、移行する人は相当混乱すると思われます。この問題・・・ComboBox の IME を無効にしても有効になる・・・は Connect に提案もしくは問題として挙げておきたいと思います。
ひらぽん http://d.hatena.ne.jp/hilapon/