Hier ist ein Versuch, einige der Probleme mit anderen Lösungen zu lösen:
- Wenn Sie das Kontextmenü mit der rechten Maustaste für Ausschneiden / Kopieren / Einfügen verwenden, wird der gesamte Text ausgewählt, auch wenn Sie nicht alles ausgewählt haben.
- Bei der Rückkehr aus dem Kontextmenü mit der rechten Maustaste wird immer der gesamte Text ausgewählt.
- Wenn Sie mit Alt+ zur Anwendung zurückkehren, Tabwird immer der gesamte Text ausgewählt.
- Wenn Sie versuchen, beim ersten Klick nur einen Teil des Texts auszuwählen, wird immer alles ausgewählt (im Gegensatz zur Adressleiste von Google Chromes zum Beispiel).
Der Code, den ich geschrieben habe, ist konfigurierbar. Sie können wählen , welche Aktionen das ganze Verhalten auswählen , indem Sie drei Nur - Lese - Felder auftreten sollte: SelectOnKeybourdFocus
, SelectOnMouseLeftClick
, SelectOnMouseRightClick
.
Der Nachteil dieser Lösung ist, dass sie komplexer ist und der statische Zustand gespeichert wird. Es scheint ein hässlicher Kampf mit dem Standardverhalten der TextBox
Kontrolle zu sein. Trotzdem funktioniert es und der gesamte Code ist in der Containerklasse Attached Property versteckt.
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;
}
}
Um die angehängte Eigenschaft an a TextBox
anzuhängen, müssen Sie lediglich den XML-Namespace ( xmlns
) der angehängten Eigenschaft hinzufügen und dann wie folgt verwenden:
<TextBox attachedprop:TextBoxExtensions.SelectOnFocus="True"/>
Einige Hinweise zu dieser Lösung:
- Um das Standardverhalten eines Mouse-Down-Ereignisses zu überschreiben und die Auswahl nur eines Teils des Texts beim ersten Klick zu aktivieren, wird der gesamte Text beim Mouse-Up-Ereignis ausgewählt.
- Ich musste mich damit auseinandersetzen, dass sich das das
TextBox
an seine Auswahl erinnert, nachdem es den Fokus verloren hat. Ich habe dieses Verhalten tatsächlich überschrieben.
- Ich musste mich daran erinnern, ob eine Maustaste die erste Aktion auf dem
TextBox
( FirstActionIsMouseDown
statischen Feld) ist.
- Ich musste mich an das Kontextmenü erinnern, das mit einem Rechtsklick geöffnet wurde (
ContextMenu
statisches Feld).
Der einzige Nebeneffekt, den ich gefunden habe, ist, wann er SelectOnMouseRightClick
wahr ist. Manchmal flackert das Kontextmenü mit der rechten Maustaste, wenn es geöffnet wird, und wenn Sie mit der rechten Maustaste auf ein Leerzeichen klicken, TextBox
wird nicht "Alle auswählen" angezeigt.