นี่คือความพยายามในการแก้ปัญหาบางอย่างด้วยวิธีแก้ไขปัญหาอื่น ๆ :
- ใช้เมนูบริบทคลิกขวาเพื่อตัด / คัดลอก / ที่ผ่านมาเลือกข้อความทั้งหมดแม้ว่าคุณจะไม่ได้เลือกเลยก็ตาม
- เมื่อกลับมาจากเมนูบริบทคลิกขวาข้อความทั้งหมดจะถูกเลือกเสมอ
- เมื่อกลับสู่แอปพลิเคชันด้วยAlt+ Tabข้อความทั้งหมดจะถูกเลือกเสมอ
- เมื่อพยายามเลือกเพียงส่วนหนึ่งของข้อความในการคลิกครั้งแรกจะถูกเลือกทั้งหมดเสมอ (ต่างจากแถบที่อยู่ของ 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"/>
หมายเหตุบางประการเกี่ยวกับโซลูชันนี้:
- ในการแทนที่พฤติกรรมเริ่มต้นของเหตุการณ์การวางเมาส์และเปิดใช้งานการเลือกเพียงส่วนหนึ่งของข้อความในการคลิกครั้งแรกข้อความทั้งหมดจะถูกเลือกในเหตุการณ์เลื่อนเมาส์
- ฉันต้องจัดการกับความจริงที่
TextBox
ว่าจำได้ว่าการเลือกหลังจากที่มันหมดความสำคัญ ฉันได้ลบล้างพฤติกรรมนี้จริง ๆ แล้ว
- ผมจะจำไว้ถ้ากดปุ่มเมาส์คือการกระทำครั้งแรกบน
TextBox
(FirstActionIsMouseDown
ฟิลด์คงที่) หรือไม่
- ฉันต้องจำเมนูบริบทที่เปิดโดยคลิกขวา (
ContextMenu
ฟิลด์คงที่)
ผลข้างเคียงเดียวที่ฉันพบคือเมื่อSelectOnMouseRightClick
เป็นจริง บางครั้งเมนูบริบทคลิกขวาจะกะพริบเมื่อเปิดและคลิกขวาที่ช่องว่างซึ่งอยู่ในส่วนTextBox
"ห้ามเลือกทั้งหมด"