none
ListView SelectionChangedでのフォーカス移動 RRS feed

  • 質問

  • WPFのListViewに一覧を表示し、クリックにて選択されたデータを編集する画面を作成しています。

    SelectionChangedで編集用のテキストボックスに値をセットした後、リストボックス外にあるテキストボックスに

    フォーカス移動したいのですが、フォーカスが移動しません。

    private void deltailList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
    
        var selectedData = (DetailData)deltailList.SelectedItem;
    
        itemIdTextBox.Text = selectedData .ItemId.ToString();
        itemNameTextBlock.Text = selectedData .ItemName;
    
        itemIdTextBox.Focus(); ←フォーカスが移動しない
    }

    ListViewがフォーカスを持ったままとなっています。

    PageやWindowsオブジェクトからたどって処理しないとダメなのでしょうか?

    対応方法を教えていただけますでしょうか。

    2017年3月19日 15:13

回答

  • 外にあるテキストボックスにフォーカスは移動していますが、SelectionChangedを抜けた後にフォーカスが戻されてしまうのでBeginInvokeでフォーカス移動を遅らせてみる

    private void deltailList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var lv = (ListView)sender;
        var selectedData = (DetailData)deltailList.SelectedItem;
    
        itemIdTextBox.Text = selectedData.ItemId.ToString();
        itemNameTextBlock.Text = selectedData.ItemName;
    
        System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
                {
                    itemIdTextBox.Focus();
                }));
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク まさどん 2017年3月20日 2:17
    • 編集済み gekkaMVP 2017年3月20日 3:01 コード内のInvokeをBeginInvokeに訂正
    2017年3月19日 22:09
  • 試したところやはりダメでした。
    • 回答としてマーク まさどん 2017年3月20日 2:18
    2017年3月20日 2:07
  • 文中では「BeginInvoke」と書いていますが、コード中は「Invoke」と誤っているために起きているのかもしれません。(このケースの場合、Invoke はその場で実行し、BeginInvoke は少し後で実行されるはず)
    CurrentDispatcher.Invoke の部分を CurrentDispatcher.BeginInvoke に変えてもダメですか?
    2017年3月20日 2:27
    モデレータ

すべての返信

  • 今、検証できる環境におらず申し訳ありませんが、FocusManagerを使ってみたらいかがでしょうか?

    (参考)

    WPF/XAML : Window 起動時のフォーカスを設定する / コードからフォーカスを設定する
    http://increment.hatenablog.com/entry/2015/07/28/231445


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2017年3月19日 15:27
    モデレータ
  • 外にあるテキストボックスにフォーカスは移動していますが、SelectionChangedを抜けた後にフォーカスが戻されてしまうのでBeginInvokeでフォーカス移動を遅らせてみる

    private void deltailList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var lv = (ListView)sender;
        var selectedData = (DetailData)deltailList.SelectedItem;
    
        itemIdTextBox.Text = selectedData.ItemId.ToString();
        itemNameTextBlock.Text = selectedData.ItemName;
    
        System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
                {
                    itemIdTextBox.Focus();
                }));
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク まさどん 2017年3月20日 2:17
    • 編集済み gekkaMVP 2017年3月20日 3:01 コード内のInvokeをBeginInvokeに訂正
    2017年3月19日 22:09
  • 試したところやはりダメでした。
    • 回答としてマーク まさどん 2017年3月20日 2:18
    2017年3月20日 2:07
  • ご指摘の通り、いったんTextBoxにフォーカス移動してまた。

    Invokeでもまた、ListViewにフォーカスが戻ってしまいましたので、少々カッコ悪いですが

    フラグを設けて、ListViewからのフォーカス移動の場合、TextBoxからのフォーカス移動をキャンセルするようにしました。

    以下、ソースでうまく動作しました。

    ご回答ありがとうございました!

            /// <summary>
            /// 明細選択フラグ
            /// </summary>
            private bool isSelectingDetailRow = false;
    
            private void deltailList_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
    
                var selectData = (MainPageDetailViewModel)deltailList.SelectedItem;
    
                itemIdTextBox.Text = selectData.ItemId.ToString();
                itemNameTextBlock.Text = selectData.ItemName;
    
                //明細選択フラグOn
                isSelectingDetailRow = true;
    
                itemIdTextBox.Focus();
            }
    
            //テキストボックスのフォーカスロスト時にフラグを判定しフォーカスが移動しないよう制御した。
            private void itemIdTextBox_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
            {
                if(isSelectingDetailRow)
                {
                    e.Handled = true;
                    isSelectingDetailRow = false;
                }
            }

    2017年3月20日 2:17
  • こちらの方法も、試したところダメでした。
    2017年3月20日 2:20
  • 文中では「BeginInvoke」と書いていますが、コード中は「Invoke」と誤っているために起きているのかもしれません。(このケースの場合、Invoke はその場で実行し、BeginInvoke は少し後で実行されるはず)
    CurrentDispatcher.Invoke の部分を CurrentDispatcher.BeginInvoke に変えてもダメですか?
    2017年3月20日 2:27
    モデレータ
  • すみません、Azuleanさんが指摘しているようにInvokeではなくBeginInvokeが正しいです。

    #コピペしたときのミスですorz


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年3月20日 3:00
  • 今、プログラムを修正しBeginInvokeにしたら上手く動作しました!これでプログラムもスッキリしました。ありがとうございます。
    2017年3月20日 3:43