简单的定制事件

我试图学习自定义事件,我试图创build一个,但似乎我有一个问题

我已经创build了一个Form,静态类和自定义事件。 我想要实现的是当我按下button时,Form将会调用静态类的function,然后func会不时地上传一个事件来报告当前状态。 如果事件发生,Form1将会侦听,如果是,则会改变label1的Text

这是我到目前为止

public partial class Form1 : Form { public EventHandler<Progress> progress; public Form1() { InitializeComponent(); progress += SetStatus; } private void SetStatus(object sender, Progress e) { label1.Text = e.Status; } private void button1_Click_1(object sender, EventArgs e) { TestClass.Func(); } } 

文件2

 class TestClass { public static void Func() { //time consuming code Report status // time consuming code report status } } public class Progress : EventArgs { public string Status { get; private set; } private Progress() {} public Progress(string status) { Status = status; } } 

现在我不明白的是,我怎么能从TestClass中引发一个事件,所以Form1可以处理事件并更改label.Text

这是创build自定义事件并提升它们的简单方法。 你在抛出的类中创build一个委托和一个事件。 然后从您的代码的另一部分订阅事件。 你已经有了一个自定义的事件参数类,所以你可以build立它来做其他的事件参数类。 注意:我没有编译这个代码。

 public partial class Form1 : Form { private TestClass _testClass; public Form1() { InitializeComponent(); _testClass = new TestClass(); _testClass.OnUpdateStatus += new TestClass.StatusUpdateHandler(UpdateStatus); } private void UpdateStatus(object sender, ProgressEventArgs e) { SetStatus(e.Status); } private void SetStatus(string status) { label1.Text = status; } private void button1_Click_1(object sender, EventArgs e) { TestClass.Func(); } } public class TestClass { public delegate void StatusUpdateHandler(object sender, ProgressEventArgs e); public event StatusUpdateHandler OnUpdateStatus; public static void Func() { //time consuming code UpdateStatus(status); // time consuming code UpdateStatus(status); } private void UpdateStatus(string status) { // Make sure someone is listening to event if (OnUpdateStatus == null) return; ProgressEventArgs args = new ProgressEventArgs(status); OnUpdateStatus(this, args); } } public class ProgressEventArgs : EventArgs { public string Status { get; private set; } public ProgressEventArgs(string status) { Status = status; } } 

你还没有创build一个事件。 要做到这一点写:

 public event EventHandler<Progress> Progress; 

然后,您可以在类声明为普通函数或委托的类中调用Progress

 Progress(this, new Progress("some status")); 

所以,如果你想在TestClass报告进度,事件也应该在那里,它也应该是静态的。 你可以像这样从你的表单订阅它:

 TestClass.Progress += SetStatus; 

另外,您应该重命名ProgressProgressEventArgs ,以便清楚它是什么。

像已经提到的那样进度栏需要关键字事件

 public event EventHandler<Progress> progress; 

但我不认为这是你真正想要的事情。 我想你真的想在TestClass的事件。 以下是怎么看? (我从来没有尝试过设置静态事件,所以我不确定下面是否会编译,但是我认为这给你一个你应该瞄准的模式的概念。)

 public partial class Form1 : Form { public Form1() { InitializeComponent(); TestClass.progress += SetStatus; } private void SetStatus(object sender, Progress e) { label1.Text = e.Status; } private void button1_Click_1(object sender, EventArgs e) { TestClass.Func(); } } public class TestClass { public static event EventHandler<Progress> progress; public static void Func() { //time consuming code OnProgress(new Progress("current status")); // time consuming code OnProgress(new Progress("some new status")); } private static void OnProgress(EventArgs e) { if (progress != null) progress(this, e); } } public class Progress : EventArgs { public string Status { get; private set; } private Progress() {} public Progress(string status) { Status = status; } } 

C#中的事件非常容易,但是我认为MSDN文档让他们非常困惑。 通常,你所看到的大多数文档都讨论了如何从EventArgs基类inheritance一个类,这是有原因的。 但是,这不是最简单的事件发生方式,对于想要快速简单的事情的人来说,在时间紧迫的情况下,使用Actiontypes就是您的票证。

创build事件并订阅他们

1.在class申报后立即在class创build活动。

 public event Action<string,string,string,string>MyEvent; 

2.在你的类中创build你的事件处理器类的方法。

 private void MyEventHandler(string s1,string s2,string s3,string s4) { Console.WriteLine("{0} {1} {2} {3}",s1,s2,s3,s4); } 

3.现在当你的类被调用时,告诉它将事件连接到新的事件处理程序。 使用+=运算符的原因是因为您将特定的事件处理程序附加到事件。 实际上,您可以使用多个单独的事件处理程序执行此操作,并且在引发事件时,每个事件处理程序将按照您添加它们的顺序进行操作。

 class Example { public Example() // I'm a C# style class constructor { MyEvent += new Action<string,string,string,string>(MyEventHandler); } } 

4.现在,当你准备好的时候,在你的class级代码的某个地方触发(也就是举起)这样的事件:

 MyEvent("wow","this","is","cool"); 

当你运行这个的最终结果是控制台会发出“哇这很酷”。 如果你用一个date或者一个序列改变了“cool”,并且多次运行这个事件触发器,你会看到结果以FIFO的顺序出现,就像事件正常运行一样。

在这个例子中,我传递了4个string。 但是你可以把它们改成任何一种可以接受的types,或者使用更多或更less的types,甚至删除<...>出,并且不向你的事件处理器传递任何东西。

而且,如果您有多个自定义事件处理程序,并使用+=运算符将它们全部订阅到您的事件,那么您的事件触发器将按顺序调用它们。

识别事件调用者

但是如果你想在你的事件处理程序中识别这个事件的调用者呢? 如果您希望事件处理程序根据谁发起/触发事件而与条件发生反应,这非常有用。 有几种方法可以做到这一点。 以下是按照操作速度顺序显示的示例:

选项1.(最快)如果你已经知道了,当你触发它的时候,把这个名字作为string传递给事件处理程序。

选项2.(有点快)将其添加到您的类中,并从调用方法中调用它,然后在触发时将该string传递给事件处理程序:

 private static string GetCaller([System.Runtime.CompilerServices.CallerMemberName] string s = null) => s; 

选项3.(最快但仍然快速)在触发它的事件处理程序中,使用以下命令获取调用方法名称string:

 string callingMethod = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().ReflectedType.Name.Split('<', '>')[1]; 

取消订阅活动

您可能有自定义事件具有多个事件处理程序的场景,但是您希望从事件处理程序列表中删除一个特殊事件。 为此,请使用-=运算符,如下所示:

 MyEvent -= MyEventHandler; 

然而,这个小小心谨慎的话。 如果你这样做,那个事件不再有任何事件处理程序,并且你再次触发该事件,它将抛出一个exception。 (例外,当然,你可以用try / catch块来捕获。)

清除所有事件

好吧,我们假设你已经完成了一些事件,而你又不想再做了。 只要将它设置为null就可以了:

 MyEvent = null; 

同样,在这里也要注意取消订阅事件。 如果您的自定义事件处理程序不再有任何事件,并且您再次触发它,则您的程序将引发exception。