简单的自定义事件

Bil*_*ill 72 c# events

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

我创建了一个Form,静态类和自定义事件.我想要实现的是当我按下按钮时,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();
    }

 }
Run Code Online (Sandbox Code Playgroud)

档案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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我不明白的是,如何从TestClass中提取事件,以便Form1可以处理事件并更改label.Text

the*_*fly 133

这是创建自定义事件并提升自定义事件的简便方法.您在要抛出的类中创建委托和事件.然后从代码的另一部分订阅该事件.您已经有了一个自定义事件参数类,因此您可以构建它以创建其他事件参数类.注意:我还没有编译这段代码.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 关于事件的另一个重要问题在[link](http://stackoverflow.com/questions/2963999/is-it-necessary-to-unsubscribe-from-events)中进行了讨论.要取消订阅事件,它是 - =而不是+ =.例如_testClass.OnUpdateStatus - = UpdateStatus; 放置取消订阅代码的位置是另一个问题,但还有其他堆栈溢出问题可以解决这个问题. (3认同)

svi*_*ick 19

您尚未创建活动.要做到这一点写:

public event EventHandler<Progress> Progress;
Run Code Online (Sandbox Code Playgroud)

然后,您可以Progress从声明正常函数或委托的类中调用:

Progress(this, new Progress("some status"));
Run Code Online (Sandbox Code Playgroud)

因此,如果您想报告进度TestClass,那么事件也应该在那里,它也应该是静态的.您可以从表单订阅它,如下所示:

TestClass.Progress += SetStatus;
Run Code Online (Sandbox Code Playgroud)

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


Vol*_*ike 13

在C#中事件非常简单,但在我看来,MSDN文档让它们变得非常混乱.通常,您看到的大多数文档都讨论了如何使类继承自基EventArgs类,这是有原因的.然而,这不是制作活动的最简单方式,对于想要快速简便的人来说,并且在时间紧迫的情况下,使用该Action类型就是您的票.

创建事件和订阅他们

1.在class宣布之后立即在课堂上创建活动.

public event Action<string,string,string,string>MyEvent;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

4.现在,当你准备就绪时,在你的类代码中的某个地方触发(也就是加注)事件,如下所示:

MyEvent("wow","this","is","cool");
Run Code Online (Sandbox Code Playgroud)

运行此操作时的最终结果是控制台将发出"哇这很酷".如果您使用日期或序列更改"酷",并多次运行此事件触发器,您会看到结果出现在FIFO序列中,就像事件应该正常运行一样.

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

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

识别事件呼叫者

但是,如果您想在事件处理程序中识别此事件的调用者,该怎么办?如果您希望事件处理程序根据引发/触发事件的人员的条件做出反应,这将非常有用.有几种方法可以做到这一点.以下示例按其运行速度顺序显示:

选项1.(最快)如果您已经知道它,则在触发时将名称作为文字字符串传递给事件处理程序.

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

private static string GetCaller([System.Runtime.CompilerServices.CallerMemberName] string s = null) => s;
Run Code Online (Sandbox Code Playgroud)

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

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

取消订阅活动

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

MyEvent -= MyEventHandler;
Run Code Online (Sandbox Code Playgroud)

但是,对此我要小心谨慎.如果您执行此操作并且该事件不再具有任何事件处理程序,并且您再次触发该事件,则会引发异常.(例外,当然,您可以使用try/catch块进行陷阱.)

清除所有事件

好吧,让我们说你已经完成了事件,你不想再处理了.只需将其设置为null,如下所示:

MyEvent = null;
Run Code Online (Sandbox Code Playgroud)

Unsubscribing事件也同样谨慎.如果您的自定义事件处理程序不再有任何事件,并再次触发它,您的程序将抛出异​​常.


Jos*_*sso 9

就像已经提到的那样,progress字段需要关键字事件

public event EventHandler<Progress> progress;
Run Code Online (Sandbox Code Playgroud)

但我不认为那是你真正想要的活动.我想你真的想要参加这个活动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;
    }
}
Run Code Online (Sandbox Code Playgroud)