simple custom event

我正在尝试学习自定义事件,我已经尝试创建一个,但似乎我有一个问题

我已经创建了一个 Form、静态类和自定义事件。我试图实现的是,当我按下按钮窗体将调用静态类函数,然后 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可以处理事件和更改标签。短信

163712 次浏览

You haven't created an event. To do that write:

public event EventHandler<Progress> Progress;

然后,您可以在类中像普通函数或委托那样声明 Progress:

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

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

TestClass.Progress += SetStatus;

此外,您可能应该将 Progress重命名为 ProgressEventArgs,以便清楚它是什么。

This is an easy way to create custom events and raise them. You create a delegate and an event in the class you are throwing from. Then subscribe to the event from another part of your code. You have already got a custom event argument class so you can build on that to make other event argument classes. N.B: I have not compiled this code.

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;
}
}

如前所述,进度字段需要关键字事件

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基类继承,这里有 一个理由。然而,这并不是最简单的方法来制作事件,对于那些想要快速简单的东西的人来说,在时间紧迫的情况下,使用 Action类型就是你的门票。

Creating Events & Subscribing To Them

1. 在 class声明之后在类中创建事件。

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

2. 在类中创建事件处理程序类方法。

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. 现在,当你准备好了,在类代码的某个地方触发(也就是引发)事件,如下所示:

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

当你运行它的时候,最终的结果是控制台会发出“哇,这太酷了”的声音。如果你用一个日期或序列改变“酷”,并且多次运行这个事件触发器,你会看到结果以 FIFO 序列出来,就像事件应该正常运行一样。

在这个例子中,我传递了4个字符串。但是您可以将它们更改为任何类型的可接受类型,或者使用更多或更少的类型,甚至可以删除 <...>并不向事件处理程序传递任何内容。

And, again, if you had multiple custom event handlers, and subscribed them all to your event with the += operator, then your event trigger would have called them all in sequence.

识别事件调用方

但是,如果希望在事件处理程序中标识此事件的调用方,该怎么办呢?如果您希望事件处理程序根据引发/触发事件的人对条件作出反应,那么这非常有用。有几种方法可以做到这一点。下面是一些例子,它们按照操作速度的快慢顺序排列:

选择一。(最快)如果您已经知道它,那么当您触发它时,将该名称作为文本字符串传递给事件处理程序。

选择二。(稍微快一点)将这个函数添加到类中,并从调用方法调用它,然后在触发它时将该字符串传递给事件处理程序:

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

选择三。(最小快速但仍然快速)在触发事件处理程序时,使用以下命令获得调用方法名字符串:

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

从事件中取消订阅

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

MyEvent -= MyEventHandler;

不过,我还是要提醒你一句。如果执行此操作,而该事件不再具有任何事件处理程序,并再次触发该事件,则它将引发异常。(当然,例外情况下,您可以使用 try/catch 块来捕获。)

清除所有活动

好吧,假设你不想再处理这些事情了。像这样设置为 null:

MyEvent = null;

这里也对取消订阅事件提出了同样的警告。如果您的自定义事件处理程序不再有任何事件,并且您再次触发它,则程序将引发异常。