Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > События компонента


Автор: Unsane 14.3.2008, 13:34
Вот возник такой вопрос.
На одно и тоже событие можно повесить несколько обработчиков. Например:
Код

this.button1.Click += new System.EventHandler(this.button11_Click);
this.button1.Click += new System.EventHandler(this.button12_Click);
this.button1.Click += new System.EventHandler(this.button13_Click);

Можно ли получить список этих обработчиков и отключить, например, первый и третий?

Автор: HAL707 14.3.2008, 17:14
Код

System.EventHandler h1= new System.EventHandler(this.button11_Click);
System.EventHandler h2= new System.EventHandler(this.button12_Click);
System.EventHandler h3= new System.EventHandler(this.button13_Click);

//подключаем
this.button1.Click += h1
this.button1.Click += h2
this.button1.Click += h3

//отключаем
this.button1.Click -= h1
this.button1.Click -= h3

Автор: CYBERDREAM 14.3.2008, 17:20
Думаю он не совсем это имел ввиду, а вывести к примеру список подключенных обработчиков..

Автор: Unsane 14.3.2008, 18:30
Цитата(CYBERDREAM @ 14.3.2008,  17:20)
Думаю он не совсем это имел ввиду, а вывести к примеру список подключенных обработчиков..

Именно так. smile 

Автор: vponomarov 14.3.2008, 18:43
Unsane, по-моему нет готового механизма для решения вашей задачи
как вариант, можно при добавлении обработчика событий записывать его куда-нить и в случае необходимости удалять его оператором -=
хотя конечно как-то некрасиво получается smile 

Автор: Ctrl 16.3.2008, 13:15
Тут все зависит от того является ли это событие собственным событием класса или это событие другого класса.
Во втором случае простых решений нет, а вот в первом вполне можно кое чего сделать.
Вот пример из которого становится ясна моя идея:
Код

using System;
using NUnit.Framework;

namespace TestOwnEventManagement {
    public class Foo {
        public event EventHandler SomeEvent;
        public EventHandler[] Listeners {
            get { return GetListenersCore(); }
        }
        public void RemoveListener(int index) {
            EventHandler[] list = Listeners;
            if (index < list.Length) SomeEvent -= list[index];
        }
        EventHandler[] GetListenersCore() {
            EventHandler[] list = new EventHandler[0];
            if (SomeEvent != null) {
                Delegate[] delegates = SomeEvent.GetInvocationList();
                list = new EventHandler[delegates.Length];
                for(int i = 0; i< delegates.Length;i++){
                    list[i] = delegates[i] as EventHandler;
                }
            }
            return list;
        }
    }
    class Program {
        static void Main(string[] args) {
            TestIt();
        }
        static void TestIt() {
            Foo foo = new Foo();
            Assert.AreEqual(0, foo.Listeners.Length);
            foo.SomeEvent += new EventHandler(foo_OnSomeEvent_00);
            foo.SomeEvent += new EventHandler(foo_OnSomeEvent_01);
            Assert.AreEqual(2, foo.Listeners.Length);
            foo.RemoveListener(1);
            Assert.AreEqual(1, foo.Listeners.Length);
        }
        static void foo_OnSomeEvent_00(object sender, EventArgs e) { }
        static void foo_OnSomeEvent_01(object sender, EventArgs e) { }
    }
}

Автор: vponomarov 17.3.2008, 11:11
Ctrl, сорри за глупый вопрос, но почему нельзя вызвать GetInvocationList из класса формы для какого-нить события (например, MouseDown)?

Автор: Ctrl 17.3.2008, 22:27
Вопрос не глупый, на самом деле в данной ситуации есть одна засада:
Вот кусок кода:
Код

   public class Foo {
   // ... something
        public event EventHandler SomeEvent;
   // ... something
}

А вот как он выглядит в IL:
Код

.class public auto ansi beforefieldinit TestOwnEventManagement.Foo
       extends [mscorlib]System.Object
{
   // ... something

    .field private class [mscorlib]System.EventHandler SomeEvent

    .event [mscorlib]System.EventHandler SomeEvent
    {
      .addon instance void TestOwnEventManagement.Foo::add_SomeEvent(class [mscorlib]System.EventHandler)
      .removeon instance void TestOwnEventManagement.Foo::remove_SomeEvent(class [mscorlib]System.EventHandler)
    } // end of event Foo::SomeEvent

   // ... something

} // end of class TestOwnEventManagement.Foo


Компилятор завернул все что надо в поле, которое поддерживает только 2 операции (+=  -= ), и на любое действие со стороны он скажет следующее:
Код

The event 'TestOwnEventManagement.Foo.SomeEvent' can only appear on the left hand side of += or -= 
(except when used from within the type 'TestOwnEventManagement.Foo')

и будет прав  smile

Добавлено через 1 минуту и 23 секунды
Так что, как я писал выше простых решений тут нет

Автор: RedsAn 18.3.2008, 15:27
Спасибо Ctrl!
Показательный пример.
Только для тестирования надо атрибуты указать: [TestFixture] для Program и [Test] для TestIt()
 + сделать этот метод экземплярным. 

Автор: Ctrl 18.3.2008, 19:57
2RedsAn: с этими аттрибутами и с техникой юнит-тестирования я отлично знаком...
Ну на самом деле целью было просто попользовать Assert, дабы не возникали при взгляде на код лишние вопросы
 "ЭЭЭЭЭ ... а как это работает?" 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)