WPF: Cách xóa tiêu điểm theo chương trình khỏi TextBox


96

Tôi muốn thêm một hành vi đơn giản (ít nhất là tôi nghĩ đó là) vào WPF của mình TextBox.

Khi người dùng nhấn Escape, tôi muốn TextBoxanh ấy đang chỉnh sửa có văn bản khi người dùng bắt đầu chỉnh sửa VÀ tôi muốn xóa tiêu điểm khỏi TextBox.

Tôi không gặp vấn đề gì khi đặt văn bản cho giá trị mà nó có khi bắt đầu chỉnh sửa.

Vấn đề là loại bỏ trọng tâm của phần tử. Tôi không muốn chuyển tiêu điểm sang bất kỳ thành phần nào khác, tôi chỉ muốn TextBoxmất tiêu điểm. Tôi sẽ phải có một yếu tố vô hình nào để đặt tiêu điểm nên tôi TextBoxcó thể bị mất tập trung?

Câu trả lời:


152

trong .NET Framework 4 chỉ Keyboard.ClearFocus();


1
Đây chính xác là những gì tôi đã tìm kiếm tối nay!
Josh

9
Điều này không phải lúc nào cũng rõ ràng tiêu điểm: Tôi gặp sự cố trong đó AutoCompleteTextBox bên trong ListBox không mất tiêu điểm khi tôi chạy Keyboard.ClearFocus()từ phía sau mã sau khi nhấp vào đâu đó.
ANeves nghĩ SE là ác

3
ClearFocusnguyên nhân GotFocuskhông kích hoạt cho điều khiển tập trung gần đây trong khi nó vẫn kích hoạt cho các điều khiển khác. Ví dụ, đó là một vấn đề lớn đối với bàn phím ảo tùy chỉnh của tôi. Nó làm cho dấu mũ biến mất, đó có lẽ là tất cả những gì mà "tiêu điểm bàn phím" đòi hỏi. Có lẽ tôi hứng thú hơn với một thứ như "tiêu điểm chuột".
Grault

2
Cảm ơn bạn Grault, tôi gặp vấn đề tương tự. Điều tốt nhất tôi nghĩ ra là chuyển trọng tâm sang một số điều khiển khác other.Focus().
Tor Klingberg

7
@Grault Thao tác này chỉ xóa tiêu điểm bàn phím, không xóa tiêu điểm hợp lý (là thứ kích hoạt GotFocussự kiện). Luôn luôn có một cái gì đó với trọng tâm hợp lý trong chương trình của bạn. Sử dụng LostKeyboardFocussự kiện hoặc chuyển tiêu điểm sang phần tử khác (thay đổi tiêu điểm hợp lý cùng với nó) trước khi xóa tiêu điểm bàn phím.
Chirimorin 20/02/17

54

Mã tôi đang sử dụng:

// 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
Mã này thật tuyệt, Keyboard.ClearFocus () có một số tác dụng phụ không mong muốn
Patrick

Tại sao điều kiện! ((IInputElement) cha) .Focusable có "!" đối đầu? Điều kiện này có đúng không nếu cha mẹ là tiêu điểm?
Mert Akcakaya

Mert - không chắc chắn nhưng chỉ cần duyệt qua bài đăng này, nó trông giống như bằng cách tiếp tục lặp lại cho đến khi điều kiện đó là đúng. Bằng cách đó, mục có thể lấy tiêu điểm đầu tiên kết thúc vòng lặp.
jpierson

4
@patrick, ngoài ý muốn tác dụng phụ? Bạn có thể đưa ra các ví dụ có liên quan?
ANeves cho rằng SE là xấu xa

1
Đây là một giải pháp tuyệt vời. Tôi cũng gặp sự cố với Keyboard.ClearFocus (). Khi chạy ClearFocus () trên TextBox bên trong một cửa sổ phương thức, nó làm cho cả TextBox và Window bị mất tiêu điểm. Có nghĩa là các sự kiện KeyDown không còn đi đến Cửa sổ nữa. Thay vào đó, bằng cách thay đổi nó để Focus thay đổi thành cha mẹ (có thể là Cửa sổ), các sự kiện KeyDown trong tương lai sẽ không bị mất. Trong ví dụ thực tế của tôi, tôi có Cửa sổ đang tìm kiếm "Key.Escape" và gọi Close (). Điều này sẽ ngừng hoạt động nếu bạn chạy ClearFocus () ở bất kỳ đâu.
Denis P

19

Đến bữa tiệc hơi muộn, nhưng nó rất hữu ích đối với tôi vì vậy nó bắt đầu.

Kể từ .Net 3.0, FrameworkElementcó một chức năng MoveFocus đã thực hiện thủ thuật cho tôi.


Để được hướng dẫn -> msdn.microsoft.com/en-us/library/…
Carter Medlin

"Hãy đảm bảo rằng bạn kiểm tra giá trị trả về của phương thức này. Giá trị trả về là false có thể được trả về nếu quá trình truyền tải gặp phải điểm dừng tab được xác định bởi thành phần của điều khiển và yêu cầu truyền tải không yêu cầu kết thúc." - msdn.microsoft.com/en-us/library/…
aderesh Ngày

13

Vì không có câu trả lời nào ở trên phù hợp với tôi và câu trả lời được chấp nhận chỉ hoạt động cho tiêu điểm bàn phím, tôi đã đi đến cách tiếp cận sau:

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

Tiêu diệt cả hai, logic cũng như tiêu điểm bàn phím.


9

Bạn có thể đặt tiêu điểm thành tổ tiên có thể lấy tiêu điểm. Mã này sẽ hoạt động ngay cả khi hộp văn bản nằm bên trong một mẫu không có tổ tiên có thể lấy tiêu điểm bên trong cùng một mẫu đó:

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, không thể loại bỏ hoàn toàn tiêu điểm. Một cái gì đó trong Cửa sổ của bạn sẽ luôn có tiêu điểm.


2

Trong Phát triển Windows Phone, tôi vừa làm Focus()hoặc this.Focus()trong PhoneApplicationPage và nó hoạt động như một sự quyến rũ.


1

Đối với tôi, nó khá phức tạp, đặc biệt là khi sử dụng với liên kết LostFocus. Tuy nhiên, cách giải quyết của tôi là thêm một nhãn trống và tập trung vào nó.

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

...

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

0

Câu trả lời của tôi không đáp ứng trực tiếp câu hỏi trên, tuy nhiên, tôi cảm thấy rằng cách diễn đạt của nó đã khiến nó trở thành "Câu hỏi" về việc loại bỏ tiêu điểm theo chương trình. Một tình huống phổ biến khi điều này là cần thiết để người dùng có thể xóa tiêu điểm khi nhấp chuột trái vào nền của điều khiển gốc, chẳng hạn như cửa sổ.

Vì vậy, để đạt được điều này, bạn có thể tạo Hành vi đính kèm sẽ chuyển tiêu điểm sang điều khiển được tạo động (trong trường hợp của tôi là nhãn trống). Tốt hơn là sử dụng hành vi này trên các phần tử cấp cao nhất như cửa sổ, vì nó lặp qua các phần tử con của nó để tìm một bảng điều khiển mà nó có thể thêm nhãn giả vào.

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();
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.