простое пользовательское событие - PullRequest
71 голосов
/ 11 июля 2011

Я пытаюсь изучить пользовательские события, и я пытался создать одно, но кажется, что у меня есть проблема

Я создал форму, статический класс и пользовательское событие. Я пытаюсь добиться того, чтобы при нажатии кнопки 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;
    }
}

Теперь я не понимаю, как я могу вызвать событие из TestClass, чтобы Form1 мог обработать событие и изменить метку. Текст

Ответы [ 4 ]

131 голосов
/ 11 июля 2011

Это простой способ создавать собственные события и вызывать их.Вы создаете делегата и событие в классе, из которого вы бросаете.Затем подпишитесь на событие из другой части вашего кода.У вас уже есть собственный класс аргумента события, поэтому вы можете использовать его для создания других классов аргумента события.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;
    }
}
19 голосов
/ 11 июля 2011

Вы не создали событие. Для этого напишите:

public event EventHandler<Progress> Progress;

Затем вы можете вызвать Progress из класса, где он был объявлен как обычная функция или делегат:

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

Итак, если вы хотите сообщить о прогрессе в TestClass, событие также должно быть там, и оно должно быть статичным. Вы можете подписаться на него из вашей формы следующим образом:

TestClass.Progress += SetStatus;

Кроме того, вам, вероятно, следует переименовать Progress в ProgressEventArgs, чтобы было понятно, что это такое.

11 голосов
/ 14 октября 2017

События довольно просты в 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 строки.Но вы можете изменить их на любой приемлемый тип, или использовать более или менее типы, или даже удалить <...> out и ничего не передавать обработчику событий.

И, опять же, если у вас было несколько пользовательскихобработчики событий и подписав их все на ваше событие с оператором +=, тогда ваш триггер событий будет вызывать их всех по порядку.

Идентификация вызывающих событий

Но что, если вы хотитеопределить вызывающего на это событие в вашем обработчике событий?Это полезно, если вы хотите обработчик события, который реагирует на условия, основанные на том, кто вызвал / вызвал событие.Есть несколько способов сделать это.Ниже приведены примеры, которые показаны в порядке их быстродействия:

Вариант 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;

То же самое предостережение для событий отписки также здесь.Если в вашем пользовательском обработчике событий больше нет событий, и вы запускаете его снова, ваша программа выдаст исключение.

9 голосов
/ 11 июля 2011

Как уже было упомянуто, поле прогресса требует ключевого слова event

public event EventHandler<Progress> progress;

Но я не думаю, что именно там вы на самом деле хотите ваше событие.Я думаю, что вы действительно хотите событие в TestClass.Как выглядит следующее?(Я никогда не пытался настроить статические события, поэтому я не уверен, скомпилируется ли следующее или нет, но я думаю, что это дает вам представление о шаблоне, к которому вы должны стремиться.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...