WPF: Odağı bir TextBox'tan programlı olarak kaldırma


96

WPF'ime basit (en azından öyle olduğunu düşündüm) bir davranış eklemek istiyorum TextBox.

Kullanıcı Escape tuşuna bastığında TextBox, düzenleme yapmakta olduğu metnin kullanıcı düzenlemeye başladığında sahip olmasını istiyorum VE odağı öğesinden kaldırmak istiyorum TextBox.

Metni düzenlemenin başında sahip olduğu değer için ayarlarken herhangi bir sorun yaşamıyorum.

Sorun, öğenin odağını kaldırmaktır. Odağı başka herhangi bir bileşene kaydırmak istemiyorum, sadece TextBoxodağı kaybetmek istiyorum . Odağı TextBoxkaybetmek için odağı ayarlamak için görünmez bir öğeye sahip olmam gerekecek mi?

Yanıtlar:


153

.NET Framework 4'te sadece Keyboard.ClearFocus();


1
Bu tam da bu akşam aradığım şeydi!
Josh

9
Bu, odağı her zaman netleştirmez: ListBox içindeki bir AutoCompleteTextBox, Keyboard.ClearFocus()bir yere tıkladıktan sonra arka koddan çalıştırdığımda odağı kaybetmediğinde bir sorun yaşıyorum .
ANeves,

3
ClearFocusGotFocusdiğer kontroller için hala ateşlenirken son odaklanmış kontrol için ateşlenmemesine neden olur . Bu, örneğin özel ekran klavyem için büyük bir sorun. İmlecin kaybolmasına neden olur, muhtemelen "klavye odağı" nın gerektirdiği tek şeydir. Belki "fare odağı" gibi bir şeyle daha çok ilgileniyorum.
Grault

3
Teşekkürler Grault, bende de aynı sorun var. Bulduğum en iyi şey, odağı başka bir kontrole kaydırmak other.Focus().
Tor Klingberg

7
@Grault Bu sadece klavye odağını temizler, mantıksal odağı değil ( GotFocusolay için tetiklenen şey budur ). Programınızda her zaman mantıksal odaklı bir şey vardır. LostKeyboardFocusKlavye odağını temizlemeden önce olayı kullanın veya odağı başka bir öğeye kaydırın (mantıksal odağı onunla birlikte kaydırır).
Chirimorin

56

Kullanmakta olduğum kod:

// 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);

2
Bu kod harika, Keyboard.ClearFocus () bazı istenmeyen yan etkilere sahip
patrick

Neden koşul! ((IInputElement) ebeveyn) .Odaklanabilen "!" önünde? Ebeveyn odaklanabilirse bu koşul doğru olmamalı mı?
Mert Akçakaya

Mert - emin değilim ama sadece bu yazıya göz attığımızda, bu durum doğru olana kadar döngüye devam etmek gibi görünüyor. Bu şekilde ilk odaklanabilir öğe döngüyü sonlandırır.
jpierson

4
@patrick, hangi istenmeyen yan etkiler? Alakalı örnekler verebilir misiniz?
ANeves SE'nin kötü olduğunu düşünüyor

2
Bu harika bir çözüm. Keyboard.ClearFocus () ile de sorunlar yaşadım. ClearFocus (), kalıcı bir Pencere içindeki bir Metin Kutusu'nda çalıştırıldığında, hem Metin Kutusu'nun hem de Pencerenin odağı kaybetmesine neden olur. Yani KeyDown olayları artık Pencereye gitmiyor. Bunun yerine, Odak bir üst öğeye (Pencere olabilir) dönüşecek şekilde değiştirildiğinde, gelecekteki KeyDown olayları kaybolmaz. Pratik örneğimde, "Key.Escape" i arayan ve Close () 'u çağıran Pencere var. ClearFocus () herhangi bir yerde çalıştırılırsa bu, çalışmayı durdurur.
Denis P

19

Partiye biraz geç kaldım ama bana yardımcı oldu, işte burada.

.Net 3.0'dan beri, benim için hile yapan FrameworkElementbir MoveFocus işlevi var.



"Bu yöntemin dönüş değerini kontrol ettiğinizden emin olun. Geçiş, bir denetimin bileşimi tarafından tanımlanan bir sekme durağına girerse ve geçiş isteği sarmayı talep etmediyse, yanlış dönüş değeri döndürülebilir. - msdn.microsoft.com/en-us/library/…
aderesh

16

Yukarıdaki cevapların hiçbiri benim için işe yaramadığından ve kabul edilen cevap sadece klavye odağı için işe yaradığından, aşağıdaki yaklaşıma geldim:

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

Hem mantıksal hem de klavye odağını öldürür.


9

Odağı odaklanabilir bir ataya ayarlayabilirsiniz. Bu kod, metin kutusu aynı şablonun içinde odaklanılabilir ataları olmayan bir şablonun içinde olsa bile çalışacaktır:

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

    ancestor = VisualTreeHelper.GetParent(ancestor);
}

6

AFAIK, odağı tamamen kaldırmak mümkün değildir. Pencerenizdeki bir şey her zaman odağa sahip olacaktır.


2

Windows Phone Geliştirme'de, yeni yaptım Focus()ya this.Focus()da PhoneApplicationPage'de ve harika çalıştı.


1

Benim için oldukça zor, özellikle de LostFocus bağlama ile kullanıldığında. Ancak benim çözümüm boş bir etiket eklemek ve ona odaklanmak.

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

...

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

0

Cevabım yukarıdaki soruya doğrudan hitap etmiyor, ancak bu sorunun üslubunun programatik olarak odaktan kurtulma konusunda "Soru" olmasına neden olduğunu hissediyorum. Bunun gerekli olduğu yaygın bir senaryo, kullanıcının pencere gibi bir kök denetimin arka planına sol tıkladıktan sonra odağı temizleyebilmesidir.

Dolayısıyla, bunu başarmak için, odağı dinamik olarak oluşturulmuş bir kontrole (benim durumumda boş bir etiket) geçirecek bir Ekli Davranış oluşturabilirsiniz. Bu davranışı pencereler gibi en üst düzey öğelerde kullanmak tercih edilir, çünkü alt öğeleri arasında sahte bir etiket ekleyebileceği bir panel bulmak için yinelenir.

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();
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.