WPF: วิธีลบโฟกัสโดยใช้โปรแกรมออกจากกล่องข้อความ


96

ฉันต้องการเพิ่มง่าย (อย่างน้อยผมคิดว่ามัน) พฤติกรรมการ TextBoxWPF

เมื่อผู้ใช้กด Escape ฉันต้องการให้TextBoxเขาแก้ไขข้อความเมื่อผู้ใช้เริ่มแก้ไขและฉันต้องการลบโฟกัสออกจากไฟล์TextBox.

ฉันไม่มีปัญหาในการตั้งค่าข้อความสำหรับค่าที่มีในตอนเริ่มต้นของการแก้ไข

ปัญหาคือการลบโฟกัสขององค์ประกอบ ฉันไม่ต้องการย้ายโฟกัสไปที่ส่วนประกอบอื่นฉันแค่อยากTextBoxให้โฟกัสเสีย ฉันจะต้องมีองค์ประกอบที่มองไม่เห็นเพื่อตั้งโฟกัสเพื่อที่ฉันTextBoxจะสูญเสียโฟกัสหรือไม่?

คำตอบ:


153

ใน. NET Framework 4 เพียงแค่ Keyboard.ClearFocus();


1
นี่คือสิ่งที่ฉันกำลังมองหาในเย็นนี้!
Josh

9
สิ่งนี้ไม่ชัดเจนในการโฟกัสเสมอไป: ฉันมีปัญหาที่ AutoCompleteTextBox ใน ListBox ไม่สูญเสียโฟกัสเมื่อฉันเรียกใช้Keyboard.ClearFocus()จากโค้ดด้านหลังหลังจากคลิกที่ใดที่หนึ่ง
ANeves คิดว่า SE เป็นคนชั่ว

3
ClearFocusทำให้GotFocusไม่ยิงสำหรับการควบคุมที่โฟกัสล่าสุดในขณะที่ยังคงยิงเพื่อควบคุมอื่น นั่นเป็นปัญหาใหญ่สำหรับแป้นพิมพ์บนหน้าจอแบบกำหนดเองของฉัน มันทำให้คาเร็ตหายไปซึ่งอาจเป็นทั้งหมดที่ "โฟกัสแป้นพิมพ์" เกี่ยวข้อง บางทีฉันอาจจะสนใจบางอย่างเช่น "การโฟกัสของเมาส์" มากกว่า
Grault

3
ขอบคุณ Grault ฉันมีปัญหาเดียวกัน ดีที่สุดที่ฉันได้มาด้วยคือการย้ายการโฟกัสไปยังบางส่วนควบคุมอื่น ๆ other.Focus()ด้วย
Tor Klingberg

7
@Grault สิ่งนี้จะล้างเฉพาะโฟกัสของแป้นพิมพ์เท่านั้นไม่ใช่โฟกัสแบบลอจิคัล (ซึ่งเป็นสิ่งที่ทำให้GotFocusเกิดเหตุการณ์) มีบางอย่างที่เน้นตรรกะในโปรแกรมของคุณเสมอ ใช้LostKeyboardFocusเหตุการณ์หรือเปลี่ยนโฟกัสไปยังองค์ประกอบอื่น (ซึ่งจะเลื่อนโฟกัสแบบลอจิคัลไปด้วย) ก่อนที่จะล้างโฟกัสของแป้นพิมพ์
Chirimorin

56

รหัสที่ฉันใช้:

// 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
รหัสนี้ดีมาก Keyboard.ClearFocus () มีผลข้างเคียงที่ไม่ได้ตั้งใจ
patrick

ทำไมเงื่อนไข! ((IInputElement) parent) .Focusable มี "!" ข้างหน้า? เงื่อนไขนี้ไม่ควรเป็นจริงถ้าผู้ปกครองสามารถโฟกัสได้?
Mert Akcakaya

Mert - ไม่แน่ใจ แต่แค่ค้นดูโพสต์นี้ดูเหมือนว่าจะวนลูปต่อไปจนกว่าเงื่อนไขนั้นจะเป็นจริง ด้วยวิธีนี้รายการแรกที่โฟกัสได้จะยุติการวนซ้ำ
jpierson

4
@patrick ซึ่งผลข้างเคียงโดยไม่ได้ตั้งใจ? คุณช่วยยกตัวอย่างที่เกี่ยวข้องได้ไหม
ANeves คิดว่า SE เป็นคนชั่ว

2
นี่เป็นทางออกที่ยอดเยี่ยม ฉันยังมีปัญหากับ Keyboard.ClearFocus () เมื่อเรียกใช้ ClearFocus () บนกล่องข้อความภายในหน้าต่างโมดอลจะทำให้ทั้งกล่องข้อความและหน้าต่างสูญเสียโฟกัส ความหมาย KeyDown เหตุการณ์ไม่ไปที่หน้าต่างอีกต่อไป โดยการเปลี่ยนแทนเพื่อให้โฟกัสเปลี่ยนเป็นพาเรนต์ (ซึ่งอาจเป็นหน้าต่าง) เหตุการณ์ KeyDown ในอนาคตจะไม่สูญหายไป ในตัวอย่างการใช้งานจริงของฉันฉันมีหน้าต่างที่มองหา "Key.Escape" และเรียก Close () สิ่งนี้จะหยุดทำงานหากคุณเรียกใช้ ClearFocus () ที่ใดก็ได้
Denis P

19

ไปงานปาร์ตี้ช้าไปหน่อย แต่มันก็มีประโยชน์สำหรับฉันดังนั้นมันจึงไปได้

ตั้งแต่. Net 3.0 FrameworkElementมีฟังก์ชันMoveFocusซึ่งทำเคล็ดลับให้ฉัน


สำหรับคำแนะนำ -> msdn.microsoft.com/en-us/library/…
Carter Medlin

"ตรวจสอบให้แน่ใจว่าคุณได้ตรวจสอบค่าส่งคืนของวิธีนี้อาจมีการส่งคืนค่าที่เป็นเท็จหากการส่งผ่านไปยังจุดหยุดแท็บที่กำหนดโดยองค์ประกอบของตัวควบคุมและคำขอการส่งผ่านไม่ได้ขอให้รวม" - msdn.microsoft.com/en-us/library/…
aderesh

16

เนื่องจากคำตอบข้างต้นไม่ได้ผลสำหรับฉันและคำตอบที่ยอมรับนั้นใช้ได้เฉพาะกับการโฟกัสบนแป้นพิมพ์เท่านั้นฉันจึงใช้แนวทางต่อไปนี้:

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

ฆ่าทั้งตรรกะและโฟกัสของแป้นพิมพ์


9

คุณสามารถกำหนดโฟกัสเป็นบรรพบุรุษที่โฟกัสได้ รหัสนี้จะใช้งานได้แม้ว่ากล่องข้อความจะอยู่ในเทมเพลตที่ไม่มีบรรพบุรุษที่โฟกัสได้ภายในเทมเพลตเดียวกันก็ตาม:

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 ไม่สามารถลบโฟกัสได้ทั้งหมด บางสิ่งในหน้าต่างของคุณจะมีจุดสนใจเสมอ



1

สำหรับฉันมันค่อนข้างยุ่งยากโดยเฉพาะเมื่อใช้กับการเชื่อม LostFocus อย่างไรก็ตามวิธีแก้ปัญหาของฉันคือการเพิ่มป้ายกำกับที่ว่างเปล่าและมุ่งเน้นไปที่มัน

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

...

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

0

คำตอบของฉันไม่ได้ตอบคำถามข้างต้นโดยตรง แต่ฉันรู้สึกว่าถ้อยคำของคำถามนี้ทำให้กลายเป็น "คำถาม" เกี่ยวกับการกำจัดโฟกัสโดยใช้โปรแกรม สถานการณ์ทั่วไปที่จำเป็นเพื่อให้ผู้ใช้สามารถล้างโฟกัสได้เมื่อคลิกซ้ายที่พื้นหลังของตัวควบคุมรูทเช่นหน้าต่าง

ดังนั้นเพื่อให้บรรลุสิ่งนี้คุณสามารถสร้าง Attached Behavior ที่จะเปลี่ยนโฟกัสเป็นการควบคุมที่สร้างขึ้นแบบไดนามิก (ในกรณีของฉันคือป้ายว่าง) เป็นที่นิยมที่จะใช้พฤติกรรมนี้กับองค์ประกอบระดับสูงสุดเช่นหน้าต่างเนื่องจากมันจะวนซ้ำผ่านเด็ก ๆ เพื่อค้นหาแผงควบคุมที่สามารถเพิ่มป้ายกำกับจำลอง

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();
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.