简体   繁体   English

如何在 C# 事件中区分是代码更改还是用户更改?

[英]How to distinguish in a C# event if a change was made from code or by the user?

I have a simple TextBox that is empty in the beginning.我有一个简单的TextBox ,一开始是空的。 I have a simple event, _TextChanged, to know when the user changed anything in that TextBox .我有一个简单的事件 _TextChanged 来了解用户何时更改了该TextBox任何内容。 However, the event fires if I do anything with it myself from within code.但是,如果我自己在代码中对其进行任何操作,则会触发该事件。 Like setting textbox.Text = "Test";像设置textbox.Text = "Test"; or similar.或类似。

    private void textNazwa_TextChanged(object sender, EventArgs e) {
        changesToClient = true;
    }

How do I make the event only fire on user interaction and not code changes?如何使事件仅在用户交互时触发而不是代码更改?

I've been using this process, and it seems to work well.我一直在使用这个过程,它似乎工作得很好。 If the event fires and the focus is not in the textbox, then I ignore the request, so when I set the text the focus is elsewhere, but when the user is typing in the textbox, it has the focus, so I acknowledge the changes.如果事件触发并且焦点不在文本框中,那么我会忽略该请求,因此当我设置文本时,焦点在其他地方,但是当用户在文本框中键入时,它具有焦点,因此我确认更改.

private void textNazwa_TextCanged(object sender, EventArgs e)
{
    if ( !textNazwa.Focused) 
        return; 
}

The event itself does not make a distinction between text entered via user input and text changed via code.事件本身不区分通过用户输入输入的文本和通过代码更改的文本。 You'll have to set a flag yourself that tells your code to ignore the event.您必须自己设置一个标志,告诉您的代码忽略该事件。 For example,例如,

private bool ignoreTextChanged;

private void textNazwa_TextCanged(object sender, EventArgs e)
{
    if (ignoreTextChanged) return;
}

Then use this to set the text instead of just calling Text = "...";然后使用它来设置文本而不是仅仅调用Text = "..."; :

private void SetTextboxText(string text)
{
    ignoreTextChanged = true;

    textNazwa.Text = text;

    ignoreTextChanged = false;
}

Judging by your comment to another answer, it sounds like you have quite a number of textboxes.从你对另一个答案的评论来看,听起来你有很多文本框。 In that case, you could modify the function in this way:在这种情况下,您可以通过以下方式修改函数:

private void SetTextBoxText(TextBox box, string text)
{
    ignoreTextChanged = true;

    box.Text = text;

    ignoreTextChanged = false;
}

Then call it like this:然后像这样调用它:

SetTextBoxText(textNazwa, "foo");

This would accomplish the same thing as just doing textNazwa.Text = "foo" , but will set the flag letting your event handler know to ignore the event.这将完成与仅执行textNazwa.Text = "foo"相同的事情,但会设置标志让您的事件处理程序知道忽略该事件。

Well you can't not really anyway.那么你不能真的无论如何。 What you can do is remove the handler before you make your change and add it back after you've made the change.您可以做的是在进行更改之前删除处理程序,并在进行更改后将其添加回来。

eg例如

  textNazwa.TextChanged -= textNazwa_TextChanged;
  textbox.Text = "Test";
  textNazwa.TextChanged += textNazwa_TextChanged;

If your method has the same scope as where you're changing the value of the text box as the textNazwa_TextChanged (eg both are in a form) you could set a flag instead or if that's not oopsy enough for you, you could use Chain Of Responsiblity to determine if the textNazwa_TextChanged method should be called如果您的方法与您将文本框的值更改为textNazwa_TextChanged (例如两者都在一个表单中),您可以设置一个标志,或者如果这对您来说不够好,您可以使用 Chain Of确定是否应该调用textNazwa_TextChanged方法的责任

I suggest you use Bindings for your TextBox with a presenter that has properties, so if you need to change your values in the code (for testing for example) you don't to fire events or change to UI code.我建议您使用具有属性的演示者的 TextBox 绑定,因此如果您需要更改代码中的值(例如用于测试),您不要触发事件或更改为 UI 代码。 The only thing you need to do is to set a value on your Presenter.您唯一需要做的就是在 Presenter 上设置一个值。

public class Presenter : INotifyPropertyChanged
{
    public string MyTextValue { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;
    /// Create a method here that raises the event that you call from your setters..
}

And then in you Windows Forms code you need a bindingSource set to your Presenter, and add a Binding to you textBoxes:然后在您的 Windows 窗体代码中,您需要将 bindingSource 设置为您的 Presenter,并向您的文本框添加一个 Binding:

EDIT编辑

private BindingSource myPresenterSource ;
this.myPresenterSource = new System.Windows.Forms.BindingSource(this.components);
// Some time later in the

((System.ComponentModel.ISupportInitialize)(this.myPresenterSource )).BeginInit();
// you set the DataSource of your BindingSource
// m_SettingsBindingSource
//
this.myPresenterSource .DataSource = typeof(Presenter );

// and when you create your TextBox you do this :
this.YourTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Text",
   this.myPresenterSource, "MyTextValue", true,
   System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));

Then in your InitializeComponent you set the source like this :然后在您的 InitializeComponent 中设置源如下:

myPresenterSource.DataSource = new Presenter();

Check more resources by looking for how to implement the Movel-View-Presenter (MVP) in Windows Forms.查看更多资源,了解如何在 Windows 窗体中实现Movel-View-Presenter (MVP)。

To me I would implement it this way对我来说,我会以这种方式实现它

bool wasUserTyping = false;
private void textNazwa_KeyUp(object sender, KeyEventArgs e){
     wasUserTyping = true;
}

private void textNazwa_TextChanged(object sender, TextChangedEventArgs e){
    if(wasUserTyping){
          //Yaaay!! User did type
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM