WPF: Cara menghapus fokus secara terprogram dari TextBox

96

Saya ingin menambahkan perilaku sederhana (setidaknya saya pikir itu) ke WPF saya TextBox.

Ketika pengguna menekan Escape, saya ingin TextBoxdia yang sedang mengedit memiliki teks yang dimilikinya saat pengguna mulai mengedit, DAN saya ingin menghapus fokus dari TextBox.

Saya tidak memiliki masalah dalam menyetel teks untuk nilai yang dimilikinya di awal pengeditan.

Masalahnya adalah menghilangkan fokus elemen. Saya tidak ingin memindahkan fokus ke komponen lain, saya hanya ingin TextBoxkehilangan fokus. Apakah saya harus memiliki elemen tak terlihat untuk mengatur fokus sehingga saya TextBoxbisa kehilangan fokus?

jpsstavares.dll
sumber

Jawaban:

153

di .NET Framework 4 saja Keyboard.ClearFocus();

LPL
sumber
1
Inilah yang saya cari malam ini!
Josh
9
Ini tidak selalu menghapus fokus: Saya memiliki masalah di mana AutoCompleteTextBox di dalam ListBox tidak kehilangan fokus saat saya menjalankan Keyboard.ClearFocus()dari belakang kode setelah klik di suatu tempat.
ANeves menganggap SE itu jahat
3
ClearFocuspenyebab GotFocustidak aktifnya kontrol yang difokuskan baru-baru ini saat masih aktif untuk kontrol lain. Itu masalah besar untuk keyboard layar kustom saya, misalnya. Itu memang menyebabkan tanda sisipan menghilang, yang mungkin merupakan semua yang diperlukan "fokus keyboard". Mungkin saya lebih tertarik pada sesuatu seperti "fokus mouse".
Grault
3
Terima kasih Grault, saya mendapat masalah yang sama. Hal terbaik yang saya dapat adalah dengan memindahkan fokus ke kontrol lain other.Focus().
Tor Klingberg
7
@Grault Ini hanya menghapus fokus keyboard, bukan fokus logis (yang diaktifkan ke GotFocusacara). Selalu ada sesuatu dengan fokus logis dalam program Anda. Gunakan LostKeyboardFocusperistiwa atau alihkan fokus ke elemen lain (yang menggeser fokus logis bersamanya) sebelum menghapus fokus keyboard.
Chirimorin
56

Kode yang telah saya gunakan:

// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)textBox.Parent;
while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
{
    parent = (FrameworkElement)parent.Parent;
}

DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
decasteljau
sumber
2
Kode ini bagus, Keyboard.ClearFocus () memiliki beberapa efek samping yang tidak diinginkan
patrick
Mengapa kondisi! (((IInputElement) parent] .Focusable memiliki "!" di depan? Bukankah kondisi ini harus benar jika orang tua bisa fokus?
Mert Akcakaya
Mert - tidak yakin tetapi hanya menelusuri posting ini sepertinya dengan melanjutkan perulangan sampai kondisi itu benar adalah intinya. Dengan cara itu, item pertama yang dapat difokuskan mengakhiri loop.
jpierson
4
@ patrick, efek samping mana yang tidak diinginkan? Bisakah Anda memberikan contoh yang relevan?
ANeves menganggap SE itu jahat
2
Ini adalah solusi yang bagus. Saya juga mengalami masalah dengan Keyboard.ClearFocus (). Saat menjalankan ClearFocus () pada TextBox di dalam jendela modal, ini menyebabkan TextBox dan Window kehilangan fokus. Arti peristiwa KeyDown tidak lagi masuk ke Window. Dengan mengubahnya sehingga Fokus berubah menjadi induk (yang mungkin merupakan Jendela), peristiwa KeyDown mendatang tidak hilang. Dalam contoh praktis saya, saya memiliki Window yang mencari "Key.Escape" dan memanggil Close (). Ini berhenti bekerja jika Anda menjalankan ClearFocus () di mana saja.
Denis P
19

Agak terlambat ke pesta, tapi itu membantu saya jadi ini dia.

Sejak .Net 3.0, FrameworkElementmemiliki fungsi MoveFocus yang melakukan trik untuk saya.

SuperOli
sumber
Untuk instruksi -> msdn.microsoft.com/en-us/library/…
Carter Medlin
"Pastikan Anda memeriksa nilai kembalian metode ini. Nilai kembalian false mungkin dikembalikan jika traversal berjalan ke tab stop yang ditentukan oleh komposisi kontrol, dan permintaan traversal tidak meminta untuk ditutup." - msdn.microsoft.com/en-us/library/…
aderesh
16

Karena tidak ada jawaban di atas yang berhasil untuk saya dan jawaban yang diterima hanya berfungsi untuk fokus keyboard, saya sampai pada pendekatan berikut:

// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();

Membunuh keduanya, logis serta fokus keyboard.

Topan
sumber
9

Anda bisa mengatur fokus ke leluhur yang bisa difokuskan. Kode ini akan berfungsi bahkan jika kotak teks berada di dalam templat tanpa leluhur yang dapat difokuskan di dalam templat yang sama:

DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
    var element = ancestor as UIElement;
    if (element != null && element.Focusable)
    {
        element.Focus();
        break;
    }

    ancestor = VisualTreeHelper.GetParent(ancestor);
}
Julian Dominguez
sumber
6

AFAIK, tidak mungkin menghapus fokus sepenuhnya. Sesuatu di Jendela Anda akan selalu menjadi fokus.

bitbonk
sumber
2

Dalam Pengembangan Windows Phone, saya baru saja melakukannya Focus()atau this.Focus()di PhoneApplicationPage dan bekerja seperti pesona.

Bruno Lemos
sumber
1

Bagi saya, ini cukup rumit, terutama saat menggunakan dengan pengikatan LostFocus. Namun, solusi saya adalah menambahkan label kosong dan fokus padanya.

<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />

...

OnKeyDown(object sender, RoutedEventArgs e)
{
  //if is Esc
  ResetFocusArea.Focus();
}
Brian Ng
sumber
0

Jawaban saya tidak menjawab pertanyaan di atas secara langsung, namun saya merasa bahwa pengkalimatannya telah menyebabkannya menjadi "Pertanyaan" tentang menghilangkan fokus secara terprogram. Skenario umum yang memerlukan ini adalah agar pengguna dapat menghapus fokus setelah mengklik kiri latar belakang kontrol root, seperti jendela.

Jadi, untuk mencapai ini, Anda dapat membuat Attached Behavior yang akan mengalihkan fokus ke kontrol yang dibuat secara dinamis (dalam kasus saya, label kosong). Lebih disukai untuk menggunakan perilaku ini pada elemen tingkat tertinggi seperti jendela, karena ia melakukan iterasi melalui turunannya untuk menemukan panel yang dapat ditambahkan label tiruan.

public class LoseFocusOnLeftClick : Behavior<FrameworkElement>
{
    private readonly MouseBinding _leftClick;
    private readonly Label _emptyControl = new Label() { Focusable = true, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top };

    public LoseFocusOnLeftClick()
    {
        _leftClick = new MouseBinding(new RelayCommand(LoseFocus), new MouseGesture(MouseAction.LeftClick));
    }

    protected override void OnAttached()
    {
        AssociatedObject.InputBindings.Add(_leftClick);
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }        

    protected override void OnDetaching()
    {
        AssociatedObject.InputBindings.Remove(_leftClick);
        AssociatedObject.Loaded -= AssociatedObject_Loaded;
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        AssociatedObject.Loaded -= AssociatedObject_Loaded;

        AttachEmptyControl();
    }

    private void AttachEmptyControl()
    {            
        DependencyObject currentElement = AssociatedObject;
        while (!(currentElement is Panel))
        {
            currentElement = VisualTreeHelper.GetChild(currentElement, 0);
        }

        ((Panel)currentElement).Children.Add(_emptyControl);
    }

    private void LoseFocus()
    {            
        _emptyControl.Focus();
    }
}
TripleAccretion
sumber