我正在尝试将eventHandler传递给方法。 在我的方法中,我将使用不同类型的eventHandlers。即KeyDownEventHandler,ClickEventHandler等。
可以这样做吗?
@Enigmativity
这是完整的测试代码。就像我说我试图传递EventHandlers名称。正如你在这里看到的那样。但当我得到每个它的正文而不是真正的事件处理程序。在foreach循环中,您将看到它应该删除或添加事件(订阅或取消订阅)的位置。当我确实得到它的一半工作。 unsubscribed remove删除事件处理程序不起作用。它应该工作的方式是我在form1事件+ =中有6个订阅事件,对于textbox1到textchange来命中。当它发生时,我点击它进入DisableEvents方法它会抛出foreach然后当它完成它再次返回到textbox1_textbox1_textchange。 6次。我希望DisableEvents删除其他订阅的。取决于最后一个变量true或false将设置或删除它。让我知道,如果有任何问题,我可以帮助解决这个问题。 @Enigmativity 这是描述我的问题的最佳方式。 form1设置subscribe(+ =)。然后在textBox1_textChanged事件中我只添加了一行textBox1.TextChanged - = null;而已。当我运行代码6时,订阅被设置,当我单击文本框并键入任何一个char时,textBox1_Changed命中。我认为 - = null应该清除所有订阅,textbox1_Changed不会再次上升,直到我订阅它。我哪里错了?想要一个方法,所以我可以传递参数。但我想这不可能完成或者可以。我继续阅读。感谢
public Form1()
{
InitializeComponent();
//Setup the subscribed here
textBox1.TextChanged += textBox1_TextChanged;
textBox1.TextChanged += textBox1_TextChanged;
textBox1.TextChanged += textBox1_TextChanged;
textBox1.TextChanged += textBox1_TextChanged;
textBox1.TextChanged += textBox1_TextChanged;
textBox1.TextChanged += textBox1_TextChanged;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
DisableEvents(textBox1, "TextChanged", textBox1_TextChanged, false);
}
private static Delegate[] DisableEvents(object target, string eventName, EventHandler eventHandlerName, bool add)
{
FieldInfo fieldInfo = typeof(Control).GetField("Event" + eventName, BindingFlags.NonPublic | BindingFlags.Static);
PropertyInfo propertyInfo = target.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(target, null) as EventHandlerList;
object eventKey = fieldInfo.GetValue(target);
var _eventHandler = eventHandlerList[eventKey] as Delegate;
if (_eventHandler == null)
return null;
Delegate[] invocationList = _eventHandler.GetInvocationList();
foreach (eventHandlerName item in invocationList)
{
if (add)
{
target.GetType().GetEvent(eventName).AddEventHandler(target, item);
}
else
{
target.GetType().GetEvent(eventName).RemoveEventHandler(target, item);
}
}
return invocationList;
}
//here is the example.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyEventsExample
{
public partial class Form1 : DevExpress.XtraEditors.XtraForm
{
public Form1()
{
InitializeComponent();
//Subscribe 8 times
for (int c = 0; c < 7; c++)
{
textBox1.KeyDown += textBox1_KeyDown;
MessageBox.Show("Events added at Start # : " + c.ToString());
}
button1.Click += button1_Click;
}
int a;
int b;
int c;
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
//This should take the subscribed += and remove them -=.
EventDescriptor edTypeDescriptor.GetEvents(textBox1).Find ("KeyDown", true);
if (ed != null)
{
for (int i = 0; i < ed.Attributes.Count; i++)
{
ed.RemoveEventHandler(textBox1, Delegate.CreateDelegate(typeof(KeyEventHandler), this, "textBox1_KeyDown"));
}
}
//after the above is done this event should not work at all any more unless i subscribe to it again
//But it keeps hitting the event the total of the subscried time in this case 8 times it enters in.
//when i make my method ill need a way to pass the typeof in this case its the KeyEWvenHandler.
a++;
MessageBox.Show("Done " + a);
}
private void button1_Click(object sender, EventArgs e)
{
//Lets do it again
//Subscribe 8 times
for (int b = 0; b < 7; b++)
{
textBox1.KeyDown += textBox1_KeyDown;
MessageBox.Show("Event Button Add # : " + b.ToString());
}
}
}
} 生病需要将textBox1中的代码转换为一个方法,像textbox一样传递控件类型,像textbox_KeyDown一样传递事件动作,但最重要的是事件处理程序,如textBox1_KeyDown事件中的KeyEventHandler。但最重要的是清除了我传递方法的所有事件。
答案 0 :(得分:1)
事件处理程序和事件之间存在差异。
事件处理程序只是一个委托。它可以毫无问题地传播。
拿这段代码:
Action foo = () => Console.WriteLine("1");
foo += () => Console.WriteLine("2");
foo();
写出1
&amp; <{1}}被调用时。
我可以将2
作为参数传递给任何方法。问题是委托是不可变的引用类型。这意味着如果您修改委托,例如下面的Action foo
示例,那么您已经创建了一个新委托,并且更改未反映在bar += () => Console.WriteLine("3")
中。当您进行更改时,它们不再是对同一对象的引用。
foo
因此,如果我将该代码添加到原始代码,则会输出Action bar = foo;
bar += () => Console.WriteLine("3");
foo();
bar();
,1
,2
,1
,2
,1
,2
。
向3
代表添加新处理程序时,原始foo
未被修改。
如果您尝试修改自己引用的副本,则无法影响原始代理。
另一方面,事件根本无法传递。这就是编译器的工作方式。只要您具有对包含事件的原始对象的引用,您就只能将处理程序附加到事件并将其分离。
你必须使用棘手的反射代码才能使传递事件成为可能,但这绝对不是一种直接的方法。
我怀疑还有另一个选项适合你。
我建议您使用Microsoft的Reactive Framework。它就像类固醇的事件库。
你可以做这件事:
bar
您通过致电TextBox textBox = new TextBox();
IObservable<EventPattern<TextBox, KeyEventArgs>> keyDowns =
Observable
.FromEventPattern<TextBox, KeyEventArgs>(
textBox, "KeyDown");
IDisposable textBoxKeyDownsSubscription =
keyDowns
.Subscribe(ep =>
{
// Use `ep.Sender` & `ep.EventArgs` here
// Both are strongly-typed
});
来附加活动,并通过致电.Subscribe(...)
分离。
这种方法的优势在于,您现在可以将textBoxKeyDownsSubscription.Dispose()
作为该语言的一等公民传递,并附加和分离订阅者,而不保留对原始对象的引用,也不进行任何反映。 / p>
此外,您可以使用标准的LINQ操作对此对象进行查询。现在这成为可能:
IObservable<EventPattern<TextBox, KeyEventArgs>>
查询TextBox textBox = new TextBox();
IObservable<EventPattern<TextBox, KeyEventArgs>> keyDowns =
Observable
.FromEventPattern<TextBox, KeyEventArgs>(
textBox, "KeyDown");
bool enabled = true;
IObservable<Keys> onlyAOrBWhenEnabled =
from kd in keyDowns
where kd.EventArgs.KeyCode == Keys.A || kd.EventArgs.KeyCode == Keys.B
where enabled == true
select kd.EventArgs.KeyCode;
IDisposable onlyAOrBWhenEnabledSubscription =
onlyAOrBWhenEnabled
.Subscribe(keyCode =>
{
// Use `keyCode` here
});
对原始事件执行逻辑,仅在onlyAOrBWhenEnabled
时返回A
或B
的键。如果您要禁用该事件,则只需设置enabled == true
。
我不清楚你打算做什么enabled = false
,但如果你能澄清一下,我可以提供一个更好的例子来说明如何使用它。
Just NuGet&#34; System.Reactive&#34; &安培; &#34; System.Reactive.Windows.Forms&#34;得到你需要的东西。