Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>User input in a <code>TextBox</code> can be identified with</p> <ul> <li>Typing : <em>PreviewTextInput event</em></li> <li>Backspace, Delete, Enter : <em>PreviewKeyDown event</em></li> <li>Pasting : <em>DataObject.PastingEvent</em></li> </ul> <p>Combining these three events with a bool flag to indicate if any of the above occured before the <em>TextChanged</em> event and you'll know the reason for the update.</p> <p>Typing and Pasting are easy, but Backspace doesn't always trigger <code>TextChanged</code> (if no text is selected and the cursor is at position 0 for example). So some logic is needed in <em>PreviewTextInput</em>.</p> <p>Here is an Attached Behavior that implements the logic above and executes a command with a bool flag when <code>TextChanged</code> is raised.</p> <pre><code>&lt;TextBox ex:TextChangedBehavior.TextChangedCommand="{Binding TextChangedCommand}" /&gt; </code></pre> <p>And in code you can find out the source for the update like</p> <pre><code>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.. } } </code></pre> <p>Here is a small sample project demonstrating the effect: <a href="https://www.dropbox.com/s/n56hp8tryok4m2t/SourceOfTextChanged.zip?dl=0" rel="nofollow noreferrer">SourceOfTextChanged.zip</a></p> <p><em>TextChangedBehavior</em></p> <pre><code>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) &amp;&amp; (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) &amp;&amp; (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 &gt; 0 || textBox.SelectionStart &lt; textBox.Text.Length) { SetUserInput(textBox, true); } } else if (e.Key == Key.Back) { if (textBox.SelectionLength &gt; 0 || textBox.SelectionStart &gt; 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 } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload