простое пользовательское событие


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

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

4 ответа:

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

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, так что понятно, что это есть.

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

события довольно просты в 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. Теперь, когда вы будете готовы, триггер (aka raise) событие где-то в вашем коде класса, например:

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;

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