WPF 텍스트 상자에 이벤트 붙여넣기
다음을 상속하는 사용자 지정 컨트롤을 만들었습니다.TextBox
이 사용자 지정 컨트롤은 숫자입니다.TextBox
지원되는 숫자만.
사용 중OnPreviewTextInput
입력 중인 각 새 문자를 검사하여 문자가 유효한 입력인지 확인합니다.이것은 아주 잘 작동합니다.하지만, 만약 내가 텍스트를 붙여넣는다면,TextBox
,OnPreviewTextInput
실행되지 않았습니다.
붙여넣은 텍스트를 캡처하는 가장 좋은 방법은 무엇입니까?TextBox
?
또한 뒷공간을 눌렀을 때 문제가 있는데, 어떤 이벤트가 발생할지 알 수 없습니다. OnPreviewTextInput
발사되지 않았습니다!
WPF에서 붙여넣은 텍스트 및 백스페이스 이벤트를 캡처하는 방법에 대한 모든 아이디어TextBox
?
필요할 때를 대비해 숨겨둔 코드가 있습니다.도움이 될 겁니다
public Window1()
{
InitializeComponent();
// "tb" is a TextBox
DataObject.AddPastingHandler(tb, OnPaste);
}
private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
if (!isText) return;
var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
...
}
TextBox를 발생시킬 수 있는 모든 개별 이벤트를 가로채고 트랩하려고 할 때 발생하는 문제입니다.변경할 텍스트 속성은 다음과 같은 이벤트가 많다는 것입니다.
- 텍스트 입력: 사용자 유형
- 키다운: 삭제, 백스페이스, 입력, IME
- 명령 제스처:Ctrl-X, Ctrl-Y, Ctrl-V, Ctrl-X
- 마우스 아래로: 붙여넣기 단추, 잘라내기 단추, 실행 취소 단추, ...
- 클릭: 붙여넣기, 잘라내기, 실행 취소 단추에 로컬 포커스가 있을 때 스페이스 바를 누릅니다.
- 이벤트 발생: 코드가 붙여넣기, 잘라내기, 실행 취소, 다시 실행 명령을 발생시킵니다.
- 접근성:음성 명령, 점자 키보드 등
이 모든 것을 안정적으로 가로채려는 것은 헛된 일입니다.훨씬 더 나은 해결책은 TextBox를 모니터링하는 것입니다.텍스트 변경 및 사용자가 원하지 않는 변경사항을 거부합니다.
이 답변에서는 질문을 받는 특정 시나리오에 대해 TextBoxRestriction 클래스를 구현하는 방법을 보여 줍니다.이와 동일한 기법을 일반화하여 텍스트 상자 컨트롤에 적용하려는 모든 제한사항에 사용할 수 있습니다.
예를 들어, 당신의 경우, 당신은 다음을 구현할 수 있습니다.RestrictValidChars
유사한 첨부 재산.RestrictDeleteTo
해당 코드의 속성입니다.내부 루프가 삭제가 아닌 삽입을 확인한다는 점을 제외하고는 동일합니다.다음과 같이 사용할 수 있습니다.
<TextBox my:TextBoxRestriction.RestrictValidChars="0123456789" />
이것은 단지 그것이 어떻게 처리될 수 있는지에 대한 아이디어입니다.원하는 것에 따라 코드를 구성하는 방법은 여러 가지가 있습니다.예를 들어, TextBoxRestriction을 변경하여 대리자 또는 이벤트가 포함된 개체를 사용하는 연결된 속성을 사용하여 사용자 고유의 코드를 호출하여 유효성을 검사할 수 있습니다.
TextBoxRestriction 클래스를 사용할 때 Text 속성을 바인딩하는 방법에 대한 자세한 내용은 다른 답변을 참조하여 원하지 않을 때 제한을 트리거하지 않도록 합니다.
백스페이스의 경우 PreviewKeyDown 이벤트를 확인하십시오.
붙여넣기 명령의 경우 Application Commands에 명령 바인딩을 추가합니다.아무 작업도 수행하지 않으려면 인수를 붙여넣고 처리할 인수를 설정합니다.
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Paste"
Executed="PasteExecuted" />
</Window.CommandBindings>
그리고 코드 뒤에:
private void PasteExecuted(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
이것은 당신이 찾는 정확한 답이 아닐 수도 있지만, 붙여넣은 텍스트를 처리하는 방법은 다음과 같습니다(사용자가 상황에 맞는 메뉴를 사용하여 붙여넣은 경우에도 작동합니다).
InitializeComponent();
// "DescriptionTextBox" is a TextBox
DataObject.AddPastingHandler(DescriptionTextBox, OnDescriptionPaste);
private void OnDescriptionPaste(object sender, DataObjectPastingEventArgs e)
{
if (!e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true))
return;
var pastedText = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
if (string.IsNullOrEmpty(pastedText))
return;
var txtBox = (TextBox) sender;
var before = ""; //Text before pasted text
var after = txtBox.Text; //Text after pasted text
//Get before and after text
if (txtBox.CaretIndex > 0)
{
before = txtBox.Text.Substring(0, txtBox.CaretIndex);
after = txtBox.Text.Substring(txtBox.CaretIndex);
}
//Do custom logic for handling the pasted text.
//Split sentences ending with . into new line.
var parts = pastedText.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 1)
{
pastedText = parts.Select(x => x.Trim()).ToArray().ToStringX(".\r\n");
pastedText += ".";
}
var newCaretIndex = before.Length + pastedText.Length;
e.CancelCommand(); //Cancels the paste, we do it manually
txtBox.Text = $"{before}{pastedText}{after}"; //Set new text
txtBox.CaretIndex = newCaretIndex; //Set new caret index
}
백스페이스를 처리하려면 PreviewKeyDown 이벤트를 사용합니다.
다음을 통해 이를 달성할 수 있습니다.PreviewKeyDown
및 벤트및이TextChanged
이벤트
PreviewKeyDown
if(Key.V == e.Key && Keyboard.Modifiers == ModifierKeys.Control)
{
strPreviousString = this.txtNumber.Text;
bIsPasteOperation = true;
}
TextChanged
if (true == bIsPasteOperation)
{
if (false == this.IsNumber(this.txtNumber.Text))
{
this.txtNumber.Text = strPreviousString;
e.Handled = true;
}
bIsPasteOperation = false;
}
에▁where디IsNumber
아닌지합니다.
private bool IsNumber(string text)
{
int number;
//Allowing only numbers
if (!(int.TryParse(text, out number)))
{
return false;
}
return true
}
이것은 저에게 꽤 효과가 있습니다.사용자가 내용을 변경할 때 텍스트 상자의 색상을 변경하고 싶었습니다.
- 마침표와 음수를 포함한 숫자 사용
- 입력한 키: 삭제, 백스페이스, ctrl-V(붙여넣기), ctrl-X(잘라내기)
- 마우스 오른쪽 버튼을 클릭하여 붙여넣기 및 잘라내기
아래의 3가지 이벤트를 통해 달성할 수 있었습니다.
public bool IsDirty {
set {
if(value) {
txtValue.Background = Brushes.LightBlue;
} else {
txtValue.Background = IsReadOnly ? Brushes.White : Brushes.LightYellow;
}
}
get {
return txtValue.Background == Brushes.LightBlue;
}
}
private void PreviewTextInput(object sender, TextCompositionEventArgs e) {
TextBox tb = ((TextBox)sender);
string originalText = tb.Text;
string newVal = "";
//handle negative
if (e.Text=="-") {
if(originalText.IndexOf("-") > -1 || tb.CaretIndex != 0 || originalText == "" || originalText == "0") {
//already has a negative or the caret is not at the front where the - should go
//then ignore the entry
e.Handled = true;
return;
}
//put it at the front
newVal = e.Text + originalText;
} else {
//normal typed number
newVal = originalText + e.Text;
}
//check if it's a valid double if so then dirty
double dVal;
e.Handled = !double.TryParse(newVal, out dVal);
if(!e.Handled) {
IsDirty = true;
}
}
private void PreviewKeyUp(object sender, KeyEventArgs e) {
//handle paste
if ((Key.V == e.Key || Key.X == e.Key) && Keyboard.Modifiers == ModifierKeys.Control) {
IsDirty = true;
}
//handle delete and backspace
if (e.Key == Key.Delete || e.Key == Key.Back) {
IsDirty = true;
}
}
private void PreviewExecuted(object sender, ExecutedRoutedEventArgs e) {
//handle context menu cut/paste
if (e.Command == ApplicationCommands.Cut || e.Command == ApplicationCommands.Paste) {
IsDirty = true;
}
}
아래 코드가 저에게 효과가 있었습니다.누군가에게 도움이 되길 바랍니다.
Xceed RichTextBox 컨트롤을 사용하는 경우 다음 코드를 사용합니다.
<xctk:RichTextBox Name="Description" CommandManager.PreviewExecuted="CommandExecuted_PreviewExecuted">
private void CommandExecuted_PreviewExecuted(object sender, RoutedEventArgs e)
{
Xceed.Wpf.Toolkit.RichTextBox richTextBox = (Xceed.Wpf.Toolkit.RichTextBox)sender;
string rtbtext = StringFromRichTextBox(richTextBox);
if ((e as ExecutedRoutedEventArgs).Command == ApplicationCommands.Paste)
{
// verify that the textbox handled the paste command
if (Clipboard.GetText() > 2500)//Get copied text from clipboard
{
e.Handled = true;// prevent paste if length is more than 2500.
return;
}
}
}
TextBlock을 사용하는 경우 아래 코드를 사용합니다.
TextBlock textBlock = (TextBlock)sender;
이것 대신에
Xceed.Wpf.Toolkit.RichTextBox richTextBox = (Xceed.Wpf.Toolkit.RichTextBox)sender;
나머지 모든 코드는 TextBlock에 대해서도 위와 동일하게 유지될 수 있습니다.
언급URL : https://stackoverflow.com/questions/3061475/paste-event-in-a-wpf-textbox
'itsource' 카테고리의 다른 글
배열을 해시 루비로 (0) | 2023.05.12 |
---|---|
Excel 공식에서 상대 위치 사용 (0) | 2023.05.12 |
및/또는 VBA의 기타 기능 (0) | 2023.05.12 |
PowerShell에서 CMD 명령 실행 (0) | 2023.05.07 |
사용자가 WPF로 작성된 응용 프로그램의 최상위 창 크기를 조정하지 못하게 하는 가장 좋은 방법은 무엇입니까? (0) | 2023.05.07 |