TextBox TextChanged event on programmatic versus user change of text contents

后端 未结 8 1711
日久生厌
日久生厌 2020-12-15 18:16

I would like to differentiate between changing the text programmatically (for example in a button click handler event) and user input (typing, cutting and pasting text). <

相关标签:
8条回答
  • 2020-12-15 18:36

    I had this problem too, but for my case it was enough to listen to the (Preview)TextInput event instead of using Meleak's rather complex solution. I realize that's not a complete solution if you have to listen for programmatic changes aswell, but in my case it worked fine.

    0 讨论(0)
  • 2020-12-15 18:37

    If you just want to use the built-in WPF TextBox, then I don't believe it's possible.

    There is a similar discussion on the Silverlight forums here: http://forums.silverlight.net/p/119128/268453.aspx It's not exactly the same question, but I think the idea similar to that in the original post might do the trick for you. Have a SetText method on a subclassed TextBox, that set a flag before changing the text and then set it back after. You could then check for the flag inside the TextChanged event. This would of course require all of your programmatic text changes to use that method, but if you have enough control over the project to mandate that I think it would work.

    0 讨论(0)
  • 2020-12-15 18:41

    Similar to JHunz's answer, just add a boolean member variable to your control:

    bool programmaticChange = false;
    

    When you are making programmatic changes do this:

    programmaticChange = true;
    // insert changes to the control text here
    programmaticChange = false;
    

    In your event handlers, you just need to inspect the value of programmaticChange to determine if its a programmatic change or not.

    Fairly obvious and not very elegant but its also workable and simple.

    0 讨论(0)
  • 2020-12-15 18:43

    Thanks to Tim for pointing in the right direction, but for my needs, the check for the IsFocus worked like a charm. It's so simple....

     if (_queryField.IsKeyboardFocused && _queryField.IsKeyboardFocusWithin)
     {
         //do your things
     }
     else 
     { 
         //whatever 
     }
    
    0 讨论(0)
  • 2020-12-15 18:51

    Depending on your exact demands you can use TextBox.IsFocused in the TextChanged event to determine manual input. This will obviously not cover all ways of programmatical changes, but works for a lot of examples just fine and is a pretty clean and save way of doing so.

    Basically this works if:
    ...the programmatical changes are all based on a manual change (e.g. a Button press).
    It will not work if:
    ...the programmatical changes are completely based on code (e.g. a Timer).

    Code example:

    textBox.TextChanged += (sender, args) =>
        if (textBox.IsFocused)
        {
            //do something for manual input
        }
        else
        {
            //do something for programmatical input
        }
    }
    
    0 讨论(0)
  • 2020-12-15 18:51

    I have cleaned up and modified the TextChangedBehavior class from Fredrik answer so that it also correctly handles the cut command (ctr+X).

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    public class TextChangedBehavior
    {
        public static readonly DependencyProperty TextChangedCommandProperty =
            DependencyProperty.RegisterAttached("TextChangedCommand",
                                                typeof (ICommand),
                                                typeof (TextChangedBehavior),
                                                new UIPropertyMetadata(TextChangedCommandChanged));
    
        private static readonly DependencyProperty UserInputProperty =
            DependencyProperty.RegisterAttached("UserInput",
                                                typeof (bool),
                                                typeof (TextChangedBehavior));
    
        public static void SetTextChangedCommand(DependencyObject target, ICommand value)
        {
            target.SetValue(TextChangedCommandProperty, value);
        }
    
        private static void ExecuteTextChangedCommand(TextBox sender, TextChangedEventArgs e)
        {
            var command = (ICommand)sender.GetValue(TextChangedCommandProperty);
            var arguments = new object[] { sender, e, GetUserInput(sender) };
            command.Execute(arguments);
        }
    
        private static bool GetUserInput(DependencyObject target)
        {
            return (bool)target.GetValue(UserInputProperty);
        }
    
        private static void SetUserInput(DependencyObject target, bool value)
        {
            target.SetValue(UserInputProperty, value);
        }
    
        private static void TextBoxOnPreviewExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Command != ApplicationCommands.Cut)
            {
                return;
            }
    
            var textBox = sender as TextBox;
            if (textBox == null)
            {
                return;
            }
    
            SetUserInput(textBox, true);
        }
    
        private static void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            var textBox = (TextBox)sender;
            switch (e.Key)
            {
                case Key.Return:
                    if (textBox.AcceptsReturn)
                    {
                        SetUserInput(textBox, true);
                    }
                    break;
    
                case Key.Delete:
                    if (textBox.SelectionLength > 0 || textBox.SelectionStart < textBox.Text.Length)
                    {
                        SetUserInput(textBox, true);
                    }
                    break;
    
                case Key.Back:
                    if (textBox.SelectionLength > 0 || textBox.SelectionStart > 0)
                    {
                        SetUserInput(textBox, true);
                    }
                    break;
            }
        }
    
        private static void TextBoxOnPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            SetUserInput((TextBox)sender, true);
        }
    
        private static void TextBoxOnTextChanged(object sender, TextChangedEventArgs e)
        {
            var textBox = (TextBox)sender;
            ExecuteTextChangedCommand(textBox, e);
            SetUserInput(textBox, false);
        }
    
        private static void TextBoxOnTextPasted(object sender, DataObjectPastingEventArgs e)
        {
            var textBox = (TextBox)sender;
            if (e.SourceDataObject.GetDataPresent(DataFormats.Text, true) == false)
            {
                return;
            }
    
            SetUserInput(textBox, true);
        }
    
        private static void TextChangedCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {
            var textBox = target as TextBox;
            if (textBox == null)
            {
                return;
            }
    
            if (e.OldValue != null)
            {
                textBox.PreviewKeyDown -= TextBoxOnPreviewKeyDown;
                textBox.PreviewTextInput -= TextBoxOnPreviewTextInput;
                CommandManager.RemovePreviewExecutedHandler(textBox, TextBoxOnPreviewExecuted);
                DataObject.RemovePastingHandler(textBox, TextBoxOnTextPasted);
                textBox.TextChanged -= TextBoxOnTextChanged;
            }
    
            if (e.NewValue != null)
            {
                textBox.PreviewKeyDown += TextBoxOnPreviewKeyDown;
                textBox.PreviewTextInput += TextBoxOnPreviewTextInput;
                CommandManager.AddPreviewExecutedHandler(textBox, TextBoxOnPreviewExecuted);
                DataObject.AddPastingHandler(textBox, TextBoxOnTextPasted);
                textBox.TextChanged += TextBoxOnTextChanged;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题