Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как работать с событиями? 
:(
    Опции темы
Dims
Дата 25.10.2008, 21:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Объясните попроще, как работать с событиями?

Вот в джаве всё просто: если отправитель события, а есть получатель. Если получатель хочет знать о наступлении события, то он регистрирует у отправителя. Всё. Два участника. Ещё может быть в виде отдельного класса заведено событие. Тогда будет три участника, причём все осмысленны:

1) отправитель
2) получатель
3) событие

А что у нас в Си#?

Вот, например, читаю тут: http://msdn.microsoft.com/en-us/library/9aackb16(VS.85).aspx

Простая ситуация, будильник звенит и кого-то будет. В Джаве было бы максимум три класса: будильник, спящий человек и звонок.

А тут: 

AlarmEventArgs - это, наверное, отображение звонка
AlarmEventHandler - что отображается?
AlarmClock - это будильник
WakeMeUp - что это?

А, понял, это спящий человек...

Пока отбой smile

Хотя нафига ещё делегат заводить...

Добавлено через 9 минут и 46 секунд
А вот, такой вопрос. 

Допустим, я хочу как-то говорить, что данный класс у меня будет реагировать на некие события.

В Джаве я создавал интерфейс получателя событий и делал, чтобы класс его имплементил.

А тут что?

И можно ли как-то создать интерфейс или что-то типа того, чтобы указывать, что класс будет отправителем событий?

В Джаве этого сделать нельзя. Там надо просто по договорённости определить методы Add-чего-то-там-Listener и тогда, если такой метод в классе есть, то значит, класс является отправителем соответствующих событий. 

А как тут?
PM MAIL   Вверх
PashaPash
Дата 25.10.2008, 22:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(Dims @  25.10.2008,  21:26 Найти цитируемый пост)
И можно ли как-то создать интерфейс или что-то типа того, чтобы указывать, что класс будет отправителем событий?

В Джаве этого сделать нельзя. Там надо просто по договорённости определить методы Add-чего-то-там-Listener и тогда, если такой метод в классе есть, то значит, класс является отправителем соответствующих событий. 

Тут точно так же, но есть ньюансы smile В получателе вместо интерфейса - метод с нужной сигнатурой - AlarmEventHandler. В отправителе - event, который на самом деле - две функции add/remove + общие для них метаданные. Потом где-то в коде связываешь получателя и отправителя - создаешь из его метода делегат AlarmEventHandler, вызываешь AlarmClock.add_Alarm. Т.е. внутри так же работает, только синтаксис немного отличается.


--------------------
PM MAIL WWW   Вверх
QryStaL
Дата 25.10.2008, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Intellectual feast
**


Профиль
Группа: Участник
Сообщений: 914
Регистрация: 30.11.2005

Репутация: 14
Всего: 32



Dims, здесь очень хорошо подойдет паттерн Observer из GoF
Делегат выступает в качестве Observer, event в качестве Subject. Соответственно ConcreteObserver - класс, в котором описывается метод с сигнатурой, соответствующей делегату, ConcreteSubject - класс, содержащий event

Это сообщение отредактировал(а) QryStaL - 25.10.2008, 22:22

Присоединённый файл ( Кол-во скачиваний: 18 )
Присоединённый файл  observer.gif 8,80 Kb


--------------------
I don't need a reason being who I am...
PM MAIL ICQ   Вверх
Dims
Дата 25.10.2008, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



А этот "Обзёрвер" чем-то отличается от того, что я описал словами?


PashaPash, а как мне сделать интерфейс, который бы был отправителем? 

Я хочу определить тип, который бы мог содержаться в графическом элементе управления и который бы автоматически перерисовывался бы.

Ну уровне классов, вроде, понятно:

1) надо определить делегата:

Код

public delegate void RedrawHandler(Picture sender);


2) внутри класса надо определить событие

Код

event RedrawHandler Redraw;



3) потом определить функцию

Код

private void OnRedraw()
        {
            RedrawHandler handler = Redraw;
            if (handler != null)
            {
                handler(this);
            }

        }


и

4) вызывать эту функцию после каждого обновления.

Кстати, сама по себе необходимость определять 3 сущности кажется мне странной.

Ну а как это сделать на уровне интерфейса?

когда я в интерфейсе написал

Код

interface IDarkness
    {
        void Draw(Graphics g);
        Size GetSize();
        double GetDarknessDouble(int x, int y);
        string[] DebugOutput(double thresold);

        event RedrawHandler Redraw;
    }


оно мне стало говорить, что 

'Test.Etalon' does not implement interface member 'Test.IDarkness.Redraw'    

Etalon -- это класс, который реализует интерфейс.

Что я должен определить в этом классе (и нафига)?
PM MAIL   Вверх
PashaPash
Дата 26.10.2008, 00:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Dims, интерфейс - это буквально список того, что должно быть реализовано в классе. Строчка "event RedrawHandler Redraw;" в интерфейсе означает только что реализующие его классы должны объявить event с типом обработчика RedrawHandler и именем Redraw. Т.е. что все классы с этим интерфейсом должны реализовать add_Redraw и remove_Redraw.
Код

[MethodImpl(MethodImplOptions.Synchronized)]
void add_Redraw(EventHandler value);
 
[MethodImpl(MethodImplOptions.Synchronized)]
void remove_Redraw(EventHandler value);

Класс должен эти методы реализовать. Фишка в том, что точно такая же строчка строчка в классе превращается в метаданные и стандартную реализацию евента:
Код

private EventHandler Redraw;

[MethodImpl(MethodImplOptions.Synchronized)]
public void add_Redraw(EventHandler value)
{
    this.Redraw = (EventHandler) Delegate.Combine(this.Redraw, value);
}

[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_Redraw(EventHandler value)
{
    this.Redraw = (EventHandler) Delegate.Remove(this.Redraw, value);
}

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


--------------------
PM MAIL WWW   Вверх
VK_Techno
Дата 26.10.2008, 09:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 29.9.2007

Репутация: нет
Всего: нет



Для реализации эвента из интерфейса достаточно его public-объявления в классе, реализующем этот интерфейс. Дополнительные методы (типа add_Event() и другие) - лишь следование гайдлайнам от MS.
PM MAIL   Вверх
Dims
Дата 26.10.2008, 11:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(VK_Techno @  26.10.2008,  09:15 Найти цитируемый пост)
достаточно его public-объявления в классе, реализующем этот интерфейс

Что-то мне казалось, что я так и попробовал, но возникла какая-то другая ошибка.
PM MAIL   Вверх
PashaPash
Дата 26.10.2008, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(VK_Techno @  26.10.2008,  09:15 Найти цитируемый пост)
Для реализации эвента из интерфейса достаточно его public-объявления в классе, реализующем этот интерфейс. Дополнительные методы (типа add_Event() и другие) - лишь следование гайдлайнам от MS. 

Это зависит не от следования гайдлайнам, а от используемого компилятора/VES. Компилятор C# в .NET добавляет в интерфейс функции add/remove, и их обязательно придется реализовать в классе. Хотя бы в виде public event, для которого тот же компилятор сгенерирует стандартную реализацию add/remove.
Цитата(Dims @  26.10.2008,  11:27 Найти цитируемый пост)
Что-то мне казалось, что я так и попробовал, но возникла какая-то другая ошибка. 

Мне кажется что для исправления какой-т другой ошибки надо как-то по-другому подправить код.


--------------------
PM MAIL WWW   Вверх
Dims
Дата 1.11.2008, 15:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Вот тогда вопросы по коду из доки:

Код

public class Publisher
    {
        // Declare the delegate (if using non-generic pattern).
        public delegate void SampleEventHandler(object sender, SampleEventArgs e);

        // Declare the event.
        public event SampleEventHandler SampleEvent;

        // Wrap the event in a protected virtual method
        // to enable derived classes to raise the event.
        protected virtual void RaiseSampleEvent()
        {
            // Raise the event by using the () operator.
            SampleEvent(this, new SampleEventArgs("Hello"));
        }
    }


1) можно ли было делегат объявить так

public delegate void SampleEventHandler(Publisher sender, int arg1, int arg2);

Казалось бы, это логичнее. Поскольку источником данных событий может быть только данный класс, то и тип параметра sender должен быть таким. Поскольку параметры события предопределены, проще явно описать их набор и типы, а не заворачивать в дополнительный класс SampleEventArgs

2) зачем определять функцию RaiseSampleEvent, разве Publisher не сможет запускать события просто при помощи команды

SampleEvent(this, 1, 2, 3)

Или наследники не смогут этого делать даже несмотря на то, что событие объявлено public?

3) не надо ли было внутри RaiseSampleEvent проверить SampleEvent на null? Что будет, если никто не подписан на событие, а будет вызван метод RaiseSampleEvent?
PM MAIL   Вверх
QryStaL
Дата 1.11.2008, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Intellectual feast
**


Профиль
Группа: Участник
Сообщений: 914
Регистрация: 30.11.2005

Репутация: 14
Всего: 32



Цитата(Dims @  1.11.2008,  15:33 Найти цитируемый пост)
2) зачем определять функцию RaiseSampleEvent, разве Publisher не сможет запускать события просто при помощи командыSampleEvent(this, 1, 2, 3)Или наследники не смогут этого делать даже несмотря на то, что событие объявлено public?

Во-первых, метод RaiseSampleEvent описан неправильно, должно быть так
Код

        protected virtual void RaiseSampleEvent()
        {
            // Raise the event by using the () operator.
            if (SampleEvent != null)
            {
                SampleEvent(this, new SampleEventArgs("Hello"));
            }
        }


Во-вторых public являются только методы AddHandler и RemoveHandler; поле, содержащее экземпляр делегата, является private. Поэтому наследники смогут вызвать событие только через RaiseSampleEvent.

Цитата(Dims @  1.11.2008,  15:33 Найти цитируемый пост)
Что будет, если никто не подписан на событие, а будет вызван метод RaiseSampleEvent?

NullReferenceException


--------------------
I don't need a reason being who I am...
PM MAIL ICQ   Вверх
Rififi
Дата 1.11.2008, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1254
Регистрация: 9.3.2008

Репутация: 5
Всего: 36



Dims
1) можно ли было делегат объявить так

public delegate void SampleEventHandler(Publisher sender, int arg1, int arg2);

Можно, но MS рекомендует определять параметры через наследование от EventArgs

PS. вместо проверки на null, можно подписаться на "заглушку"
SampleEvent += delegate {};

PM MAIL   Вверх
Dims
Дата 1.11.2008, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(QryStaL @  1.11.2008,  15:53 Найти цитируемый пост)
Во-вторых public являются только методы AddHandler и RemoveHandler

А почему? Ведь тогда не будет возможности использовать мощь оператора +=?


Цитата(QryStaL @  1.11.2008,  15:53 Найти цитируемый пост)
поле, содержащее экземпляр делегата, является private

А почему? Что плохого, если оно будет public?


PM MAIL   Вверх
QryStaL
Дата 2.11.2008, 03:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Intellectual feast
**


Профиль
Группа: Участник
Сообщений: 914
Регистрация: 30.11.2005

Репутация: 14
Всего: 32



Цитата(Dims @  1.11.2008,  17:56 Найти цитируемый пост)
А почему? Ведь тогда не будет возможности использовать мощь оператора +=?

как раз += и -= соответствуют AddHandler и RemoveHandler


Цитата(Dims @  1.11.2008,  17:56 Найти цитируемый пост)
А почему? Что плохого, если оно будет public?

инкапсуляция


--------------------
I don't need a reason being who I am...
PM MAIL ICQ   Вверх
Dims
Дата 5.11.2008, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(QryStaL @  2.11.2008,  03:01 Найти цитируемый пост)
как раз += и -= соответствуют AddHandler и RemoveHandler

Я понимаю, но как же я смогу их использовать, если событие будет private?
PM MAIL   Вверх
PashaPash
Дата 5.11.2008, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(Dims @  5.11.2008,  15:01 Найти цитируемый пост)
Я понимаю, но как же я смогу их использовать, если событие будет private? 

Для public события компилятор генерирует public методы add/remove и private делегат. Подписываться может любой, вызывать событие - только сам класс.


--------------------
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1121 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.