วิธีการเลือกข้อความทั้งหมดที่มุ่งเน้นใน WPF TextBox โดยอัตโนมัติ?


232

ถ้าฉันโทรSelectAllจากGotFocusตัวจัดการเหตุการณ์มันไม่สามารถใช้งานได้กับเมาส์ - การเลือกจะหายไปทันทีที่ปล่อยเมาส์

แก้ไข: ผู้คนชื่นชอบคำตอบของ Donnelle ฉันจะพยายามอธิบายว่าทำไมฉันถึงไม่ชอบเท่าคำตอบที่ยอมรับ

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

หากคุณจะมีมากกว่าหนึ่งรูปแบบคำตอบของเธอยังคงซับซ้อนน้อยกว่าแบบแรก การใช้งานของตัวเลือกทั้งสองนั้นเป็นสิ่งที่สงสัยในขณะที่คุณสามารถเปลี่ยนวิธีการทำงานของทั้งสอง
thepaulpage

1
@Sergey: คุณอาจต้องการเปลี่ยนคำตอบที่ยอมรับสำหรับคำถามนี้เนื่องจากมีคำตอบที่ดีกว่าตั้งแต่นั้นมา ฉันจะไม่ให้คำแนะนำในเหมือง แต่คุณสามารถ;)
Grokys

คำถามมีแท็ก Silverlight แต่ Silverlight ไม่มีกิจกรรมส่วนใหญ่ / กิจกรรมตัวอย่างใด ๆ เลย วิธีแก้ปัญหาใดที่ควรใช้กับ Silverlight?
Valentin Kuzub

ลิงก์ "ทำไมการโฟกัสใน WPF จึงยุ่งยากมาก" ถูกทำลาย
Maxence

1
ตามที่ระบุไว้ในความคิดเห็นในstackoverflow.com/a/2553297/492ด้านล่างmadprops.org/blog/wpf-textbox-selectall-on-focusเป็นวิธีการแก้ปัญหาที่ง่ายและคงไว้ซึ่งลักษณะนิสัยดั้งเดิม ฉันใส่การลงทะเบียนเหตุการณ์ในตัวสร้างเพราะฉันมีการควบคุม WPF เพียงหนึ่งเดียวในแอป
คนเจ้าหมอ CAD

คำตอบ:


75

ไม่ทราบว่าเพราะเหตุใดจึงสูญเสียการเลือกในGotFocusเหตุการณ์

แต่ทางออกหนึ่งคือการเลือกในGotKeyboardFocusและGotMouseCaptureเหตุการณ์ ด้วยวิธีนี้มันจะทำงานเสมอ


10
Nope เมื่อคลิกด้วยเมาส์ที่อยู่ตรงกลางของข้อความที่มีอยู่ - การเลือกจะหายไปทันทีที่ปล่อยปุ่มเมาส์
Sergey Aldoukhov

3
แม้ว่า - หลังจากคลิกครั้งที่สองมันจะเลือกข้อความทั้งหมดอีกครั้ง ... ไม่แน่ใจว่ามันเป็นพฤติกรรมที่ตั้งใจจากนักออกแบบ WPF แต่การใช้งานนั้นไม่เลว ข้อแตกต่างจากตัวจัดการ GotFocus เดียวก็คือการคลิกที่พื้นที่ว่างในกล่องข้อความจะเลือกทั้งหมด
Sergey Aldoukhov

3
นี่คือทางออกของฉันด้วย แต่ฉันพบว่าผู้ใช้รู้สึกรำคาญจริง ๆ เมื่อพวกเขาไม่สามารถเลือกข้อความโดยใช้เม้าส์ได้เพราะทุกครั้งที่พวกเขาคลิกข้อความทั้งหมดจะถูกเลือก ...
Nils

1
ข้อเสียอีกข้อหนึ่งของการแก้ปัญหานี้คือเมื่อคุณใช้เมนู "ตัด / คัดลอก / วาง" กล่องข้อความข้อความทั้งหมดจะถูกเลือกเมื่อคุณเลือกรายการเมนูใด ๆ

@gores ฉันรู้ว่ามันเก่า แต่ไม่มีใครรู้ว่าทำไมในเหตุการณ์ GotFocus ข้อความที่เลือกหายไป? คุณถูกต้องเกี่ยวกับมันทำงานในกิจกรรมอื่น ๆ แม้ว่าและนั่นเป็นทางออกที่ยอมรับอย่างสมบูรณ์ในหนังสือของฉัน
ปลอม

210

เรามีมันเพื่อให้คลิกครั้งแรกเลือกทั้งหมดและอีกคลิกไปที่เคอร์เซอร์ (แอปพลิเคชันของเราถูกออกแบบมาเพื่อใช้กับแท็บเล็ตด้วยปากกา)

คุณอาจพบว่ามันมีประโยชน์.

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();
    }
}

9
ขอบคุณมากสำหรับสิ่งนี้ มันใช้งานได้อย่างยอดเยี่ยมและควรเป็นคำตอบที่ได้รับการยอมรับจาก IMHO โค้ดด้านบนใช้งานได้เมื่อกล่องข้อความได้รับโฟกัสผ่านแป้นพิมพ์หรือเมาส์ (และสไตลัสที่เห็นได้ชัด) +1
Drew Noakes

5
ฉันเห็นคำตอบที่เหมือนกันเกือบทุกอย่างที่นี่social.msdn.microsoft.com/Forums/en-US/wpf/thread/ ......มันใช้ได้ดีไม่เคยใช้ e.OriginalSource หรือคลานผ่านต้นไม้ที่มองเห็น มีข้อได้เปรียบอะไรบ้างในการทำทั้งหมดนี้?
Marco Luglio

1
ใช้งานได้ดี แต่จะสมบูรณ์แบบถ้ามันยังอนุญาตให้ลากข้อความที่เลือกด้วยเมาส์ แถบที่อยู่ของ Google Chrome เป็นตัวอย่างที่สมบูรณ์แบบของระบบในอุดมคติ: หากผู้ใช้คลิกและเผยแพร่โดยไม่ต้องลากข้อความทั้งหมดจะถูกเน้น อย่างไรก็ตามหากผู้ใช้คลิกและลากลากจะเลือกข้อความตามปกติโดยไม่ต้องเลือกทั้งหมด SelectAll เกิดขึ้นเฉพาะบนเมาส์ปล่อย ฉันจะเล่นและดูว่าฉันสามารถปรับปรุงการออกแบบนี้ได้หรือไม่
devios1

2
ข้อเสียอีกข้อหนึ่งของการแก้ปัญหานี้คือเมื่อคุณใช้เมนู "ตัด / คัดลอก / วาง" กล่องข้อความข้อความทั้งหมดจะถูกเลือกเมื่อคุณเลือกรายการเมนูใด ๆ

1
ฉันพบว่าการทดสอบเพิ่มเติมในSelectAllTextวิธีการtextBox.IsFocusedปรับปรุงให้ดีขึ้น คุณไม่ต้องการที่จะเลือกทั้งหมดเมื่อGetKeyboardFocusเป็นเพราะแท็บ alt ในโปรแกรม
Scott Stafford

164

คำตอบของ Donnelle นั้นใช้งานได้ดีที่สุด แต่การได้คลาสใหม่เพื่อใช้มันเป็นความเจ็บปวด

แทนที่จะทำเช่นนั้นฉันจะลงทะเบียนตัวจัดการตัวจัดการใน App.xaml.cs สำหรับ TextBox ทั้งหมดในแอปพลิเคชัน สิ่งนี้ทำให้ฉันสามารถใช้คำตอบของ Donnelle กับตัวควบคุมกล่องข้อความมาตรฐาน

เพิ่มวิธีการต่อไปนี้ลงใน 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();
    }
}

4
นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมมากมันถูกอธิบายโดย Matt Hamilton ทุกเพศทุกวัยที่นี่: madprops.org/blog/wpf-textbox-selectall-on-focus
Ashley Davis

มีการสะกดคำผิดใน 'รับ', 'โฟกัส'
Nate Zaugg

2
ขอบคุณ Nate แก้ไขแม้ว่าในการป้องกันของฉันผมอยากจะชี้ให้เห็นความผิดพลาดของการสะกดคำที่ถูกคัดลอกคำต่อคำจากคำตอบของ Donnelle;)
Grokys

คำถามมีแท็ก Silverlight แต่ Silverlight ไม่มีกิจกรรมส่วนใหญ่ / กิจกรรมตัวอย่างใด ๆ เลย วิธีแก้ปัญหาใดที่ควรใช้กับ Silverlight? ขอบคุณล่วงหน้า
Valentin Kuzub

4
"การสะกดที่เน้นนั้นเป็นเรื่องธรรมดามากในสหรัฐอเมริกาอย่างไรก็ตามบางครั้งการสะกดคำเพ่งความสนใจใช้ในสหราชอาณาจักรและแคนาดาและโดยเฉพาะอย่างยิ่งในออสเตรเลียและนิวซีแลนด์" ดังนั้น nyah;)
Donnelle

85

นี่ค่อนข้างเก่า แต่ฉันจะแสดงคำตอบของฉัน

ฉันเลือกส่วนหนึ่งของคำตอบของ Donnelle (ข้ามการคลิกสองครั้ง) เพราะฉันคิดว่านี่เป็นธรรมชาติมากขึ้น อย่างไรก็ตามเช่นเดียวกับ gcores ฉันไม่ชอบความจำเป็นในการสร้างคลาสที่ได้รับมา แต่ฉันก็ไม่ชอบOnStartupวิธีgcores และฉันต้องการสิ่งนี้ในแบบ "โดยทั่วไป แต่ไม่เสมอไป"

ฉันใช้สิ่งนี้เป็นสิ่งที่แนบมาDependencyPropertyเพื่อให้ฉันสามารถตั้งค่าเป็นlocal:SelectTextOnFocus.Active = "True"xaml ฉันพบว่าวิธีนี้เป็นที่ชื่นชอบมากที่สุด

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

สำหรับฉัน "ทั่วไป แต่ไม่เสมอไป" มีผมตั้งนี้ทูตคุณสมบัติTrueใน TextBox Style(ทั่วโลก) วิธีนี้ "การเลือกข้อความ" จะเป็น "เปิด" เสมอ แต่ฉันสามารถปิดการใช้งานแบบข้อความต่อกล่องข้อความได้


8
+1 สิ่งนี้ดีกว่าการตั้งค่าทั่วโลกและเป็น 'วิธีการ WPF' มากกว่าการได้มาจากกล่องข้อความ
stijn

3
+1 เห็นด้วยกับ stijn "ซ่อน" รหัสของคุณใน app.cs ไม่ดีสำหรับผู้ที่มีฐานะยากจนซึ่งต้องคิดว่าเหตุใด SelectAllOnFocus จึงเกิดขึ้น :-) ฉันเพิ่งปล่อยสิ่งนี้ลงในคลาสของฉันสำหรับ TextBoxBehaviors แล้วอัปเดตสไตล์กล่องข้อความพื้นฐานของฉัน ทำงานรักษา ไชโย
ลีแคมป์เบล

2
@tronda: เพียงเพิ่มสไตล์ให้กับทรัพยากรโดยใช้ TargetType ของ TextBox ฉันขอแนะนำให้คุณดูที่wpftutorial.net/Styles.html
Nils

2
อีก +1 สำหรับคำตอบที่ดีที่สุด ปัญหาเดียวที่ฉันพบคือมีการเลือกข้อความเสมอแม้เมื่อฉันใช้ปุ่มเมาส์ขวา - ซึ่งฉันมักทำเพื่อแก้ไขข้อความผ่านทางเมนูบริบท - โซลูชันไม่ทำงานสำหรับกรณีนี้เพราะจะเลือกข้อความทั้งหมดเสมอแม้ว่าฉันจะ แค่ต้องการตัด 1 คำผ่านเมนูบริบท พวกคุณรู้วิธีแก้ปัญหานี้หรือไม่?
user3313608

2
ฉันชอบคำตอบนี้ แต่ทำไมคุณต้องขยาย DependencyObject ฉันลบออกแล้วและก็ยังใช้งานได้ดี
Fred

47

นี่คือพฤติกรรมการผสมผสานที่ใช้โซลูชันคำตอบเพื่อความสะดวกของคุณ:

หนึ่งสำหรับการแนบไปกับกล่องข้อความเดียว:

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;
        }
    }
}

และอีกอันหนึ่งสำหรับติดกับรูทของคอนเทนเนอร์ที่บรรจุ TextBox'es หลายอัน:

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();
    }
}

นี่คือทางออกที่ดีที่สุดและสะอาดที่สุด ขอบคุณมากสำหรับการแบ่งปัน
Golvellius

มันดูดีจริงๆ แต่ด้วยเหตุผลบางอย่างมันทำให้การควบคุมแท็บหยุดชะงัก ... ความคิดใดที่เป็นเหตุให้?
Marc

ฉันต้องการใช้วิธีแก้ปัญหาเล็กน้อย แต่หลงทางจริงๆ ... คุณอาจมีตัวอย่างไหม?
Juan Pablo Gomez

เมื่อคุณคลิกที่ไหนสักแห่งในกล่องข้อความในขณะที่มีโฟกัส (ลองนึกภาพว่าคุณต้องการย้ายเครื่องหมายรูปหมวกไปยังสถานที่อื่น) มันจะ SelectAll อีกครั้งแทนที่จะย้ายเครื่องหมายรูปหมวก มันไม่คาดคิด แก้ไขโดยแทนที่ GotMouseCapture ด้วย MouseDoubleClick ซึ่งเป็นเรื่องปกติ ขอบคุณการแก้ปัญหาหลังจาก MSDN
norekhov

1
ดูเหมือนว่าจะไม่ทำงานเมื่อกล่องข้อความได้รับโฟกัสเริ่มต้นผ่าน FocusManager.FocusedElement ความคิดใดทำไม
szx

24

แม้ว่านี่จะเป็นคำถามเก่า แต่ฉันเพิ่งมีปัญหานี้ แต่แก้ไขโดยใช้พฤติกรรมที่แนบมาแทนที่จะเป็นพฤติกรรมการแสดงออกในคำตอบของ Sergey นี่หมายความว่าฉันไม่ต้องการการพึ่งพาSystem.Windows.Interactivityใน 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();
    }
}

จากนั้นคุณสามารถใช้มันใน XAML ของคุณเช่นนี้:

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

ฉัน blogged เกี่ยวกับเรื่องนี้ที่นี่


ฉันชอบวิธีนี้ แต่วิธีการตั้งค่า / ไม่ควรลงท้ายด้วย "คุณสมบัติ"; ฉันต้องลบมันออกเพื่อให้ได้การคอมไพล์โค้ดหลังจากเพิ่มส่วน Xaml
Patrick Quirk

ดีมากทำงานได้ตามที่คาดไว้ ฉันชอบสิ่งนี้เพราะมันช่วยให้ฉันแยกความกังวลออกจาก View เมื่อทำ MVVM
Killnine

16

นี่เป็นวิธีที่ง่ายมากในMSDN :

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

นี่คือรหัสที่อยู่เบื้องหลัง:

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();
        }
    }
}

1
โดยพื้นฐานแล้วนี่เป็นโซลูชันเดียวกับที่ได้รับการจัดอันดับมากที่สุดในชุดข้อความนี้ แต่เนื่องจากเมื่อสองปีก่อนตอนนี้ฉันรู้แล้วว่า @Donnelle ยืมมาจากไหน)
Sergey Aldoukhov

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

10

ฉันคิดว่ามันใช้งานได้ดี:

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

หากคุณต้องการที่จะใช้มันเป็นวิธีการขยาย:

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

และในGotFocusกิจกรรมของคุณ:

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

UIElementผมค้นพบวิธีการแก้ปัญหาข้างต้นเพราะหลายเดือนที่ผ่านมาผมกำลังมองหาวิธีการที่จะมุ่งเน้นการตั้งรับ ฉันค้นพบรหัสด้านล่างบางแห่ง (ให้เครดิตไว้) และใช้งานได้ดี ฉันโพสต์ถึงแม้ว่ามันจะไม่ได้เกี่ยวข้องโดยตรงกับคำถามของ OP เพราะมันแสดงให้เห็นถึงรูปแบบเดียวกันในการใช้ในการทำงานด้วยDispatcherUIElement

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

ฉันเดาว่านี่เป็นวิธีที่ง่ายที่สุดในการติดตั้ง หลังจากสร้างวิธีการขยายคุณจะต้องโทร myTextBox.SelectAllText () ทำไมคำตอบนี้ไม่ได้รับคะแนนมากขึ้น? ทำไมโซลูชั่นอื่น ๆ ถึงดีกว่ามาก?
Tono Nam

2
ฉันจะหลีกเลี่ยงวิธีนี้เพราะอาศัยการเรียกใช้ async เพื่อเรียกใช้หลังจากตัวจัดการ MouseUp ของกล่องข้อความ ฉันไม่เชื่อว่าสิ่งนี้จะกำหนดได้ 100% และอาจนำไปสู่พฤติกรรมที่ไม่สอดคล้องกัน แม้ว่ามันอาจจะไม่เกิดขึ้น แต่ฉันก็อยากจะไปกับวิธีการดับเพลิงข้างต้น
Rob H

6

นี่คือความพยายามในการแก้ปัญหาบางอย่างด้วยวิธีแก้ไขปัญหาอื่น ๆ :

  1. ใช้เมนูบริบทคลิกขวาเพื่อตัด / คัดลอก / ที่ผ่านมาเลือกข้อความทั้งหมดแม้ว่าคุณจะไม่ได้เลือกเลยก็ตาม
  2. เมื่อกลับมาจากเมนูบริบทคลิกขวาข้อความทั้งหมดจะถูกเลือกเสมอ
  3. เมื่อกลับสู่แอปพลิเคชันด้วยAlt+ Tabข้อความทั้งหมดจะถูกเลือกเสมอ
  4. เมื่อพยายามเลือกเพียงส่วนหนึ่งของข้อความในการคลิกครั้งแรกจะถูกเลือกทั้งหมดเสมอ (ต่างจากแถบที่อยู่ของ Google Chromes เช่น)

รหัสที่ฉันเขียนนั้นสามารถกำหนดค่าได้ SelectOnKeybourdFocusคุณสามารถเลือกในสิ่งที่กระทำพฤติกรรมเลือกทั้งหมดควรจะเกิดขึ้นโดยการตั้งค่าสามช่องอ่านได้อย่างเดียว: SelectOnMouseLeftClick, SelectOnMouseRightClick,

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

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;
    }
}

ในการเชื่อมต่อ Attached Property ไปยัง a TextBoxสิ่งที่คุณต้องทำคือเพิ่ม xml namespace ( xmlns) ของ Attached Property จากนั้นใช้สิ่งนี้:

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

หมายเหตุบางประการเกี่ยวกับโซลูชันนี้:

  1. ในการแทนที่พฤติกรรมเริ่มต้นของเหตุการณ์การวางเมาส์และเปิดใช้งานการเลือกเพียงส่วนหนึ่งของข้อความในการคลิกครั้งแรกข้อความทั้งหมดจะถูกเลือกในเหตุการณ์เลื่อนเมาส์
  2. ฉันต้องจัดการกับความจริงที่TextBoxว่าจำได้ว่าการเลือกหลังจากที่มันหมดความสำคัญ ฉันได้ลบล้างพฤติกรรมนี้จริง ๆ แล้ว
  3. ผมจะจำไว้ถ้ากดปุ่มเมาส์คือการกระทำครั้งแรกบนTextBox(FirstActionIsMouseDownฟิลด์คงที่) หรือไม่
  4. ฉันต้องจำเมนูบริบทที่เปิดโดยคลิกขวา ( ContextMenuฟิลด์คงที่)

ผลข้างเคียงเดียวที่ฉันพบคือเมื่อSelectOnMouseRightClickเป็นจริง บางครั้งเมนูบริบทคลิกขวาจะกะพริบเมื่อเปิดและคลิกขวาที่ช่องว่างซึ่งอยู่ในส่วนTextBox"ห้ามเลือกทั้งหมด"


5

ฉันพบว่าไม่มีคำตอบใด ๆ ที่นำเสนอที่นี่เลียนแบบกล่องข้อความ Windows มาตรฐาน ตัวอย่างเช่นลองคลิกในช่องว่างระหว่างอักขระตัวสุดท้ายของกล่องข้อความและด้านขวาของกล่องข้อความ โซลูชันส่วนใหญ่ที่นี่มักจะเลือกเนื้อหาทั้งหมดซึ่งทำให้ยากต่อการเพิ่มข้อความในกล่องข้อความ

คำตอบที่ฉันนำเสนอที่นี่จะทำงานได้ดีขึ้นในแง่นี้ มันเป็นพฤติกรรม (ดังนั้นจึงต้องใช้แอสเซมบลีSystem.Windows.InteractivityจากBlend SDK ) มันสามารถเขียนใหม่โดยใช้คุณสมบัติที่แนบมาเช่นกัน

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;
    }
}

นี้เป็นไปตามรหัสที่ฉันได้พบที่นี่


1
ในขณะที่นี่เป็นคำตอบที่ดีฉันคิดว่าเมื่อผู้ใช้คลิกบนพื้นที่สีขาวความตั้งใจของเขา (ในแอปพลิเคชันทางธุรกิจ) ส่วนใหญ่น่าจะแทนที่ค่าทั้งหมดดังนั้นการเลือกทั้งหมดเป็นวิธีที่เหมาะสม
Sergey Aldoukhov

1
Sergey: การคลิกครั้งแรกจะเลือกค่าทั้งหมดการคลิกครั้งที่สองจะวางเคอร์เซอร์ที่ด้านขวาของค่า ในโซลูชันที่นำเสนออื่น ๆ การคลิกครั้งที่สองจะเก็บค่าทั้งหมดไว้ซึ่งทำให้ยากต่อการเพิ่มมูลค่า
Kristof Verbiest

มันใช้งานอย่างไร? ฉันเพิ่มรหัสนี้ใน App.xaml.cs แต่ดูเหมือนว่าจะไม่มีผลกับ TextBox ในแอปของฉัน
PIntag

5

การใช้งานที่เรียบง่ายนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน:

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;
    }
}

เพื่อนำไปใช้กับทุกคนTextBoxใส่รหัสต่อไปนี้หลังจากInitializeComponent();

EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(TextBox_GotFocus));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseDownEvent, new MouseButtonEventHandler(TextBox_PreviewMouseDown));

4

ในไฟล์ App.xaml:

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

ในไฟล์ App.xaml.cs:

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

ด้วยรหัสนี้คุณสามารถเข้าถึงทุกสิ่งTextBoxในใบสมัครของคุณ


3

นำมาจากที่นี่ :

ลงทะเบียนตัวจัดการเหตุการณ์ส่วนกลางในไฟล์ App.xaml.cs:

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

    base.OnStartup(e);
}

จากนั้นตัวจัดการนั้นง่ายเหมือน:

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

3

ฉันรู้ว่านี่เก่ามาก แต่นี่เป็นวิธีแก้ปัญหาของฉันซึ่งขึ้นอยู่กับการแสดงออกของนิพจน์ / ไมโครซอฟท์และการโต้ตอบระหว่างชื่อ

ก่อนอื่นฉันทำตามคำแนะนำที่ลิงค์นี้เพื่อให้เกิดการโต้ตอบในสไตล์

จากนั้นก็ลงมาที่นี่

<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>

และนี่

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;
  }
}

ในกรณีของฉันฉันมีการควบคุมผู้ใช้โดยที่กล่องข้อความนั้นมีโค้ดอยู่เบื้องหลัง code-behind มีฟังก์ชันตัวจัดการ ฉันให้ชื่อผู้ใช้เป็นชื่อควบคุมใน XAML และฉันใช้ชื่อนั้นสำหรับองค์ประกอบ มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน เพียงแค่ใช้รูปแบบใด ๆที่คุณอยากมีข้อความทั้งหมดที่เลือกเมื่อคุณคลิกในTextBoxTextBox

ครั้งแรกที่CallMethodActionเรียกSelectAllวิธีการของกล่องข้อความเมื่อGotKeyboardFocusเหตุการณ์ในTextBoxกองไฟ

ฉันหวังว่านี่จะช่วยได้.


เนื่องจากนี่เป็นคำถามเก่า ๆ มันอาจช่วยให้คำตอบของคุณได้รับความสนใจถ้าคุณพูดถึงว่าทำไมบางคนอาจเลือกวิธีนี้
divibisan

ก่อนอื่นสิ่งนี้ไม่จำเป็นต้องใส่ในสไตล์ แต่ฉันคิดว่ามันชัดเจนว่ามีตัวควบคุมกล่องข้อความจำนวนมากที่ต้องการสิ่งนี้สไตล์คือหนทางที่จะไป
wiyosaya

1
บางทีบางคนอาจจะไม่เห็นด้วยกับวิธีการนี้ แต่เป็นเพราะเหตุใดคุณจึงอาจใช้วิธีนี้มันไม่จำเป็นต้องใช้กล่องข้อความย่อย, การลงทะเบียนเหตุการณ์ตัวจัดการคลาส, วิธีการขยาย, การสร้างคุณสมบัติที่แนบมาเป็นต้น ไปยังพจนานุกรมทรัพยากรของโครงการ xaml ใด ๆ หากไม่มี x: คีย์มันจะถูกนำไปใช้กับอินสแตนซ์กล่องข้อความใด ๆ ภายในขอบเขตของพจนานุกรมทรัพยากรโดยไม่ต้องแก้ไข xaml ของกล่องข้อความแต่ละกล่อง ในบางกรณีอาจเป็นวิธีที่สะอาดกว่า
wiyosaya

2

ฉันใช้คำตอบของนิลส์ แต่ได้รับการดัดแปลงให้ยืดหยุ่นมากขึ้น

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

ใน XAML คุณสามารถใช้อย่างใดอย่างหนึ่งต่อไปนี้:

<!-- 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" />

1
ทางออกที่ดีจริงๆสำหรับการใช้งานในแม่แบบเนื่องจากคุณสามารถผูกกับ xaml ได้โดยไม่ต้องมีโค้ดจริง ๆ เพียงแค่ขยายลักษณะการทำงานของกล่องข้อความ
Eric Johansson

2

นี่คือคำตอบเวอร์ชั่น C # ที่โพสต์โดย @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);
}

ในขณะที่MyTextBox_GotFocusเป็นตัวจัดการเหตุการณ์ที่กำหนดให้กรณีของGotFocusMyTextBox


2

ฉันมีคำตอบที่ง่ายขึ้นเล็กน้อยสำหรับเรื่องนี้ (มีเพียง PreviewMouseLeftButtonDownเหตุการณ์) ซึ่งดูเหมือนว่าจะเลียนแบบการทำงานปกติของเบราว์เซอร์:

ใน XAML คุณได้TextBoxพูดว่า:

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

ใน 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();
    }
}

1
อาจต้องการเพิ่มเหตุการณ์ GotKeyboardFocus ด้วย TextBox.SelectAll () ภายในสำหรับผู้ที่แท็บทางรอบแอปพลิเคชันของคุณ โซลูชันของคุณใช้งานได้กับ PasswordBox เช่นกัน (เนื่องจาก PasswordBoxes เป็นประเภทที่ปิดผนึกจึงไม่สามารถขยายได้)
David Sherret

1

ลองวิธีการขยายนี้เพื่อเพิ่มพฤติกรรมที่ต้องการให้กับกล่องข้อความควบคุม ฉันยังไม่ได้ทดสอบมันอย่างกว้างขวาง แต่ดูเหมือนว่าจะตอบสนองความต้องการของฉัน

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();
            }
        }
    }
}

1

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

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();
}

1

ฉันมีปัญหาเดียวกัน ใน VB.Net มันใช้งานง่าย:

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 # (ขอบคุณ 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);
}

ทางออกที่ดีที่สุดสำหรับฉันฉันโพสต์คำแปล C # ที่นี่: stackoverflow.com/a/48385409/3936440
ViRuSTriNiTy

สำหรับฉันวิธีนี้บางครั้งล้มเหลวในการเลือกข้อความ ฉันคิดว่ามันเป็นสภาพการแข่งขันเนื่องจาก BeginInvoke
Vimes

กรุณาระบุ ลำดับความสำคัญโปรแกรมเลือกจ่ายงานกำลังทำงานกับแอปพลิเคชันเริ่มต้นตามที่คาดไว้ สถานการณ์ของคุณคืออะไร? คุณลองแน่นอนตามที่อธิบายไว้หรือไม่ มีอะไรพิเศษในโซลูชันของคุณ?
Nasenbaer

1

นี่คือทางออกที่ง่ายที่สุด

เพิ่ม global handler เข้ากับแอ็พพลิเคชัน (App.xaml.cs) และเสร็จสิ้น คุณจะต้องการโค้ดเพียงไม่กี่บรรทัด

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

    base.OnStartup(e);
}

ดังนั้นให้ใช้คลาส EventManager เพื่อลงทะเบียนตัวจัดการเหตุการณ์ระดับโลกกับประเภท (กล่องข้อความ) ตัวจัดการจริงตายง่าย ๆ :

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

ตรวจสอบที่นี่: WPF TextBox SelectAll on Focus

หวังว่ามันจะช่วย


1

สำหรับผู้ที่สนใจแนวทางของ Donnelle / Groky แต่ต้องการคลิกทางด้านขวาของตัวละครตัวสุดท้าย (แต่ยังอยู่ในTextBox) เพื่อวางเครื่องหมายรูปหมวกท้ายข้อความที่ป้อนฉันได้มาพร้อมกับวิธีแก้ปัญหานี้:

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();
}

GetRoundedCharacterIndexFromPointวิธีการถูกนำมาจากนี้โพสต์


1
ใช้งานได้ดี แต่เหตุการณ์การคลิกสองครั้งไม่ได้รับการกระตุ้น
Rodrigo Caballero

จริงๆแล้วมันเข้าสู่เหตุการณ์ doubleclick แต่คุณสมบัติ OriginalSource เป็นประเภท TextBoxView ดังนั้นเมธอด SelectAllText ควรเป็นเช่นนี้: โมฆะสแตติกส่วนตัวของ SelectAllText (ผู้ส่งวัตถุ, RoutedEventArgs e) {var textBox = e.OriginalSource เป็น TextBox; if (textBox! = null) {textBox.SelectAll (); System.Diagnostics.Debug.WriteLine ("เลือกทั้งหมด"); } อื่นถ้า (ผู้ส่งเป็นกล่องข้อความ) {(ผู้ส่งเป็นกล่องข้อความ). เลือกทั้งหมด (); }
Rodrigo Caballero

1

หลังจาก googling และทดสอบฉันพบโซลูชันง่าย ๆ ที่เหมาะกับฉัน

คุณต้องเพิ่มตัวจัดการLoadedเหตุการณ์ในเหตุการณ์ของหน้าต่างคอนเทนเนอร์ของคุณ:

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

ถัดไปคุณต้องสร้างตัวจัดการตามที่อ้างถึงRoutedEventHandlerในรหัสก่อนหน้า:

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

ตอนนี้คุณสามารถเพิ่มSelectAll()คำสั่งบนGotFocusตัวจัดการเหตุการณ์ไปยังTextBoxตัวควบคุมใด ๆแยกกัน:

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

ตอนนี้ข้อความของคุณถูกเลือกโดยมุ่งเน้น!

ดัดแปลงจากโซลูชัน Dr. WPF, ฟอรัม MSDN


ฉันเพิ่งใช้: โมฆะ async ส่วนตัวโมฆะ TBTime_GotFocus (ผู้ส่งวัตถุ RoutedEventArgs e) {TextBox tb = (TextBox) e.OriginalSource; รอ 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

หากคุณมีช่องข้อความ 20 ช่องบนหน้าต่างคุณจะสร้าง 3 วิธีสำหรับทุกช่องข้อความหรือไม่? วิธีนี้ไม่ดี ดูที่นี่: rachel53461.wordpress.com/2011/11/05/…
Alexandru Dicu

0

ดูเหมือนว่าจะทำงานได้ดีสำหรับฉัน มันเป็นบทสรุปของโพสต์ก่อนหน้านี้บางส่วน ฉันเพิ่งใส่ลงในไฟล์ MainWindow.xaml.cs ของฉันใน Constructor ฉันสร้างตัวจัดการสองตัวหนึ่งตัวสำหรับแป้นพิมพ์และอีกตัวสำหรับเมาส์และช่องทางทั้งสองเหตุการณ์เป็นฟังก์ชั่นเดียวกันHandleGotFocusEventซึ่งกำหนดไว้หลังจากตัวสร้างในไฟล์เดียวกัน

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();
}

ดีและใช้งานง่าย แต่ดูเหมือนว่าจะมีปัญหาเกี่ยวกับเวลา - ทุก ๆ ลอง (คลิกเมาส์) มันยกเลิกการเลือกอีกครั้งทันที ... ?
T4NK3R

0

วิธีง่ายๆในการแทนที่ mouseDown และเลือกทั้งหมดหลังจาก doubleclick คือ:

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();
    }
}

0

ลองวางสิ่งนี้ลงในคอนสตรัคเตอร์ของสิ่งที่ตัวควบคุมควบคุมเป็นกล่องข้อความของคุณ:

Loaded += (sender, e) =>
{
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    myTextBox.SelectAll();
}

วิธีการนี้จะไม่ทำงานเมื่อคุณวางสิ่งนี้ลงในตัวสร้างหน้าต่าง
ViRuSTriNiTy

0

หากมีเหตุการณ์ที่ยกเลิกการเลือกข้อความระหว่างการOnFocusเลื่อนเมาส์ขึ้นฉันมักจะชะลอการเลือกทั้งหมด

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (TextBox.Text != null)
    {
        _ = Task.Run(() =>
        {
            Dispatcher.Invoke(
                async () => {
                    await Task.Delay(100);
                    TextBox.SelectAll();
                }
            );
        });
    }
}

-1

ฉันได้ทดสอบพวกเขาทั้งหมด แต่ได้ผลดังต่อไปนี้เท่านั้น:

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();
}

4
นอกจากนี้ยังเป็นการใช้รหัสแฮชในทางที่ผิด ฉันอ่านข้อความนี้ลิงก์
RichK

3
และใช้GetType().Nameแทนisหรือas
แฮ็ค

-1

ฉันเห็นว่ามีคำตอบมากมาย แต่ในฐานะที่เป็นผู้อนุมัติวิธีการที่ควรใช้คือ EditTextBoxGotCapture

ด้วยรหัสต่อไปนี้ที่อยู่เบื้องหลัง:

private void EditTextBoxGotCapture(object sender, MouseEventArgs e)
{
    if (sender is TextBox tb)
    {
        tb.Select(0, tb.Text.Length);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.