Gre*_*reg 17 wpf events wpf-controls
我想区分以编程方式更改文本(例如在按钮单击处理程序事件中)和用户输入(键入,剪切和粘贴文本).
可能吗?
Fre*_*lad 25
a中的用户输入TextBox可以用
将这三个事件与bool标志组合以指示在TextChanged事件之前是否发生了上述任何事件,并且您将知道更新的原因.
键入和粘贴很容易,但Backspace并不总是触发TextChanged(如果没有选择文本,光标位于0位置).因此,PreviewTextInput需要一些逻辑.
这是一个附加行为,它实现上面的逻辑并在TextChanged引发时执行带有bool标志的命令.
<TextBox ex:TextChangedBehavior.TextChangedCommand="{Binding TextChangedCommand}" />
Run Code Online (Sandbox Code Playgroud)
在代码中,您可以找到更新的来源,如
private void TextChanged_Executed(object parameter)
{
object[] parameters = parameter as object[];
object sender = parameters[0];
TextChangedEventArgs e = (TextChangedEventArgs)parameters[1];
bool userInput = (bool)parameters[2];
if (userInput == true)
{
// User input update..
}
else
{
// Binding, Programatic update..
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个展示效果的小样本项目:SourceOfTextChanged.zip
TextChangedBehavior
public class TextChangedBehavior
{
public static DependencyProperty TextChangedCommandProperty =
DependencyProperty.RegisterAttached("TextChangedCommand",
typeof(ICommand),
typeof(TextChangedBehavior),
new UIPropertyMetadata(TextChangedCommandChanged));
public static void SetTextChangedCommand(DependencyObject target, ICommand value)
{
target.SetValue(TextChangedCommandProperty, value);
}
// Subscribe to the events if we have a valid command
private static void TextChangedCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
TextBox textBox = target as TextBox;
if (textBox != null)
{
if ((e.NewValue != null) && (e.OldValue == null))
{
textBox.PreviewKeyDown += textBox_PreviewKeyDown;
textBox.PreviewTextInput += textBox_PreviewTextInput;
DataObject.AddPastingHandler(textBox, textBox_TextPasted);
textBox.TextChanged += textBox_TextChanged;
}
else if ((e.NewValue == null) && (e.OldValue != null))
{
textBox.PreviewKeyDown -= textBox_PreviewKeyDown;
textBox.PreviewTextInput -= textBox_PreviewTextInput;
DataObject.RemovePastingHandler(textBox, textBox_TextPasted);
textBox.TextChanged -= textBox_TextChanged;
}
}
}
// Catches User input
private static void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
TextBox textBox = sender as TextBox;
SetUserInput(textBox, true);
}
// Catches Backspace, Delete, Enter
private static void textBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
TextBox textBox = sender as TextBox;
if (e.Key == Key.Return)
{
if (textBox.AcceptsReturn == true)
{
SetUserInput(textBox, true);
}
}
else if (e.Key == Key.Delete)
{
if (textBox.SelectionLength > 0 || textBox.SelectionStart < textBox.Text.Length)
{
SetUserInput(textBox, true);
}
}
else if (e.Key == Key.Back)
{
if (textBox.SelectionLength > 0 || textBox.SelectionStart > 0)
{
SetUserInput(textBox, true);
}
}
}
// Catches pasting
private static void textBox_TextPasted(object sender, DataObjectPastingEventArgs e)
{
TextBox textBox = sender as TextBox;
if (e.SourceDataObject.GetDataPresent(DataFormats.Text, true) == false)
{
return;
}
SetUserInput(textBox, true);
}
private static void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
TextChangedFired(textBox, e);
SetUserInput(textBox, false);
}
private static void TextChangedFired(TextBox sender, TextChangedEventArgs e)
{
ICommand command = (ICommand)sender.GetValue(TextChangedCommandProperty);
object[] arguments = new object[] { sender, e, GetUserInput(sender) };
command.Execute(arguments);
}
#region UserInput
private static DependencyProperty UserInputProperty =
DependencyProperty.RegisterAttached("UserInput",
typeof(bool),
typeof(TextChangedBehavior));
private static void SetUserInput(DependencyObject target, bool value)
{
target.SetValue(UserInputProperty, value);
}
private static bool GetUserInput(DependencyObject target)
{
return (bool)target.GetValue(UserInputProperty);
}
#endregion // UserInput
}
Run Code Online (Sandbox Code Playgroud)
与 JHunz 的答案类似,只需将布尔成员变量添加到您的控件中即可:
bool programmaticChange = false;
Run Code Online (Sandbox Code Playgroud)
当您进行程序更改时,请执行以下操作:
programmaticChange = true;
// insert changes to the control text here
programmaticChange = false;
Run Code Online (Sandbox Code Playgroud)
在事件处理程序中,您只需检查 的值programmaticChange即可确定是否是编程更改。
相当明显,不是很优雅,但它也可行且简单。
根据您的确切需求,您可以TextBox.IsFocused在TextChanged事件中使用来确定手动输入。这显然不会涵盖所有的编程更改方式,但适用于很多示例就好了,并且是一种非常干净且保存的方式。
基本上这在以下情况下有效:
...程序更改全部基于手动更改(例如按下按钮)。
如果出现以下情况,它将不起作用:
...编程更改完全基于代码(例如计时器)。
代码示例:
textBox.TextChanged += (sender, args) =>
if (textBox.IsFocused)
{
//do something for manual input
}
else
{
//do something for programmatical input
}
}
Run Code Online (Sandbox Code Playgroud)
如果您只想使用内置的WPF文本框,那么我认为这是不可能的。
在Silverlight论坛上也有类似的讨论:http : //forums.silverlight.net/p/119128/268453.aspx 这不是完全相同的问题,但我认为与原始帖子中类似的想法可能会解决这个问题。给你的把戏。在子类TextBox上有一个SetText方法,该方法在更改文本之前先设置一个标志,然后再将其重新设置。然后,您可以检查TextChanged事件中的标志。当然,这将需要对所有程序化文本进行更改才能使用该方法,但是如果您对项目有足够的控制权以强制执行,我认为它将起作用。
| 归档时间: |
|
| 查看次数: |
23780 次 |
| 最近记录: |