İşte diğer çözümlerle ilgili bazı sorunları çözme girişimi:
- Kes / kopyala / geçmiş için sağ tıklama bağlam menüsünü kullanmak, tümünü seçmeseniz bile tüm metni seçer.
- Sağ tıklama bağlam menüsünden geri dönerken, tüm metin her zaman seçilir.
- Alt+ İle uygulamaya geri dönerken Tab, tüm metinler her zaman seçilir.
- İlk tıklamada metnin yalnızca bir bölümünü seçmeye çalışırken, tümü her zaman seçilir (örneğin, Google krom adres çubuğunun aksine).
Yazdığım kod yapılandırılabilir. Sen eylemler üç salt okunur alanları belirleyerek gerçekleşmesi gereken tüm davranışlarını seçmek ne seçebilirsiniz: SelectOnKeybourdFocus
, SelectOnMouseLeftClick
, SelectOnMouseRightClick
.
Bu çözümün dezavantajı, daha karmaşık ve statik durumun depolanmasıdır. TextBox
Kontrolün varsayılan davranışı ile çirkin bir mücadele gibi görünüyor . Yine de çalışır ve tüm kod Attached Property kapsayıcı sınıfında gizlidir.
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;
}
}
Ekli Özelliğe a TextBox
eklemek için tek yapmanız gereken Ekli Özelliğin xml ad alanını ( xmlns
) eklemektir ve ardından şu şekilde kullanmaktır:
<TextBox attachedprop:TextBoxExtensions.SelectOnFocus="True"/>
Bu çözüm hakkında bazı notlar:
- Bir fare aşağı olayının varsayılan davranışını geçersiz kılmak ve ilk tıklatmada metnin yalnızca bir kısmını seçmeyi etkinleştirmek için, fare yukarı olayında tüm metinler seçilir.
TextBox
Odağı kaybettikten sonra seçimini hatırladığı gerçeğiyle uğraşmak zorunda kaldım . Aslında bu davranışı geçersiz kıldım.
- Fare düğmesinin aşağı
TextBox
( FirstActionIsMouseDown
statik alan) üzerindeki ilk eylem olup olmadığını hatırlamak zorundaydım .
- Sağ tıklamayla açılan
ContextMenu
statik menüyü hatırlamam gerekiyordu ( statik alan).
Bulduğum tek yan etki ne zaman SelectOnMouseRightClick
doğru. Bazen sağ tıklatma bağlam menüsü açıldığında ve bir boşluk üzerine sağ tıklandığında TextBox
"tümünü seç" yapmaz.