2

これは奇妙なものであり、何を検索すればよいかさえわかりませんが、私が持っていると信じてください.

テキストボックスがあり、そのOnTextChangedイベントにバインドされているのは以下のメソッドです。

ここでの目的は、テキスト ボックスにフォーカスを与え、カーソルを TextBox の末尾に移動し、実際にフォーカスされていたもの (通常はボタン) にフォーカスを戻すことです。問題は、フォーカスを元のフォーカスされた要素に戻す前に、TextBox が「再描画」されていないように見えることです (ただし、すべてのプロパティは更新されていると考えています)。 .

現在、私はこれを一緒に残酷にハックして、基本的に前にフォーカスされたアイテムの再フォーカスを 10 ミリ秒遅らせ、別のスレッドで実行して、UI を更新する時間を確保しました。さて、これは明らかに任意の時間であり、私のマシンでは問題なく動作しますが、古いマシンでこのアプリを実行している人には問題がある可能性があります.

これを行う適切な方法はありますか?私はそれを理解することはできません。

private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
{
    if (sender == null) return;
    var box = sender as TextBox;

    if (!box.IsFocused)
    {

        var oldFocus = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
        box.Select(box.Text.Length, 0);
        Keyboard.Focus(box); // or box.Focus(); both have the same results

        var thread = new Thread(new ThreadStart(delegate
                                                    {
                                                        Thread.Sleep(10);
                                                        Dispatcher.Invoke(new Action(() => oldFocus.Focus()));
                                                    }));
        thread.Start();
    }
}

編集

私が持っていた新しいアイデアは、UIの更新が完了したら oldFocus.Focus() メソッドを実行することだったので、次のことを試しましたが、同じ結果が得られました:(

var oldFocus = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));

Dispatcher.Invoke(DispatcherPriority.Send, new Action(delegate
 {
   box.Select(box.Text.Length, 0);
   box.Focus();
 }));

Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => oldFocus.Focus()));
4

3 に答える 3

1

あなたは正しい道を進んでいます。問題は、.Focus()通話を持続させるために、Dispatcher で通話を後で遅らせる必要があることです。Sendの値(最も高い値)
を使用する代わりに、 Dispatcher を使用して、 Inputなどの後の DispatcherPriority にフォーカスを設定してみてください。DispatcherPriority

Dispatcher.BeginInvoke(DispatcherPriority.Input,
new Action(delegate() { 
    oldFocus.Focus();         // Set Logical Focus
    Keyboard.Focus(oldFocus); // Set Keyboard Focus
 }));

ご覧のとおり、キーボード フォーカスも設定しています。
WPF は複数のフォーカス スコープを持つことができ、1 つ以上の要素が論理フォーカス ( IsFocused = true) を持つことができます。ただし、キーボード フォーカスを持つことができ、キーボード入力を受け取る要素は1 つだけです。

于 2012-12-22T12:09:57.117 に答える
0

何日も経って、ようやくそれを機能させることができました。テキストボックスにフォーカスとキーボードフォーカスの両方があり、多くのループがあるかどうかを Dispatcher が確認する必要がありました。

参考までにコードはこちら。いくつかのコメントがありますが、誰かが答えを探してこのページにアクセスした場合は、自分で読む必要があります. リマインダー、これはテキストの変更に関するものです。

protected void TextBox_ShowEndOfLine(object sender, TextChangedEventArgs e)
    {
        if (sender == null) return;
        var box = sender as TextBox;

        if (!box.IsFocused && box.IsVisible)
        {
            IInputElement oldFocus = FocusManager.GetFocusedElement(FocusManager.GetFocusScope(this));
            box.Focus();
            box.Select(box.Text.Length, 0);
            box.Focus();

            // We wait for keyboard focus and regular focus before returning focus to the button
            var thread = new Thread((ThreadStart)delegate
                                        {
                                            // wait till focused
                                            while (true)
                                            {
                                                var focused = (bool)Dispatcher.Invoke(new Func<bool>(() => box.IsKeyboardFocusWithin && box.IsFocused && box.IsInputMethodEnabled), DispatcherPriority.Send);
                                                if (!focused)
                                                    Thread.Sleep(1);
                                                else
                                                    break;
                                            }

                                            // Focus the old element
                                            Dispatcher.Invoke(new Action(() => oldFocus.Focus()), DispatcherPriority.SystemIdle);
                                        });
            thread.Start();
        }
        else if (!box.IsVisible)
        {
            // If the textbox is not visible, the cursor will not be moved to the end. Wait till it's visible.
            var thread = new Thread((ThreadStart)delegate
                                        {
                                            while (true)
                                            {
                                                Thread.Sleep(10);
                                                if (box.IsVisible)
                                                {
                                                    Dispatcher.Invoke(new Action(delegate
                                                                                     {
                                                                                         box.Focus();
                                                                                         box.Select(box.Text.Length, 0);
                                                                                         box.Focus();

                                                                                     }), DispatcherPriority.ApplicationIdle);
                                                    return;
                                                }
                                            }
                                        });
            thread.Start();
        }
    }
于 2012-12-27T23:37:31.907 に答える