我正在寻找一个简洁的解决方案来暂时取消订阅WinForm事件。例如,如果我有一个带有以下事件处理程序的textBox1控件:
private void textBox1_TextChanged(object sender, EventArgs eventArgs)
{
// Do something
}
当我以编程方式更改文本框的内容时,我不希望触发此事件。但不是写作:
try
{
textBox1.TextChanged -= textBox1_TextChanged;
// Change textbox contents without triggering event
}
finally
{
textBox1.TextChanged += textBox1_TextChanged;
}
我正在寻找一些我可以使用的东西:
using(new EventInhibitor(textBox1.TextChanged, textBox1_TextChanged))
{
// Change textbox contents without triggering event
}
问题是如何将textBox1.TextChanged事件传递给构造函数?反射?表达式?
public class EventInhibitor : IDisposable
{
private bool _disposed = false;
private XXX _event;
private EventHandler _handler;
public EventInhibitor(XXX event, EventHandler handler)
{
_event = event;
_handler = handler;
_event -= _handler;
}
public void Dispose()
{
if(_disposed)
return:
_event += _handler;
_event = null;
_handler = null;
_disposed = true;
}
}
答案 0 :(得分:3)
另一种解决方案......只是在之前和之后调用函数:
public class EventInhibitor : IDisposable {
private bool _disposed;
private Action _after;
public EventInhibitor(Action before, Action after)
{
before();
_after = after;
}
public void Dispose() {
if (_disposed)
return;
_disposed = true;
_after();
}
}
用法:
using(new EventInhibitor(() => textBox1.TextChanged -= textBox1_TextChanged,
() => textBox1.TextChanged += textBox1_TextChanged)) {
}
答案 1 :(得分:2)
你必须使用反射(所以不要忘记导入System.Reflection
)。您可以将控件(或对象,如果您希望它更通用)和事件名称作为字符串传递:
public class EventInhibitor : IDisposable
{
private bool _disposed = false;
private EventInfo _event;
private EventHandler _handler;
private Control _control;
public EventInhibitor(Control c, string EventName, EventHandler handler)
{
_event = c.GetType().GetEvent(EventName);
_handler = handler;
_control = c;
_event.RemoveEventHandler(_control, _handler);
}
public void Dispose()
{
if (_disposed)
return;
_event.AddEventHandler(_control, _handler);
_event = null;
_handler = null;
_control = null;
_disposed = true;
}
}
然后使用它:
using (new EventInhibitor(textBox1, "TextChanged", textBox1_TextChanged))
{
textBox1.Text = "Hello World";
}
答案 2 :(得分:0)
作为您想要的解决方案的替代方案,这就是我过去总是解决这个问题的方法。
TextBox myTextBox;
private string _text;
public string Text
{
get
{
return _text;
}
set
{
if (_text != value)
{
_text = value;
OnTextChanged();
}
}
}
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (Text != myTextBox.Text)
{
// the user must have edited the TextBox
Text = myTextBox.Text;
}
}
private void OnTextChanged()
{
if (myTextBox.Text != Text)
myTextBox.Text = Text;
}
这样,当用户通过在框中键入来更改文本时,它会引发事件并执行您选择的一些代码。但是如果手动设置Text属性,它只会引发一次事件而不是两次。如果您想对用户编辑文本框的方式做出不同的反应,那么您可以在事件处理程序中添加一些额外的代码,它只会在文本因用户输入而更改时执行。
通过这种方式,您可以解除处理文本更改方式的不同方面。例如,您可能希望在OnTextChanged()
中执行代码,该代码会更新另一个控件,无论文本是否因用户操作或应用程序逻辑而更改。