다른 솔루션의 일부 문제를 해결하려는 시도는 다음과 같습니다.
- 잘라 내기 / 복사 / 붙여 넣기에 마우스 오른쪽 버튼을 클릭하여 상황에 맞는 메뉴를 사용하면 모든 텍스트를 선택하지 않아도 모든 텍스트가 선택됩니다.
- 마우스 오른쪽 버튼 클릭 상황에 맞는 메뉴에서 돌아올 때 항상 모든 텍스트가 선택됩니다.
- Alt+ 를 사용하여 응용 프로그램으로 돌아 가면 Tab모든 텍스트가 항상 선택됩니다.
- 처음 클릭 할 때 텍스트의 일부만 선택하려고하면 모든 항목이 항상 선택됩니다 (예 : Google 크롬 주소 표시 줄과 달리).
내가 작성한 코드는 구성 가능합니다. 당신은 행동이 세 가지 읽기 전용 필드를 설정하여 발생해야하는 모든 행동을 선택 무엇을 선택할 수 있습니다 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;
}
}
첨부 된 속성을에 첨부하려면 첨부 된 속성 TextBox
의 xml 네임 스페이스 ( xmlns
)를 추가 한 후 다음과 같이 사용하면됩니다.
<TextBox attachedprop:TextBoxExtensions.SelectOnFocus="True"/>
이 솔루션에 대한 참고 사항 :
- 마우스 다운 이벤트의 기본 동작을 무시하고 처음 클릭 할 때 텍스트의 일부만 선택할 수 있도록하기 위해 마우스 업 이벤트에서 모든 텍스트가 선택됩니다.
- 나는
TextBox
기억이 초점을 잃은 후에 선택을 기억 한다는 사실을 다루어야 했습니다. 실제로이 동작을 재정의했습니다.
- 마우스 버튼 다운이
TextBox
( FirstActionIsMouseDown
정적 필드) 의 첫 번째 작업인지 기억해야했습니다 .
- 마우스 오른쪽 버튼을 클릭하여 열린 컨텍스트 메뉴 (
ContextMenu
정적 필드) 를 기억해야했습니다 .
내가 찾은 유일한 부작용 SelectOnMouseRightClick
은 사실입니다. 빈칸을 열고 마우스 오른쪽 버튼을 클릭 TextBox
해도 "모두 선택"하지 않는 경우 오른쪽 클릭 상황에 맞는 메뉴가 깜박 입니다.