参加以下C#课程:
c1 {
event EventHandler someEvent;
}
Run Code Online (Sandbox Code Playgroud)
如果有很多订阅c1的someEvent事件,我想清除所有这些,那么实现这一目标的最佳方法是什么?还要考虑对此事件的订阅可以是lambdas/anonymous delegates.
目前我的解决方案是添加一个ResetSubscriptions()方法,将c1其设置someEvent为null.我不知道这是否有任何看不见的后果.
我有一个按钮控件,我需要删除附加到其Click事件的所有事件处理程序.
怎么可能呢?
Button button = GetButton();
button.Click.RemoveAllEventHandlers();
Run Code Online (Sandbox Code Playgroud) 我已经编写了一个.net 4.0控制台应用程序,它定期与GSM调制解调器通信,以获取收到的SMS消息列表(它是一个USB调制解调器,但代码通过串口驱动程序连接到它并发送AT命令 - 顺便说一句,它是Sierra无线调制解调器,但我不能改变它,我有最新的驱动程序).会发生什么事情,经过一段时间(可能是几小时,也许几天),它就会停止工作.这是一个日志片段......
2012-04-17 23:07:31 DEBUG Modem Check (108) - Executing AT command 'AT+CPMS="ME"'...
2012-04-17 23:07:31 DEBUG Modem Check (108) - Finished executing 'AT+CPMS="ME"'
2012-04-17 23:07:31 DEBUG Modem Check (108) - Detaching event handlers for 'COM13'
2012-04-17 23:07:31 DEBUG Modem Check (108) - Disposing the SerialPort for 'COM13'
Run Code Online (Sandbox Code Playgroud)
这就是日志的结束 - 即使我希望看到至少还有一个语句,这就是相关的代码:
internal T Execute()
{
var modemPort = new SerialPort();
T ret;
try
{
modemPort.ErrorReceived += ModemPortErrorReceived;
modemPort.PortName = _descriptor.PortName;
modemPort.Handshake = Handshake.None;
modemPort.DataBits = 8;
modemPort.StopBits = StopBits.One; …Run Code Online (Sandbox Code Playgroud) 我将创建一个GUI,它将动态创建控件集,并为其分配事件.我需要在运行时添加和删除这些控件.它看起来像这样:
FlowLayoutPanel.Controls.Clear();
<< add new controls, assigning Click events with += >>
Run Code Online (Sandbox Code Playgroud)
我听说用+ =分配事件处理程序会导致内存泄漏(更具体地说,在应用程序退出之前不会释放内存).我想避免这种情况.我知道我可以写一些像这里的函数如何从控件中删除所有事件处理程序以查找所有事件处理程序并删除它们但它看起来非常复杂.
还有另外一种方法吗?调用Dispose有助于删除那些事件处理程序吗?你能破坏对象来强制释放内存,就像在C/C++中一样吗?
谢谢!
PS:问题是,我不知道要分离的事件.我将创建大量标签并向其添加不同类型的onclick事件.当它清理流布局面板时,无法知道哪个事件处理程序附加到哪个标签.
这是示例代码(_flowLP是FlowLayoutPanel) - 此Refresh()函数在应用程序退出之前多次运行.
private void Refresh()
{
Label l;
Random rnd = new Random();
// What code should i add here to prevent memory leaks
_flowLP.Controls.Clear();
l = new Label();
l.Text = "1";
if (rnd.Next(3) == 0) l.Click += Method1;
if (rnd.Next(3) == 0) l.Click += Method2;
if (rnd.Next(3) == 0) l.Click += Method3;
_flowLP.Controls.Add(l);
l = new Label();
l.Text = …Run Code Online (Sandbox Code Playgroud) 我想从按钮中删除所有单击事件处理程序.我在Stack Overflow问题中找到了这个方法如何从控件中删除所有事件处理程序.
private void RemoveClickEvent(Button b)
{
FieldInfo f1 = typeof(Control).GetField("EventClick",
BindingFlags.Static |
BindingFlags.NonPublic);
object obj = f1.GetValue(b);
PropertyInfo pi = b.GetType().GetProperty("Events",
BindingFlags.NonPublic |
BindingFlags.Instance);
EventHandlerList list = (EventHandlerList)pi.GetValue(b, null);
list.RemoveHandler(obj, list[obj]);
}
Run Code Online (Sandbox Code Playgroud)
但是这一行总是返回null:
typeof(Control).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic);
Run Code Online (Sandbox Code Playgroud)
这种方法写于2006年.
这个方法有最新版本吗?
是否有一个普遍接受的最佳实践来创建一个取消订阅自己的事件处理程序?
例如,我想出的第一件事就是:
// Foo.cs
// ...
Bar bar = new Bar(/* add'l req'd state */);
EventHandler handler = new EventHandler(bar.HandlerMethod);
bar.HandlerToUnsubscribe = handler;
eventSource.EventName += handler;
// ...
Run Code Online (Sandbox Code Playgroud)
// Bar.cs
class Bar
{
/* add'l req'd state */
// .ctor
public EventHandler HandlerToUnsubscribe { get; set; }
public void HandlerMethod(object sender, EventArgs args)
{
// Do what must be done w/ add'l req'd state
((EventSourceType)sender).EventName -= this.HandlerToUnsubscribe;
}
}
Run Code Online (Sandbox Code Playgroud)
说这种感觉很乱/坏是轻描淡写的.它与时间依赖紧密耦合(HandlerToUnsubscribe必须在恰当的时间分配精确值).在这种情况下,我觉得我必须扮演一个复杂的角色 - 我有什么愚蠢或简单的东西吗?
我正在创建UI和Winforms中的专有命令基础结构之间的绑定(使用ICommandSystem.Windows.Input中的有用).绑定基础结构的一个方面是,在UI命令组件(如工具栏按钮或菜单项)之间创建绑定的用户可以选择侦听命令的CanExecuteChanged事件,然后根据该状态更新UI的状态 …
我有一个列表Button,并为每个按钮添加一个事件处理程序:
List<Button> buttons = new List<Button>();
for (int i = 0; i < 10; i++)
{
Button btn = new Button();
btn.Click = new RoutedEventHandler(OnbtnClick);
buttons.Add(btn);
}
Run Code Online (Sandbox Code Playgroud)
然后我清除列表:
/* Have I to remove all events here (before cleaning the list), or not?
foreach (Button btn in buttons)
btn.Click -= new RoutedEventHandler(OnbtnClick);
*/
buttons.Clear();
Run Code Online (Sandbox Code Playgroud) 问题:我有一个包含对象列表的文档类.这些对象引发事件,如SolutionExpired,DisplayExpired等文件需要对此作出回应.
文档有时可以交换对象,但是单个对象永远不应该是多个文档的"一部分".
我的文档类包含许多用作事件处理程序的方法.每当一个对象进入文档时,我就会AddHandler用来设置事件,每当从文档中删除一个对象时,我就会RemoveHandler用来撤消损坏.但是,有些情况下很难确保所有步骤都得到适当的处理,因此我最终可能会遇到流氓事件处理程序.
长话短说; 如何删除指向特定方法的所有处理程序?注意,我没有可能的事件源列表,这些可以存储在任何地方.
就像是:
RemoveHandler *.SolutionExpired, AddressOf DefObj_SolutionExpired
Run Code Online (Sandbox Code Playgroud) 我为它创建了一个事件处理程序Textbox.Enter event,它选择文本框中的部分文本,如下所示:
TextBox1.Select(3,5);
结果如下:

当通过经由键盘输入文本框[TAB]或[SHIFT] - [Tab]键,
需要被选择的文本的所述部分被选择好,就像在上面的屏幕截图.
但是,如果不是通过键盘而是通过鼠标输入文本框,
则不会选择任何内容:

似乎发生的事情是这样的:
当我们用鼠标进入文本框时,
点击确实会提升Enter event,但鼠标点击还会将光标的位置设置为文本框内用户用鼠标单击的位置.
并且在运行事件处理程序之后立即执行此光标设置.
所以这意味着,事件处理程序执行的选择(使用该TextBox1.Select(3,5);行)被鼠标的位置覆盖,
这就是为什么用鼠标进入文本框,似乎没有选择任何东西.
如何让鼠标确实抬起Enter event,而不是更改文本框内的光标位置?
因此,我将能够保留我的选择(在代码中发生)并且不会被覆盖.
编辑:
这样做的目的是为了能够轻松选择MM:SS部分时间,这通常是正在编辑的部分(HH或mmm部分很少更改).
c# ×9
.net ×5
events ×5
delegates ×1
memory ×1
memory-leaks ×1
serial-port ×1
vb.net ×1
winforms ×1
wpf ×1