Development Tip

간단한 맞춤 이벤트

yourdevel 2020. 10. 28. 21:10
반응형

간단한 맞춤 이벤트


맞춤 이벤트를 배우려고하는데 하나를 만들려고했지만 문제가있는 것 같습니다.

Form, 정적 클래스 및 사용자 지정 이벤트를 만들었습니다. 내가 달성하려는 것은 Form 버튼을 누르면 정적 클래스 함수를 호출 한 다음 func가 때때로 현재 상태를보고하는 이벤트를 발생시키는 것입니다. Form1은 이벤트가 발생하면 수신하고 발생하면 label1의 텍스트를 변경합니다.

여기 내가 지금까지 가지고있는 것

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

이제 내가 이해하지 못하는 것은 Form1이 이벤트를 처리하고 레이블을 변경할 수 있도록 TestClass에서 이벤트를 발생시키는 방법입니다.


이것은 사용자 지정 이벤트를 생성하고 발생시키는 쉬운 방법입니다. 던지는 클래스에서 대리자와 이벤트를 만듭니다. 그런 다음 코드의 다른 부분에서 이벤트를 구독하십시오. 이미 사용자 지정 이벤트 인수 클래스가 있으므로이를 기반으로 다른 이벤트 인수 클래스를 만들 수 있습니다. NB :이 코드를 컴파일하지 않았습니다.

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. Now when your class is invoked, tell it to connect the event to your new event handler. The reason the += operator is used is because you are appending your particular event handler to the event. You can actually do this with multiple separate event handlers, and when an event is raised, each event handler will operate in the sequence in which you added them.

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

4. Now, when you're ready, trigger (aka raise) the event somewhere in your class code like so:

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

The end result when you run this is that the console will emit "wow this is cool". And if you changed "cool" with a date or a sequence, and ran this event trigger multiple times, you'd see the result come out in a FIFO sequence like events should normally operate.

In this example, I passed 4 strings. But you could change those to any kind of acceptable type, or used more or less types, or even remove the <...> out and pass nothing to your event handler.

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.

Identifying Event Callers

But what if you want to identify the caller to this event in your event handler? This is useful if you want an event handler that reacts with conditions based on who's raised/triggered the event. There are a few ways to do this. Below are examples that are shown in order by how fast they operate:

Option 1. (Fastest) If you already know it, then pass the name as a literal string to the event handler when you trigger it.

Option 2. (Somewhat Fast) Add this into your class and call it from the calling method, and then pass that string to the event handler when you trigger it:

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

Option 3. (Least Fast But Still Fast) In your event handler when you trigger it, get the calling method name string with this:

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

Unsubscribing From Events

You may have a scenario where your custom event has multiple event handlers, but you want to remove one special one out of the list of event handlers. To do so, use the -= operator like so:

MyEvent -= MyEventHandler;

A word of minor caution with this, however. If you do this and that event no longer has any event handlers, and you trigger that event again, it will throw an exception. (Exceptions, of course, you can trap with try/catch blocks.)

Clearing All Events

Okay, let's say you're through with events and you don't want to process any more. Just set it to null like so:

MyEvent = null;

The same caution for Unsubscribing events is here, as well. If your custom event handler no longer has any events, and you trigger it again, your program will throw an exception.


Like has been mentioned already the progress field needs the keyword event

public event EventHandler<Progress> progress;

But I don't think that's where you actually want your event. I think you actually want the event in TestClass. How does the following look? (I've never actually tried setting up static events so I'm not sure if the following will compile or not, but I think this gives you an idea of the pattern you should be aiming for.)

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

참고URL : https://stackoverflow.com/questions/6644247/simple-custom-event

반응형