TextBox - 确定用户是否输入数据

时间:2014-01-06 11:55:45

标签: wpf wpf-controls

我们使用TextBox显示从IO系统接收的数据。如果用户在文本框中输入了一些数据,则该值将写入IO系统。

我们正在使用OnTextChanged事件将用户输入的数据写入IO系统。

问题是当我们将从IO系统收到的值更新到文本框(来自代码)时,我们会收到此事件。

是否可以知道用户是否更改了TextBox的值或使用了代码?

2 个答案:

答案 0 :(得分:0)

我不知道这是否适合您的情况,但您可以尝试使用KeyUpKeyDown事件。只有当用户向TextBox键入内容时才会引发该事件,如果文本由代码更改则不会引发该事件。 KeyUp之后引发的TextChanged事件,因此您将在TextBox中准备好新输入的文本。并且KeyDownTextChanged之前提升,因此您需要在TextBox中追加当前文本并按下字符/键。使用KeyUp / KeyDown的缺点是,如果用户使用上下文菜单(右键单击>粘贴)通过复制/剪切粘贴输入文本,则不会收到通知。解决方法是禁用默认上下文菜单,如下所示(或通过样式):

<TextBox ContextMenu="{x:Null}"/>

用户仍然可以使用键盘快捷键进行剪切/复制/粘贴,并且在按下某些键盘键时会通知您的程序。

希望这个主意符合您的需求。

答案 1 :(得分:0)

由于我不确定你到底是怎么回事,所以我会给你两个解决方案。

解决方案1:使用MVVM进行绑定。

将TextBox绑定到viewmodel上的属性,而不是选择OnTextChanged事件。这将通过Property更新文本。从代码更新时,调用方法以更新支持字段。 ViewModel看起来像

public class MyViewModel : INotifyPropertyChanged
{
    private string text;

    public string Text
    {
        get { return text; }
        set
        {
            if (value != text)
            {
                text = value;
                OnPropertyChanged();
                Debug.WriteLine("Binding Example - Keyboard entry");
            }
        }
    }

    public void AddText(string extraText)
    {
        this.text += extraText;
        this.OnPropertyChanged("Text");
        Debug.WriteLine("Binding Example - Code entry");
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

请注意,即使我正在更新AddText方法中的支持字段,我仍然调用OnPropertyChange来更新与TextBox的绑定。 TextBox的xaml是

<TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" />

如果您希望在键入时保存,则UpdateSourceTrigger非常重要。

虽然这是我首选的解决方案,但大量文本可能会导致性能问题。

场景2:OnTextChanged

您已经处理了一个事件,处理所有相关的键盘事件(可能只有Keydown)。你的TextBox Xaml将是

<TextBox x:Name="EntryControl" PreviewKeyDown="UIElement_OnPreviewKeyDown" PreviewKeyUp="UIElement_OnPreviewKeyUp" KeyDown="UIElement_OnKeyDown" KeyUp="UIElement_OnKeyUp" TextChanged="TextBoxBase_OnTextChanged" />

如果每个事件将其名称输出到输出窗口,您将按以下顺序获取事件

  • UIElement_OnPreviewKeyDown
  • UIElement_OnKeyDown
  • TextBoxBase_OnTextChanged
  • UIElement_OnPreviewKeyUp
  • UIElement_OnKeyUp

通过在OnKeyDown事件中设置一个布尔值并在OnTextChanged事件中检查它,您可以测试键盘输入。

注意:按住某个键时,您将获得单个KeyUp事件的多个KeyDown事件。触发事件的顺序是

-UIElement_OnPreviewKeyDown -UIElement_OnKeyDown -TextBoxBase_OnTextChanged -UIElement_OnPreviewKeyDown -UIElement_OnKeyDown -TextBoxBase_OnTextChanged -UIElement_OnPreviewKeyDown -UIElement_OnKeyDown -TextBoxBase_OnTextChanged -UIElement_OnPreviewKeyUp -UIElement_OnKeyUp

所以解决方案仍然会坚持下去。

测试解决方案

如果您想在示例应用中尝试2个场景,我的示例的xaml是

<Window x:Class="StackOverflow._20949513.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}, Path=ViewModel}"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <DockPanel>
            <Button Content="Add Text" DockPanel.Dock="Top" Click="BindingButton_OnClick" />
            <TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" />
        </DockPanel>
        <DockPanel Grid.Row="1">
            <Button Content="Add Text" DockPanel.Dock="Top" Click="EventButton_OnClick" />
            <TextBox x:Name="EntryControl" PreviewKeyDown="UIElement_OnPreviewKeyDown" PreviewKeyUp="UIElement_OnPreviewKeyUp" KeyDown="UIElement_OnKeyDown" KeyUp="UIElement_OnKeyUp" TextChanged="TextBoxBase_OnTextChanged" />
        </DockPanel>
    </Grid>
</Window>

,背后的代码是

public partial class MainWindow : Window
{
    public MainWindow()
    {
        ViewModel = new MyViewModel();
        InitializeComponent();
    }

    public MyViewModel ViewModel { get; set; }

    private void BindingButton_OnClick(object sender, RoutedEventArgs e) { ViewModel.AddText("More Text"); }


    private bool keyboardPressed;

    private void UIElement_OnPreviewKeyDown(object sender, KeyEventArgs e) { DisplayEvent(); }

    private void UIElement_OnPreviewKeyUp(object sender, KeyEventArgs e) { DisplayEvent(); }

    private void UIElement_OnKeyDown(object sender, KeyEventArgs e)
    {
        DisplayEvent();
        keyboardPressed = true;
    }

    private void UIElement_OnKeyUp(object sender, KeyEventArgs e) { DisplayEvent(); }

    private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        try
        {
            if (keyboardPressed)
            {
                DisplayEvent("TextBoxBase_OnTextChanged from Keyboard");
            }
            else
            {
                DisplayEvent("TextBoxBase_OnTextChanged from Code");
            }
        }
        finally
        {
            keyboardPressed = false;
        }
    }

    private void DisplayEvent([CallerMemberName] string caller = null) { Debug.WriteLine(caller); }

    private void EventButton_OnClick(object sender, RoutedEventArgs e) { EntryControl.Text += "More Text"; }
}

ViewModel在答案开始时全部显示。

为简洁起见,已排除正确的异常处理。

我希望这会有所帮助。