Jak automatycznie zaznaczyć cały tekst na fokusie w WPF TextBox?

232

Jeśli zadzwonię SelectAllz GotFocusobsługi zdarzeń, to nie działa za pomocą myszki - wybór znika tak szybko, jak myszy jest zwolniony.

EDYCJA: Ludziom podoba się odpowiedź Donnelle, postaram się wyjaśnić, dlaczego nie podobała mi się tak bardzo, jak zaakceptowana odpowiedź.

  • Jest to bardziej złożone, a zaakceptowana odpowiedź robi to samo w prostszy sposób.
  • Przydatność zaakceptowanej odpowiedzi jest lepsza. Kiedy klikniesz w środku tekstu, tekst zostaje odznaczony po zwolnieniu myszy, co pozwala na natychmiastowe rozpoczęcie edycji, a jeśli nadal chcesz zaznaczyć wszystko, po prostu naciśnij ponownie przycisk, a tym razem nie zostanie odznaczony po zwolnieniu. Zgodnie z przepisem Donelle, jeśli kliknę w środku tekstu, muszę kliknąć drugi raz, aby móc edytować. Jeśli kliknę gdzieś w tekście na zewnątrz tekstu, najprawdopodobniej oznacza to, że chcę rozpocząć edycję zamiast nadpisywania wszystkiego.
Siergiej Aldoukhov
źródło
Jeśli będziesz miał więcej niż jedną formę, jej odpowiedź będzie mniej skomplikowana niż pierwsza. Użyteczność obu opcji jest dyskusyjna, ponieważ można zmienić sposób działania każdej z nich.
thepaulpage
1
@Sergey: Możesz zmienić zaakceptowaną odpowiedź na to pytanie, ponieważ od tamtej pory są lepsze odpowiedzi. Nie zamierzam sugerować mojego, ale mógłbyś;)
Grokys
Pytanie ma tag Silverlight, ale Silverlight w ogóle nie ma większości wydarzeń / żadnych zdarzeń podglądu. Którego rozwiązania należy użyć w przypadku Silverlight?
Valentin Kuzub
Link „Dlaczego skupienie się na WPF jest takie trudne?” jest zepsuty
Maxence
1
jak wspomniano w komentarzu na stackoverflow.com/a/2553297/492 poniżej, madprops.org/blog/wpf-textbox-selectall-on-focus jest łatwym rozwiązaniem i zachowuje oryginalne zachowanie Nouse. Umieściłem rejestrację zdarzenia w konstruktorze, ponieważ w aplikacji mam tylko jedną kontrolkę WPF.
CAD bloke

Odpowiedzi:

75

Nie wiem, dlaczego traci wybór w GotFocuswydarzeniu.

Ale jednym z rozwiązań jest dokonanie wyboru GotKeyboardFocusi GotMouseCapturewydarzeń. W ten sposób zawsze będzie działać.

gcores
źródło
10
Nie. Po kliknięciu myszą w środku istniejącego tekstu wybór zostaje utracony, gdy tylko zwolniony zostanie przycisk myszy.
Siergiej Aldoukhov,
3
Chociaż - po drugim kliknięciu ponownie zaznacza cały tekst ... Nie jestem pewien, czy jest to zamierzone zachowanie projektantów WPF, ale użyteczność nie jest taka zła. Inna różnica w stosunku do pojedynczego modułu obsługi GotFocus polega na tym, że kliknięcie pustego miejsca w TextBox powoduje zaznaczenie wszystkich.
Sergey Aldoukhov
3
To też było moje rozwiązanie na pięści. Ale zauważyłem, że użytkownicy są naprawdę zirytowani, gdy nie są w stanie zaznaczyć tekstu za pomocą myszy, ponieważ za każdym razem, gdy klikają, cały tekst jest zaznaczany ...
Nils
1
Kolejną wadą tego rozwiązania jest to, że w przypadku korzystania z menu „Wytnij / Kopiuj / Wklej” w TextBox, cały tekst jest zaznaczany po wybraniu dowolnego elementu menu.
@gcores Wiem, że to jest stare, ale czy ktoś wie, dlaczego w zdarzeniu GotFocus wybrany tekst został utracony? Ale masz rację, że działa na innych wydarzeniach i jest to całkowicie akceptowalne rozwiązanie w mojej książce.
Feign
210

Mamy to, więc pierwsze kliknięcie wybiera wszystko, a kolejne kliknięcie przechodzi do kursora (nasza aplikacja jest przeznaczona do użytku na tabletach z długopisami).

Może ci się przydać.

public class ClickSelectTextBox : TextBox
{
    public ClickSelectTextBox()
    {
        AddHandler(PreviewMouseLeftButtonDownEvent, 
          new MouseButtonEventHandler(SelectivelyIgnoreMouseButton), true);
        AddHandler(GotKeyboardFocusEvent, 
          new RoutedEventHandler(SelectAllText), true);
        AddHandler(MouseDoubleClickEvent, 
          new RoutedEventHandler(SelectAllText), true);
    }

    private static void SelectivelyIgnoreMouseButton(object sender, 
                                                     MouseButtonEventArgs e)
    {
        // Find the TextBox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        if (parent != null)
        {
            var textBox = (TextBox)parent;
            if (!textBox.IsKeyboardFocusWithin)
            {
                // If the text box is not yet focussed, give it the focus and
                // stop further processing of this click event.
                textBox.Focus();
                e.Handled = true;
            }
        }
    }

    private static void SelectAllText(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }
}
Donnelle
źródło
9
Bardzo ci za to dziękuję. Działa to wspaniale i powinna być przyjętą odpowiedzią IMHO. Powyższy kod działa, gdy TextBox otrzymuje fokus za pomocą klawiatury lub myszy (i najwyraźniej rysika). +1
Drew Noakes
5
Zobaczyłem prawie identyczną odpowiedź tutaj social.msdn.microsoft.com/Forums/en-US/wpf/thread/… , działa również, jakkolwiek nie używa e.OriginalSource, ani nie czołga się po drzewie wizualnym. Czy jest jakaś korzyść z tego wszystkiego?
Marco Luglio
1
Działa świetnie, ale byłoby idealnie, gdyby nadal pozwalał na zaznaczanie tekstu za pomocą myszy. Pasek adresu Google Chrome jest doskonałym przykładem idealnego systemu: jeśli użytkownik kliknie i zwolni bez przeciągania, cały tekst zostanie podświetlony. Jednak jeśli użytkownik kliknie i przeciągnie, przeciągnięcie zaznacza tekst normalnie bez zaznaczania wszystkich. SelectAll występuje tylko po zwolnieniu myszy . Będę majstrować i sprawdzać, czy w ogóle mogę ulepszyć ten projekt.
devios1
2
Kolejną wadą tego rozwiązania jest to, że w przypadku korzystania z menu „Wytnij / Kopiuj / Wklej” w TextBox, cały tekst jest zaznaczany po wybraniu dowolnego elementu menu.
1
Stwierdziłem, że dodatkowy test w SelectAllTextmetodzie textBox.IsFocusedpoprawienia go. Nie chcesz wybierać wszystkiego, gdy GetKeyboardFocuswynika to z wciśnięcia klawisza Alt w programie.
Scott Stafford,
164

Odpowiedź Donnelle'a działa najlepiej, ale konieczność uzyskania nowej klasy, aby z niej skorzystać, to ból.

Zamiast tego rejestruję programy obsługi w App.xaml.cs dla wszystkich pól tekstowych w aplikacji. To pozwala mi używać odpowiedzi Donnelle'a ze standardową kontrolką TextBox.

Dodaj następujące metody do pliku App.xaml.cs:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e) 
    {
        // Select the text in a TextBox when it receives focus.
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseLeftButtonDownEvent,
            new MouseButtonEventHandler(SelectivelyIgnoreMouseButton));
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotKeyboardFocusEvent, 
            new RoutedEventHandler(SelectAllText));
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.MouseDoubleClickEvent,
            new RoutedEventHandler(SelectAllText));
        base.OnStartup(e); 
    }

    void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
    {
        // Find the TextBox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        if (parent != null)
        {
            var textBox = (TextBox)parent;
            if (!textBox.IsKeyboardFocusWithin)
            {
                // If the text box is not yet focused, give it the focus and
                // stop further processing of this click event.
                textBox.Focus();
                e.Handled = true;
            }
        }
    }

    void SelectAllText(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }
}
Grokys
źródło
4
To całkiem fajne rozwiązanie, zostało również opisane przez Matta Hamiltona przed wiekami tutaj: madprops.org/blog/wpf-textbox-selectall-on-focus
Ashley Davis
Mam trochę błędów ortograficznych w „otrzymuje”, „skupia się”
Nate Zaugg,
2
Dzięki Nate, poprawiony, choć w mojej obronie chciałbym wskazać, że błędy ortograficzne zostały skopiowane dosłownie z odpowiedzi Donnelle;)
Grokys
Pytanie ma tag Silverlight, ale Silverlight w ogóle nie ma większości wydarzeń / żadnych zdarzeń podglądu. Którego rozwiązania należy użyć w przypadku Silverlight? z góry dziękuję
Valentin Kuzub
4
„Koncentracja na pisowni jest znacznie bardziej powszechna w Stanach Zjednoczonych, jednak koncentracja na pisowni jest czasami używana w Wielkiej Brytanii i Kanadzie, a szczególnie w Australii i Nowej Zelandii”. Więc nyah;)
Donnelle
85

To dość stare, ale i tak wyświetlę moją odpowiedź.

Wybrałem część odpowiedzi Donnelle (pominąłem podwójne kliknięcie), ponieważ uważam, że jest to bardziej naturalne. Jednak, podobnie jak gcores, nie lubię potrzeby tworzenia klasy pochodnej. Ale nie lubię też OnStartupmetody gcores . Potrzebuję tego na zasadzie „ogólnie, ale nie zawsze”.

Zaimplementowałem to jako załącznik, DependencyPropertydzięki czemu mogę ustawić local:SelectTextOnFocus.Active = "True"w xaml. Najbardziej podoba mi się ten sposób.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

public class SelectTextOnFocus : DependencyObject
{
    public static readonly DependencyProperty ActiveProperty = DependencyProperty.RegisterAttached(
        "Active",
        typeof(bool),
        typeof(SelectTextOnFocus),
        new PropertyMetadata(false, ActivePropertyChanged));

    private static void ActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is TextBox)
        {
            TextBox textBox = d as TextBox;
            if ((e.NewValue as bool?).GetValueOrDefault(false))
            {
                textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
            }
            else
            {
                textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
            }
        }
    }

    private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DependencyObject dependencyObject = GetParentFromVisualTree(e.OriginalSource);

        if (dependencyObject == null)
        {
            return;
        }

        var textBox = (TextBox)dependencyObject;
        if (!textBox.IsKeyboardFocusWithin)
        {
            textBox.Focus();
            e.Handled = true;
        }
    }

    private static DependencyObject GetParentFromVisualTree(object source)
    {
        DependencyObject parent = source as UIElement;
        while (parent != null && !(parent is TextBox))
        {
            parent = VisualTreeHelper.GetParent(parent);
        }

        return parent;
    }

    private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
    {
        TextBox textBox = e.OriginalSource as TextBox;
        if (textBox != null)
        {
            textBox.SelectAll();
        }
    }

    [AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(TextBox))]
    public static bool GetActive(DependencyObject @object)
    {
        return (bool) @object.GetValue(ActiveProperty);
    }

    public static void SetActive(DependencyObject @object, bool value)
    {
        @object.SetValue(ActiveProperty, value);
    }
}

Dla mojej funkcji „ogólnej, ale nie zawsze” ustawiłem tę właściwość Attache na True(globalną) TextBox Style. W ten sposób „zaznaczanie tekstu” jest zawsze „włączone”, ale mogę je wyłączyć dla poszczególnych pól tekstowych.

Nils
źródło
8
+1 jest o wiele lepsze niż ustawianie go globalnie i jest bardziej „sposobem WPF” niż pochodzeniem z TextBox.
stijn
3
+1 Zgadzam się ze stijn. „Ukrywanie” kodu w app.cs nie jest miłe dla biednego programisty, który musi dowiedzieć się, dlaczego SelectAllOnFocus się dzieje. :-) Właśnie upuściłem to na moją klasę dla TextBoxBehaviors, a następnie zaktualizowałem swój podstawowy styl TextBox. Pracowałem przysmak. Na zdrowie
Lee Campbell,
2
@tronda: Po prostu dodaj styl do zasobów za pomocą TargetType TextBox. Proponuję rzucić
Nils
2
Kolejne +1 za najlepszą odpowiedź. Jedyny problem, jaki widzę, to to, że tekst jest zawsze zaznaczany, nawet gdy używam prawego przycisku myszy - co często robię, aby edytować tekst za pomocą menu kontekstowego - rozwiązanie nie działa w tym przypadku, ponieważ zawsze zaznacza cały tekst, nawet jeśli chciałem tylko wyciąć 1 słowo za pomocą menu kontekstowego. Czy wiecie, jak to naprawić?
user3313608,
2
Podoba mi się ta odpowiedź, ale dlaczego musisz rozszerzyć DependencyObject? Usunąłem to i nadal działa dobrze.
Fred
47

Oto zachowania mieszania implementujące rozwiązanie odpowiedzi dla Twojej wygody:

Jeden do dołączania do pojedynczego TextBox:

public class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
        AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
        AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
        AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
        AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
    }

    private void AssociatedObjectGotKeyboardFocus(object sender,
        System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        AssociatedObject.SelectAll();
    }

    private void AssociatedObjectGotMouseCapture(object sender,
        System.Windows.Input.MouseEventArgs e)
    {
        AssociatedObject.SelectAll();   
    }

    private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if(!AssociatedObject.IsKeyboardFocusWithin)
        {
            AssociatedObject.Focus();
            e.Handled = true;
        }
    }
}

I jeden do dołączenia do katalogu głównego kontenera zawierającego wiele TextBoxów:

public class SelectAllTextOnFocusMultiBehavior : Behavior<UIElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.GotKeyboardFocus += HandleKeyboardFocus;
        AssociatedObject.GotMouseCapture += HandleMouseCapture;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.GotKeyboardFocus -= HandleKeyboardFocus;
        AssociatedObject.GotMouseCapture -= HandleMouseCapture;
    }

    private static void HandleKeyboardFocus(object sender,
        System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        var txt = e.NewFocus as TextBox;
        if (txt != null)
            txt.SelectAll();
    }

    private static void HandleMouseCapture(object sender,
        System.Windows.Input.MouseEventArgs e)
    {
        var txt = e.OriginalSource as TextBox;
        if (txt != null)
            txt.SelectAll();
    }
}
Siergiej Aldoukhov
źródło
To zdecydowanie najlepsze i najczystsze rozwiązanie. Wielkie dzięki za udostępnienie.
Golvellius
Wygląda naprawdę ładnie, ale z jakiegoś powodu łamie kontrolę nad kartami ... Wiesz, dlaczego?
Marc
Chciałbym użyć twojego rozwiązania. Ale naprawdę zagubiony ... może masz próbkę?
Juan Pablo Gomez
Kiedy klikniesz gdzieś w polu tekstowym, mając fokus (wyobraź sobie, że chcesz przenieść karetkę w inne miejsce), ponownie wybierze wszystko zamiast przesuwać karetkę. To nieoczekiwane. Naprawiono to, zastępując GotMouseCapture przez MouseDoubleClick, co jest powszechne. Dzięki tym ostatnim rozwiązaniom MSDN.
norekhov
1
Wygląda na to, że nie działa, gdy pole tekstowe zostanie wstępnie ustawione za pomocą FocusManager.FocusedElement. Jakieś pomysły, dlaczego?
szx
24

Chociaż jest to stare pytanie, właśnie miałem ten problem, ale rozwiązałem go za pomocą zachowania związanego z przywiązaniem, a nie zachowania wyrażania, jak w odpowiedzi Siergieja. Oznacza to, że nie potrzebuję zależności System.Windows.Interactivityw Blend SDK:

public class TextBoxBehavior
{
    public static bool GetSelectAllTextOnFocus(TextBox textBox)
    {
        return (bool)textBox.GetValue(SelectAllTextOnFocusProperty);
    }

    public static void SetSelectAllTextOnFocus(TextBox textBox, bool value)
    {
        textBox.SetValue(SelectAllTextOnFocusProperty, value);
    }

    public static readonly DependencyProperty SelectAllTextOnFocusProperty =
        DependencyProperty.RegisterAttached(
            "SelectAllTextOnFocus",
            typeof (bool),
            typeof (TextBoxBehavior),
            new UIPropertyMetadata(false, OnSelectAllTextOnFocusChanged));

    private static void OnSelectAllTextOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBox = d as TextBox;
        if (textBox == null) return;

        if (e.NewValue is bool == false) return;

        if ((bool) e.NewValue)
        {
            textBox.GotFocus += SelectAll;
            textBox.PreviewMouseDown += IgnoreMouseButton;
        }
        else
        {
            textBox.GotFocus -= SelectAll;
            textBox.PreviewMouseDown -= IgnoreMouseButton;
        }
    }

    private static void SelectAll(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox == null) return;
        textBox.SelectAll();
    }

    private static void IgnoreMouseButton(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        var textBox = sender as TextBox;
        if (textBox == null || (!textBox.IsReadOnly && textBox.IsKeyboardFocusWithin)) return;

        e.Handled = true;
        textBox.Focus();
    }
}

Następnie możesz użyć go w swojej XAML w następujący sposób:

<TextBox Text="Some Text" behaviors:TextBoxBehavior.SelectAllTextOnFocus="True"/>

Napisałem o tym tutaj blog .

Dutts
źródło
Podoba mi się to podejście, ale metody Get / Set nie powinny kończyć się na „Właściwość”; Musiałem to usunąć, aby uzyskać kompilację kodu po dodaniu części Xaml.
Patrick Quirk
Bardzo fajnie, działał zgodnie z oczekiwaniami. Podoba mi się to, ponieważ pomaga mi zachować oddzielne obawy dotyczące widoku podczas wykonywania MVVM.
Killnine
16

Oto bardzo dobre bardzo proste rozwiązanie na MSDN :

<TextBox
    MouseDoubleClick="SelectAddress"
    GotKeyboardFocus="SelectAddress"
    PreviewMouseLeftButtonDown="SelectivelyIgnoreMouseButton" />

Oto kod za:

private void SelectAddress(object sender, RoutedEventArgs e)
{
    TextBox tb = (sender as TextBox);
    if (tb != null)
    {
        tb.SelectAll();
    }
}

private void SelectivelyIgnoreMouseButton(object sender,
    MouseButtonEventArgs e)
{
    TextBox tb = (sender as TextBox);
    if (tb != null)
    {
        if (!tb.IsKeyboardFocusWithin)
        {
            e.Handled = true;
            tb.Focus();
        }
    }
}
BillBR
źródło
1
Zasadniczo jest to to samo rozwiązanie, które jest najwyżej oceniane w tym wątku. Ale odkąd to dwa lata wcześniej, teraz wiem, skąd @Donnelle go pożyczył;)
Siergiej Aldoukhov
To rozwiązanie wydawało mi się najłatwiejsze i działało dla mnie. Chciałem, aby określony podzbiór tekstu był domyślnie zaznaczony podczas wchodzenia do pola tekstowego.
Jack B Nimble
10

Myślę, że to działa dobrze:

private void ValueText_GotFocus(object sender, RoutedEventArgs e)
{
    TextBox tb = (TextBox)e.OriginalSource;
    tb.Dispatcher.BeginInvoke(
        new Action(delegate
            {
                tb.SelectAll();
            }), System.Windows.Threading.DispatcherPriority.Input);
}

Jeśli chcesz zaimplementować go jako metodę rozszerzenia:

public static void SelectAllText(this System.Windows.Controls.TextBox tb)
{
    tb.Dispatcher.BeginInvoke(
        new Action(delegate
        {
            tb.SelectAll();
        }), System.Windows.Threading.DispatcherPriority.Input);
}

A w twoim GotFocusprzypadku:

private void ValueText_GotFocus(object sender, RoutedEventArgs e)
{
    TextBox tb = (TextBox)e.OriginalSource;
    tb.SelectAllText();
}

Odkryłem powyższe rozwiązanie, ponieważ kilka miesięcy temu szukałem sposobu na skupienie się na danym UIElement. Odkryłem gdzieś kod poniżej (tutaj kredyt) i działa dobrze. Publikuję go, mimo że nie jest to bezpośrednio związane z pytaniem PO, ponieważ pokazuje ten sam wzorzec używania Dispatcherdo pracy z UIElement.

// Sets focus to uiElement
public static void DelayedFocus(this UIElement uiElement)
{
    uiElement.Dispatcher.BeginInvoke(
    new Action(delegate
    {
        uiElement.Focusable = true;
        uiElement.Focus();
        Keyboard.Focus(uiElement);
    }),
    DispatcherPriority.Render);
}
Sam
źródło
To chyba najprostsza metoda do wdrożenia. po utworzeniu metody rozszerzenia wystarczy wywołać myTextBox.SelectAllText (). Dlaczego ta odpowiedź nie otrzymała więcej punktów? dlaczego inne rozwiązania są o wiele lepsze?
Tono Nam
2
Unikałbym tej metody, ponieważ polega ona na wywołaniu asynchronicznym uruchamianym po module obsługi MouseUp pola tekstowego. Nie ufałbym, że jest to w 100% deterministyczne i może prowadzić do niespójnego zachowania. Chociaż może się to zdarzyć mało prawdopodobne, wolę zastosować powyższe metody pewników.
Rob H
6

Oto próba rozwiązania niektórych problemów z innymi rozwiązaniami:

  1. Korzystanie z menu kontekstowego kliknięcia prawym przyciskiem myszy dla wycinania / kopiowania / przeszłości zaznacza cały tekst, nawet jeśli nie zaznaczyłeś go wszystkich.
  2. Po powrocie z menu kontekstowego prawym przyciskiem myszy cały tekst jest zawsze zaznaczony.
  3. Po powrocie do aplikacji za pomocą Alt+ Tabcały tekst jest zawsze zaznaczony.
  4. Podczas próby zaznaczenia tylko części tekstu za pierwszym kliknięciem wszystko jest zawsze zaznaczone (w przeciwieństwie do paska adresu Google Chrome na przykład).

Kod, który napisałem, jest konfigurowalny. Można wybrać na jakie działania zaznaczyć cały zachowanie powinno nastąpić poprzez ustawienie trzech tylko do odczytu pola: SelectOnKeybourdFocus, SelectOnMouseLeftClick, SelectOnMouseRightClick.

Minusem tego rozwiązania jest to, że jest ono bardziej złożone, a stan statyczny jest przechowywany. Wygląda to na brzydką walkę z domyślnym zachowaniem TextBoxkontroli. Nadal działa, a cały kod jest ukryty w klasie kontenera Attached Property.

public static class TextBoxExtensions
{
    // Configuration fields to choose on what actions the select all behavior should occur.
    static readonly bool SelectOnKeybourdFocus = true;
    static readonly bool SelectOnMouseLeftClick = true;
    static readonly bool SelectOnMouseRightClick = true;

    // Remembers a right click context menu that is opened 
    static ContextMenu ContextMenu = null;

    // Remembers if the first action on the TextBox is mouse down 
    static bool FirstActionIsMouseDown = false;

    public static readonly DependencyProperty SelectOnFocusProperty =
        DependencyProperty.RegisterAttached("SelectOnFocus", typeof(bool), typeof(TextBoxExtensions), new PropertyMetadata(false, new PropertyChangedCallback(OnSelectOnFocusChanged)));

    [AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(TextBox))]
    public static bool GetSelectOnFocus(DependencyObject obj)
    {
        return (bool)obj.GetValue(SelectOnFocusProperty);
    }

    public static void SetSelectOnFocus(DependencyObject obj, bool value)
    {
        obj.SetValue(SelectOnFocusProperty, value);
    }

    private static void OnSelectOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is TextBox textBox)) return;

        if (GetSelectOnFocus(textBox))
        {
            // Register events
            textBox.PreviewMouseDown += TextBox_PreviewMouseDown;
            textBox.PreviewMouseUp += TextBox_PreviewMouseUp;
            textBox.GotKeyboardFocus += TextBox_GotKeyboardFocus;
            textBox.LostKeyboardFocus += TextBox_LostKeyboardFocus;
        }
        else
        {
            // Unregister events
            textBox.PreviewMouseDown -= TextBox_PreviewMouseDown;
            textBox.PreviewMouseUp -= TextBox_PreviewMouseUp;
            textBox.GotKeyboardFocus -= TextBox_GotKeyboardFocus;
            textBox.LostKeyboardFocus -= TextBox_LostKeyboardFocus;
        }
    }

    private static void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // If mouse clicked and focus was not in text box, remember this is the first click.
        // This will enable to prevent select all when the text box gets the keyboard focus 
        // right after the mouse down event.
        if (!textBox.IsKeyboardFocusWithin)
        {
            FirstActionIsMouseDown = true;
        }
    }

    private static void TextBox_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // Select all only if:
        // 1) SelectOnMouseLeftClick/SelectOnMouseRightClick is true and left/right button was clicked
        // 3) This is the first click
        // 4) No text is selected
        if (((SelectOnMouseLeftClick && e.ChangedButton == MouseButton.Left) || 
            (SelectOnMouseRightClick && e.ChangedButton == MouseButton.Right)) &&
            FirstActionIsMouseDown &&
            string.IsNullOrEmpty(textBox.SelectedText))
        {
            textBox.SelectAll();
        }

        // It is not the first click 
        FirstActionIsMouseDown = false;
    }

    private static void TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // Select all only if:
        // 1) SelectOnKeybourdFocus is true
        // 2) Focus was not previously out of the application (e.OldFocus != null)
        // 3) The mouse was pressed down for the first after on the text box
        // 4) Focus was not previously in the context menu
        if (SelectOnKeybourdFocus &&
            e.OldFocus != null &&
            !FirstActionIsMouseDown &&
            !IsObjectInObjectTree(e.OldFocus as DependencyObject, ContextMenu))
        {
            textBox.SelectAll();
        }

        // Forget ContextMenu
        ContextMenu = null;
    }

    private static void TextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // Remember ContextMenu (if opened)
        ContextMenu = e.NewFocus as ContextMenu;

        // Forget selection when focus is lost if:
        // 1) Focus is still in the application
        // 2) The context menu was not opened
        if (e.NewFocus != null
            && ContextMenu == null)
        {
            textBox.SelectionLength = 0;
        }
    }

    // Helper function to look if a DependencyObject is contained in the visual tree of another object
    private static bool IsObjectInObjectTree(DependencyObject searchInObject, DependencyObject compireToObject)
    {
        while (searchInObject != null && searchInObject != compireToObject)
        {
            searchInObject = VisualTreeHelper.GetParent(searchInObject);
        }

        return searchInObject != null;
    }
}

Aby dołączyć właściwość Attached do a TextBox, wystarczy dodać przestrzeń nazw xml ( xmlns) właściwości Attached, a następnie użyć jej w następujący sposób:

<TextBox attachedprop:TextBoxExtensions.SelectOnFocus="True"/>

Kilka uwag na temat tego rozwiązania:

  1. Aby zastąpić domyślne zachowanie zdarzenia opuszczenia myszy i umożliwić zaznaczenie tylko części tekstu przy pierwszym kliknięciu, cały tekst jest zaznaczany przy zdarzeniu w górę.
  2. Musiałem sobie poradzić z faktem, że TextBoxpamięta swój wybór po tym, jak stracił koncentrację. Właściwie zastąpiłem to zachowanie.
  3. Musiałem pamiętać, czy naciśnięcie przycisku myszy to pierwsza akcja na TextBox( FirstActionIsMouseDownpolu statycznym).
  4. Musiałem zapamiętać menu kontekstowe otwarte prawym przyciskiem myszy ( ContextMenupole statyczne).

Jedynym efektem ubocznym, który znalazłem, jest to, kiedy SelectOnMouseRightClickjest prawdziwe. Czasami menu kontekstowe kliknięcia prawym przyciskiem miga, gdy jest otwarte, a kliknięcie prawym przyciskiem myszy pustego miejsca TextBoxnie powoduje „zaznaczenia wszystkiego”.

Eliahu Aaron
źródło
5

Nie znalazłem żadnej z odpowiedzi tutaj naśladujących standardowy tekstowy Windows. Na przykład spróbuj kliknąć biały znak między ostatnim znakiem pola tekstowego a prawą stroną pola tekstowego. Większość rozwiązań tutaj zawsze wybierze całą treść, co bardzo utrudnia dołączenie tekstu do pola tekstowego.

Odpowiedź, którą tu przedstawiam, zachowuje się lepiej pod tym względem. Jest to zachowanie (więc wymaga zestawu System.Windows.Interactivity z Blend SDK ). Można go przepisać również przy użyciu dołączonych właściwości.

public sealed class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
    }

    void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        // Find the textbox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        var textBox = parent as TextBox;
        Debug.Assert(textBox != null);

        if (textBox.IsFocused) return;

        textBox.SelectAll();
        Keyboard.Focus(textBox);
        e.Handled = true;
    }
}

Jest to oparte na kodzie, który tu znalazłem .

Kristof Verbiest
źródło
1
Chociaż jest to dobra odpowiedź, myślę, że kiedy użytkownik kliknie białe pole, jego intencją (w aplikacji biznesowej) jest najprawdopodobniej zastąpienie całej wartości, więc wybór wszystkiego jest właściwym podejściem.
Sergey Aldoukhov
1
Siergiej: pierwsze kliknięcie wybierze całą wartość, drugie kliknięcie umieści kursor po prawej stronie wartości. W innych prezentowanych rozwiązaniach drugie kliknięcie spowoduje utrzymanie całej wartości wybranej, co bardzo utrudni dołączenie do tej wartości.
Kristof Verbiest
Jak to jest używane? Dodałem ten kod do App.xaml.cs, ale nie wydawało się, aby miało to wpływ na TextBoxes w mojej aplikacji.
PIntag
5

Ta prosta implementacja działa dla mnie idealnie:

void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    ((TextBox) sender).SelectAll();
}

void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    var TextBox = (TextBox) sender;
    if (!TextBox.IsKeyboardFocusWithin)
    {
        TextBox.Focus();
        e.Handled = true;
    }
}

Aby zastosować go do wszystkich TextBox, wstaw następujący kod poInitializeComponent();

EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(TextBox_GotFocus));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseDownEvent, new MouseButtonEventHandler(TextBox_PreviewMouseDown));
Danny Beckett
źródło
4

W pliku App.xaml:

<Application.Resources>
    <Style TargetType="TextBox">
        <EventSetter Event="GotKeyboardFocus" Handler="TextBox_GotKeyboardFocus"/>
    </Style>
</Application.Resources>

W pliku App.xaml.cs:

private void TextBox_GotKeyboardFocus(Object sender, KeyboardFocusChangedEventArgs e)
{
    ((TextBox)sender).SelectAll();
}

Dzięki temu kodowi osiągniesz wszystko TextBoxw swojej aplikacji.

Darshan Faldu
źródło
3

Zaczerpnięte stąd :

Zarejestruj globalną procedurę obsługi zdarzeń w pliku App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    EventManager.RegisterClassHandler(typeof(TextBox),TextBox.GotFocusEvent,
    new RoutedEventHandler(TextBox_GotFocus));

    base.OnStartup(e);
}

Zatem program obsługi jest tak prosty jak:

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    (sender as TextBox).SelectAll();
}
Neomoon
źródło
3

Zdaję sobie sprawę, że to bardzo stare, ale oto moje rozwiązanie oparte na interaktywności wyrażeń / microsoft i przestrzeni nazw interakcji.

Najpierw postępowałem zgodnie z instrukcjami pod tym linkiem, aby umieścić wyzwalacze interaktywne w stylu.

Sprowadza się to do tego

<Style x:Key="baseTextBox" TargetType="TextBox">
  <Setter Property="gint:InteractivityItems.Template">
    <Setter.Value>
      <gint:InteractivityTemplate>
        <gint:InteractivityItems>
          <gint:InteractivityItems.Triggers>
            <i:EventTrigger EventName="GotKeyboardFocus">
              <ei:CallMethodAction MethodName="SelectAll"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="PreviewMouseLeftButtonDown">
              <ei:CallMethodAction MethodName="TextBox_PreviewMouseLeftButtonDown"
                TargetObject="{Binding ElementName=HostElementName}"/>
            </i:EventTrigger>
          </gint:InteractivityItems.Triggers>
        </gint:InteractivityItems>
      </gint:InteractivityTemplate>
    </Setter.Value>
  </Setter>
</Style>

i to

public void TextBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
  TextBox tb = e.Source as TextBox;
  if((tb != null) && (tb.IsKeyboardFocusWithin == false))
  {
    tb.Focus();
    e.Handled = true;
  }
}

W moim przypadku mam kontrolę użytkownika, gdzie pola tekstowe mają kod. Kod-back ma funkcję handlera. Nadałem mojej kontroli nazwę w XAML i używam tej nazwy dla elementu. To działa idealnie dla mnie. Po prostu zastosuj styl w dowolnym TextBoxmiejscu, w którym chcesz zaznaczyć cały tekst po kliknięciu wTextBox .

Pierwszy CallMethodActionwywołuje SelectAllmetodę pola tekstowego, gdy GotKeyboardFocuszdarzenie jest TextBoxuruchamiane.

Mam nadzieję, że to pomoże.

wiyosaya
źródło
Ponieważ są to tak stare pytania, może pomóc ci w zwróceniu uwagi, jeśli powiesz, dlaczego ktoś może wybrać takie podejście.
dywizja
Po pierwsze, nie trzeba tego umieszczać w stylu, ale myślę, że jest oczywiste, że istnieje wiele formantów pól tekstowych, które tego potrzebują, styl jest właściwą drogą.
wiyosaya
1
Być może niektórzy nie zgodzą się z tym podejściem, jednak ze względu na to, dlaczego warto zastosować to podejście, nie wymaga ono podklasowania TextBox, rejestrowania zdarzeń obsługi klas, metod rozszerzania, tworzenia dołączonych właściwości itp. Jako styl można go również dodać do słownika zasobów dowolnego projektu xaml. Bez klucza x: byłby zastosowany do dowolnej instancji TextBox w zakresie słownika zasobów bez konieczności zmiany xaml każdego pojedynczego pola tekstowego. W niektórych przypadkach może to być czystsze podejście.
wiyosaya
2

Użyłem odpowiedzi Nilsa, ale zmieniłem na bardziej elastyczny.

public enum SelectAllMode
{

    /// <summary>
    ///  On first focus, it selects all then leave off textbox and doesn't check again
    /// </summary>
    OnFirstFocusThenLeaveOff = 0,

    /// <summary>
    ///  On first focus, it selects all then never selects
    /// </summary>
    OnFirstFocusThenNever = 1,

    /// <summary>
    /// Selects all on every focus
    /// </summary>
    OnEveryFocus = 2,

    /// <summary>
    /// Never selects text (WPF's default attitude)
    /// </summary>
    Never = 4,
}

public partial class TextBox : DependencyObject
{
    public static readonly DependencyProperty SelectAllModeProperty = DependencyProperty.RegisterAttached(
        "SelectAllMode",
        typeof(SelectAllMode?),
        typeof(TextBox),
        new PropertyMetadata(SelectAllModePropertyChanged));

    private static void SelectAllModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is System.Windows.Controls.TextBox)
        {
            var textBox = d as System.Windows.Controls.TextBox;

            if (e.NewValue != null)
            {
                textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
            }
            else
            {
                textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
            }
        }
    }

    private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DependencyObject dependencyObject = GetParentFromVisualTree(e.OriginalSource);

        if (dependencyObject == null)
            return;

        var textBox = (System.Windows.Controls.TextBox)dependencyObject;
        if (!textBox.IsKeyboardFocusWithin)
        {
            textBox.Focus();
            e.Handled = true;
        }
    }

    private static DependencyObject GetParentFromVisualTree(object source)
    {
        DependencyObject parent = source as UIElement;
        while (parent != null && !(parent is System.Windows.Controls.TextBox))
        {
            parent = VisualTreeHelper.GetParent(parent);
        }

        return parent;
    }

    private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
    {
        var textBox = e.OriginalSource as System.Windows.Controls.TextBox;
        if (textBox == null) return;

        var selectAllMode = GetSelectAllMode(textBox);

        if (selectAllMode == SelectAllMode.Never)
        {
            textBox.SelectionStart = 0;
            textBox.SelectionLength = 0;
        }
        else
            textBox.SelectAll();

        if (selectAllMode == SelectAllMode.OnFirstFocusThenNever)
            SetSelectAllMode(textBox, SelectAllMode.Never);
        else if (selectAllMode == SelectAllMode.OnFirstFocusThenLeaveOff)
            SetSelectAllMode(textBox, null);
    }

    [AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(System.Windows.Controls.TextBox))]
    public static SelectAllMode? GetSelectAllMode(DependencyObject @object)
    {
        return (SelectAllMode)@object.GetValue(SelectAllModeProperty);
    }

    public static void SetSelectAllMode(DependencyObject @object, SelectAllMode? value)
    {
        @object.SetValue(SelectAllModeProperty, value);
    }
}

W XAML możesz użyć jednego z tych:

<!-- On first focus, it selects all then leave off textbox and doesn't check again -->
<TextBox attprop:TextBox.SelectAllMode="OnFirstFocusThenLeaveOff" />

<!-- On first focus, it selects all then never selects -->
<TextBox attprop:TextBox.SelectAllMode="OnFirstFocusThenNever" />

<!-- Selects all on every focus -->
<TextBox attprop:TextBox.SelectAllMode="OnEveryFocus" />

<!-- Never selects text (WPF's default attitude) -->
<TextBox attprop:TextBox.SelectAllMode="Never" />
Bafsar
źródło
1
Naprawdę dobre rozwiązanie do użycia w szablonach, ponieważ można powiązać go z XAML bez żadnego rzeczywistego kodu, tylko rozszerzone zachowanie pola tekstowego.
Eric Johansson,
2

Oto wersja C # odpowiedzi opublikowanej przez @Nasenbaer

private delegate void TextBoxSelectAllDelegate(object sender);

private void TextBoxSelectAll(object sender)
{
    (sender as System.Windows.Controls.TextBox).SelectAll();
}

private void MyTextBox_GotFocus(object sender, System.Windows.RoutedEventArgs e)
{
    TextBoxSelectAllDelegate d = TextBoxSelectAll;

    this.Dispatcher.BeginInvoke(d,
        System.Windows.Threading.DispatcherPriority.ApplicationIdle, sender);
}

mając na uwadze, MyTextBox_GotFocusże procedura obsługi zdarzeń jest przypisana do GotFocuszdarzenia MyTextBox.

ViRuSTriNiTy
źródło
2

Mam na to nieco uproszczoną odpowiedź (tylko z PreviewMouseLeftButtonDown wydarzeniem), która wydaje się naśladować zwykłą funkcjonalność przeglądarki:

W XAML masz do TextBoxpowiedzenia:

<TextBox Text="http://www.blabla.com" BorderThickness="2" BorderBrush="Green" VerticalAlignment="Center" Height="25"
                 PreviewMouseLeftButtonDown="SelectAll" />

W codebehind:

private void SelectAll(object sender, MouseButtonEventArgs e)
{
    TextBox tb = (sender as TextBox);

    if (tb == null)
    {
        return;
    }

    if (!tb.IsKeyboardFocusWithin)
    {
        tb.SelectAll();
        e.Handled = true;
        tb.Focus();
    }
}
Danield
źródło
1
Może chcesz dodać zdarzenie GotKeyboardFocus z TextBox.SelectAll () w środku dla osób, które chodzą po Twojej aplikacji. Twoje rozwiązanie działa również dla PasswordBoxes (ponieważ PasswordBoxes są zapieczętowanymi typami, nie można ich rozszerzać).
David Sherret
1

Wypróbuj tę metodę rozszerzenia, aby dodać pożądane zachowanie do dowolnej kontrolki TextBox. Jeszcze go nie testowałem, ale wydaje się, że spełnia moje potrzeby.

public static class TextBoxExtensions
{
    public static void SetupSelectAllOnGotFocus(this TextBox source)
    {
        source.GotFocus += SelectAll;
        source.PreviewMouseLeftButtonDown += SelectivelyIgnoreMouseButton;
    }

    private static void SelectAll(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }

    private static void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
    {
        var textBox = (sender as TextBox);
        if (textBox != null)
        {
            if (!textBox.IsKeyboardFocusWithin)
            {
                e.Handled = true;
                textBox.Focus();
            }
        }
    }
}
David Kirkland
źródło
1

Dużo szukałem rozwiązania, znalazłem kilka rozwiązań, aby wybrać wszystkie Ale problem polega na tym, że po kliknięciu prawym przyciskiem myszy i wycięciu / skopiowaniu po zaznaczeniu części tekstu z pola tekstowego zaznacza się wszystko, nawet ja zaznaczyłem część tekstu. Aby to naprawić, oto rozwiązanie. Wystarczy dodać poniższy kod w zdarzeniu Wybierz na klawiaturze. To zadziałało dla mnie.

private static void SelectContentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is TextBox)
    {
        TextBox textBox = d as TextBox;
        if ((e.NewValue as bool?).GetValueOrDefault(false))
        {
            textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;                 
        }
        else
        {
            textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;

        }
    }
}


private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
{
    if (e.KeyboardDevice.IsKeyDown(Key.Tab))
        ((TextBox)sender).SelectAll();
}
Sambu Praveen
źródło
1

Miałem ten sam problem. W VB.Net działa to w ten sposób łatwo:

VB XAML:

<TextBox x:Name="txtFilterFrequency" />

Codehind:

Private Sub txtFilterText_GotFocus(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles txtFilterText.GotFocus
    Me.Dispatcher.BeginInvoke(Sub()
                                  txtFilterText.SelectAll()
                              End Sub, DispatcherPriority.ApplicationIdle, Nothing)
End Sub

C # (dzięki ViRuSTriNiTy)

private delegate void TextBoxSelectAllDelegate(object sender);

private void TextBoxSelectAll(object sender)
{
    (sender as System.Windows.Controls.TextBox).SelectAll();
}

private void MyTextBox_GotFocus(object sender, System.Windows.RoutedEventArgs e)
{
    TextBoxSelectAllDelegate d = TextBoxSelectAll;

    this.Dispatcher.BeginInvoke(d,
        System.Windows.Threading.DispatcherPriority.ApplicationIdle, sender);
}
Nasenbaer
źródło
Najlepsze rozwiązanie dla mnie, opublikowałem tłumaczenie C # tutaj: stackoverflow.com/a/48385409/3936440
ViRuSTriNiTy
Dla mnie takie podejście czasami nie wybiera tekstu. Myślę, że to warunek wyścigu dzięki BeginInvoke.
Vimes
Proszę sprecyzuj. Priorytet programu rozsyłającego działa zgodnie z oczekiwaniami na aplikacjach domyślnych. Jaka jest twoja sytuacja Czy próbowałeś dokładnie tak, jak opisano? Coś wyjątkowego w twoim rozwiązaniu?
Nasenbaer
1

To zdecydowanie najprostsze rozwiązanie.

Dodaj globalny moduł obsługi do aplikacji (App.xaml.cs) i gotowe. Będziesz potrzebował tylko kilku wierszy kodu.

protected override void OnStartup(StartupEventArgs e)
{
    EventManager.RegisterClassHandler(typeof(TextBox),
        TextBox.GotFocusEvent,
        new RoutedEventHandler(TextBox_GotFocus));

    base.OnStartup(e);
}

Dlatego użyj klasy EventManager, aby zarejestrować globalną procedurę obsługi zdarzeń dla typu (TextBox). Rzeczywisty moduł obsługi jest bardzo prosty:

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    (sender as TextBox).SelectAll();
}

Sprawdź tutaj: WPF TextBox SelectAll on Focus

Mam nadzieję, że to pomoże.

Marlon Assef
źródło
1

Dla osób zainteresowanych podejściem Donnelle / Groky, ale chcących kliknąć znak po prawej stronie ostatniego znaku (ale nadal wewnątrz TextBox), aby umieścić kursor na końcu wprowadzonego tekstu, opracowałem następujące rozwiązanie:

int GetRoundedCharacterIndexFromPoint(TextBox textBox, Point clickedPoint)
{
    int position = textBox.GetCharacterIndexFromPoint(clickedPoint, true);

    // Check if the clicked point is actually closer to the next character
    // or if it exceeds the righmost character in the textbox
    // (in this case return increase the position by 1)
    Rect charLeftEdge = textBox.GetRectFromCharacterIndex(position, false);
    Rect charRightEdge = textBox.GetRectFromCharacterIndex(position, true);
    double charWidth = charRightEdge.X - charLeftEdge.X;
    if (clickedPoint.X + charWidth / 2 > charLeftEdge.X + charWidth) position++;

    return position;
}

void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
{
    // Find the TextBox
    DependencyObject parent = e.OriginalSource as UIElement;
    while (parent != null && !(parent is TextBox))
        parent = VisualTreeHelper.GetParent(parent);

    if (parent != null)
    {
        var textBox = (TextBox)parent;
        if (!textBox.IsKeyboardFocusWithin)
        {
            // If the text box is not yet focused, give it the focus and
            // stop further processing of this click event.
            textBox.Focus();
            e.Handled = true;
        }
        else
        {
            int pos = GetRoundedCharacterIndexFromPoint(textBox, e.GetPosition(textBox));
            textBox.CaretIndex = pos;
        }
    }
}

void SelectAllText(object sender, RoutedEventArgs e)
{
    var textBox = e.OriginalSource as TextBox;
    if (textBox != null)
        textBox.SelectAll();
}

GetRoundedCharacterIndexFromPointMetoda została podjęta z tego postu.

PIntag
źródło
1
Działa dobrze, ale zdarzenie podwójnego kliknięcia nie jest uruchamiane
Rodrigo Caballero
W rzeczywistości wchodzi w zdarzenie doubleclick, ale właściwość OriginalSource jest typu TextBoxView. Tak więc metoda SelectAllText powinna wyglądać następująco: private static void SelectAllText (obiekt wysyłający, RoutedEventArgs e) {var textBox = e.OriginalSource jako TextBox; if (textBox! = null) {textBox.SelectAll (); System.Diagnostics.Debug.WriteLine („Selected ALL”); } else if (nadawca to TextBox) {(nadawca jako TextBox) .SelectAll (); }
Rodrigo Caballero,
1

Po googlowaniu i testowaniu znalazłem proste rozwiązanie, które działało dla mnie.

Musisz dodać moduł obsługi zdarzeń do Loadedzdarzenia w oknie kontenera:

private void yourwindow_Loaded(object sender, RoutedEventArgs e)
{
    EventManager.RegisterClassHandler(typeof(TextBox),
        TextBox.PreviewMouseLeftButtonDownEvent,
        new RoutedEventHandler(SelectivelyIgnoreMouseButton));
}

Następnie musisz utworzyć moduł obsługi do odwołania RoutedEventHandlerw poprzednim kodzie:

private void SelectivelyIgnoreMouseButton(object sender, RoutedEventArgs e)
{
    TextBox tb = (sender as TextBox);
    if (tb != null)
    {
        if (!tb.IsKeyboardFocusWithin)
        {
            e.Handled = true;
            tb.Focus();
        }
    }
}

Teraz możesz dodać SelectAll()polecenie w GotFocusmodułach obsługi zdarzeń do dowolnych TextBoxelementów sterujących osobno:

private void myTextBox_GotFocus(object sender, RoutedEventArgs e)
{
    (sender as TextBox).SelectAll();
}

Twój tekst jest teraz zaznaczony!

Zaadaptowano z rozwiązania Dr. WPF, Fora MSDN

DonBeto97
źródło
Właśnie użyłem: private async void TBTime_GotFocus (nadawca obiektu, RoutedEventArgs e) {TextBox tb = (TextBox) e.OriginalSource; czekają na Dispatcher.RunAsync (Windows.UI.Core.CoreDispatcherPriority.Normal, async () => {tb.SelectAll ();}); }
David Jones
1
#region TextBoxIDCard selection
private bool textBoxIDCardGotFocus = false;
private void TextBoxIDCard_GotFocus(object sender, RoutedEventArgs e)
{
    this.TextBoxIDCard.SelectAll();
}

private void TextBoxIDCard_LostFocus(object sender, RoutedEventArgs e)
{
    textBoxIDCardGotFocus = false;
}

private void TextBoxIDCard_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    if (textBoxIDCardGotFocus == false)
    {
        e.Handled = true;
        this.TextBoxIDCard.Focus();
        textBoxIDCardGotFocus = true;
    }
} 
#endregion
Brian
źródło
Jeśli masz 20 pól tekstowych w oknie, czy utworzysz 3 metody dla każdego pola tekstowego? To podejście nie jest dobre. Spójrz tutaj: rachel53461.wordpress.com/2011/11/05/…
Alexandru Dicu
0

Wydaje mi się, że to działa dobrze. Jest to w zasadzie podsumowanie niektórych wcześniejszych postów. Właśnie włożyłem to do mojego pliku MainWindow.xaml.cs w konstruktorze. Tworzę dwa moduły obsługi, jeden dla klawiatury i jeden dla myszy, i łączę oba zdarzenia w tej samej funkcji HandleGotFocusEvent, która jest zdefiniowana zaraz za konstruktorem w tym samym pliku.

public MainWindow()
{
   InitializeComponent();

   EventManager.RegisterClassHandler(typeof(TextBox), 
      UIElement.GotKeyboardFocusEvent,
      new RoutedEventHandler(HandleGotFocusEvent), true);
   EventManager.RegisterClassHandler(typeof(TextBox),
      UIElement.GotMouseCaptureEvent,
      new RoutedEventHandler(HandleGotFocusEvent), true);   
}
private void HandleGotFocusEvent(object sender, RoutedEventArgs e)
{
   if (sender is TextBox)
      (sender as TextBox).SelectAll();
}
Przetrząsać
źródło
Fajnie i łatwo, ale wydaje się, że ma problem z synchronizacją - przy każdej innej próbie (kliknięcie myszą) natychmiast odznacza ponownie ...?
T4NK3R
0

Prostym sposobem na przesłonięcie mouseDown i zaznaczenie wszystkich po podwójnym kliknięciu jest:

public class DoubleClickTextBox: TextBox
{

    public override void EndInit()
    {
        base.EndInit();            
    }

    protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
    {
        base.OnMouseEnter(e);
        this.Cursor = Cursors.Arrow;
    }
    protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {

    }

    protected override void OnMouseDoubleClick(System.Windows.Input.MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        this.SelectAll();
    }
}
Hesja
źródło
0

Spróbuj wstawić to do konstruktora dowolnego formantu zawierającego twoje pole tekstowe:

Loaded += (sender, e) =>
{
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    myTextBox.SelectAll();
}
CodeOtaku
źródło
To podejście nie działa, gdy umieścisz to w konstruktorze okien.
ViRuSTriNiTy
0

Jeśli zdarzenie usuwa zaznaczenie tekstu podczas OnFocusporuszania myszą, zwykle po prostu opóźniam zaznaczenie wszystkich.

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (TextBox.Text != null)
    {
        _ = Task.Run(() =>
        {
            Dispatcher.Invoke(
                async () => {
                    await Task.Delay(100);
                    TextBox.SelectAll();
                }
            );
        });
    }
}
milope
źródło
-1

Przetestowałem je wszystkie, ale tylko następujące działały:

protected override void OnStartup(StartupEventArgs e) 
{
    EventManager.RegisterClassHandler(typeof(TextBox), UIElement.PreviewMouseLeftButtonDownEvent,
   new MouseButtonEventHandler(SelectivelyHandleMouseButton), true);
    EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotKeyboardFocusEvent,
      new RoutedEventHandler(SelectAllText), true);
    EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotFocusEvent,
      new RoutedEventHandler(GotFocus), true);          
}

private static void SelectivelyHandleMouseButton(object sender, MouseButtonEventArgs e)
{
    var textbox = (sender as TextBox);
    if (textbox != null)
    {
        int hc = textbox.GetHashCode();
        if (hc == LastHashCode)
        {
            if (e.OriginalSource.GetType().Name == "TextBoxView")
            {
                e.Handled = true;
                textbox.Focus();
                LastHashCode = -1;
            }
        }
    }
    if (textbox != null) textbox.Focus();
}

private static void SelectAllText(object sender, RoutedEventArgs e)
{
    var textBox = e.OriginalSource as TextBox;
    if (textBox != null)
        textBox.SelectAll();
}

private static int LastHashCode;
private static void GotFocus(object sender, RoutedEventArgs e)
{
    var textBox = e.OriginalSource as TextBox;
    if (textBox != null)
        LastHashCode = textBox.GetHashCode();
}
Ehsan Zargar Ershadi
źródło
4
To także nieprzyzwoite niewłaściwe użycie kodów mieszających. Przeczytałbym to, link
RichK
3
A używanie GetType().Namezamiast islub asjest dość
hackerskie
-1

Widzę, że jest wiele odpowiedzi, ale jako zatwierdzona metoda, którą należy zastosować, jest EditTextBoxGotCapture

z następującym kodem za:

private void EditTextBoxGotCapture(object sender, MouseEventArgs e)
{
    if (sender is TextBox tb)
    {
        tb.Select(0, tb.Text.Length);
    }
}
Liviu Sosu
źródło