暂时取消订阅活动的简洁解决方案
本文关键字:简洁 解决方案 活动 取消 | 更新日期: 2023-09-27 18:32:59
我正在寻找一个简洁的解决方案来暂时取消订阅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;
}
}
另一种解决方案...只是在之前和之后调用函数:
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)) {
}
你必须
使用反射(所以不要忘记导入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";
}
作为您想要的解决方案的替代方案,这就是我过去一直解决这个问题的方式。
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()
中执行代码,无论文本是否因用户操作或应用逻辑而更改,都会更新另一个控件。