Ось спроба вирішити деякі проблеми з іншими рішеннями:
- Використовуючи контекстне меню правою кнопкою миші для вирізання / копіювання / минулого, вибирає весь текст, навіть якщо ви не вибрали його весь.
- При поверненні з контекстного меню правою кнопкою миші завжди вибирається весь текст.
- При поверненні до програми з Alt+Tab , весь текст вибирається завжди.
- Під час спроби виділити лише частину тексту під час першого клацання, все завжди вибирається (наприклад, на відміну від адресного рядка хромів Google).
Я написав код можна налаштувати. Ви можете вибрати на які дії вибрати все поведінка повинна відбуватися шляхом установки трьох полів тільки для читання: SelectOnKeybourdFocus
, SelectOnMouseLeftClick
,SelectOnMouseRightClick
.
Мінус цього рішення полягає в тому, що він складніший і статичний стан зберігається. Це здається некрасивою боротьбою з поведінкою TextBox
контролю за замовчуванням . Проте він працює, і весь код прихований у класі контейнера Attached Properties.
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;
}
}
Щоб приєднати вкладений ресурс до а TextBox
, все, що вам потрібно зробити, - це додати простір імен xml ( xmlns
) вкладеного ресурсу та використовувати його так:
<TextBox attachedprop:TextBoxExtensions.SelectOnFocus="True"/>
Деякі зауваження щодо цього рішення:
- Щоб змінити поведінку за замовчуванням події вниз миші та включити вибір лише частини тексту під час першого клацання, у події миші вибирається весь текст.
- Мені довелося мати справу з тим, що
TextBox
пам'ятає його вибір після того, як він втрачає увагу. Я насправді відмінив таку поведінку.
- Мені довелося пам'ятати, чи перша кнопка миші вниз - це перша дія на
TextBox
(FirstActionIsMouseDown
статичне поле).
- Мені довелося запам’ятати контекстне меню, відкрите правою кнопкою миші (
ContextMenu
статичне поле).
Єдиний побічний ефект, який я виявив, коли SelectOnMouseRightClick
це правда. Іноді контекстне меню правою кнопкою миші мерехтить, коли його відкрите та клацання правою кнопкою миші на порожньому TextBox
значенні не робить "вибору всіх".