简单的自定义事件

本文关键字:事件 自定义 简单 | 更新日期: 2023-09-27 18:01:54

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

我已经创建了一个表单,静态类和自定义事件。我想要实现的是,当我按下按钮表单将调用静态类函数,然后函数将不时上升一个事件来报告当前状态。如果事件被触发,Form1将监听,如果事件被触发,它将改变label 的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就可以处理事件和改变标签。文本

简单的自定义事件

这是一种创建自定义事件并引发它们的简单方法。在抛出事件的类中创建委托和事件。然后从代码的另一部分订阅该事件。你已经有了一个自定义事件参数类所以你可以在它的基础上创建其他事件参数类。注:我没有编译这段代码。

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;

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

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

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

TestClass.Progress += SetStatus;

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

事件在c#中非常简单,但是MSDN文档在我看来使它们非常混乱。通常,您看到的大多数文档都讨论如何从EventArgs基类继承一个类,并且有的原因。然而,这并不是制作事件最简单的方法,对于那些想要快速简单的东西的人来说,在时间紧张的情况下,使用Action类型是你的票。

创建事件&订阅

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个字符串。但是您可以将它们更改为任何可接受的类型,或者使用更多或更少的类型,甚至删除<...>并且不向事件处理程序传递任何内容。

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

识别事件调用者

但是,如果您想在事件处理程序中标识此事件的调用者,该怎么办?如果您想要一个事件处理程序,根据谁引发/触发了事件而对条件做出反应,这是很有用的。有几种方法可以做到这一点。下面是按操作速度排序的示例:

选项1。(最快)如果你已经知道它,那么当你触发它时,把它的名字作为一个文字字符串传递给事件处理程序。

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

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

选项。在你的事件处理程序中,当你触发它时,用这个来获取调用方法的名称字符串:

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

取消订阅事件

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

MyEvent -= MyEventHandler;
然而,这里有一个小小的警告。如果您这样做,而那个事件不再有任何事件处理程序,并且您再次触发该事件,它将抛出异常。(当然,可以使用try/catch块来捕获异常。)

清除所有事件

好的,假设您已经处理完事件,并且不想再处理任何事件。只需将其设置为null,如下所示:

MyEvent = null;

对于取消订阅事件也有同样的注意事项。如果您的自定义事件处理程序不再具有任何事件,并且您再次触发它,则程序将抛出异常。

就像已经提到的,进度字段需要关键字event

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