Метод EventTarget.removeEventListener()
Удаляет обработчик события, который был зарегистрирован при помощи EventTarget.addEventListener() . Обработчик определяется типом события, самой функцией обработки события, и дополнительными параметрами, переданными при регистрации обработчика.
Синтаксис
target.removeEventListener(type, listener[, options]); target.removeEventListener(type, listener[, useCapture]);
Параметры
Строка, описывающая тип события, которое нужно удалить.
EventListener функция, которую нужно удалить с элемента.
Объект опций, описывающий характеристики обработчика события. Доступные опции:
- capture : Boolean . Указывает на то, что события этого типа отправляются данному обработчику до того, как происходит их передача любым EventTarget , находящимся ниже него в дереве DOM.
- passive : Boolean . Указывает на то, что listener никогда не будет вызывать preventDefault() . В противном случае (если listener вызовет preventDefault() ), user agent проигнорирует вызов и сгенерирует предупреждение в консоли.
Указывает, был ли удаляемый EventListener зарегистрирован как перехватывающий обработчик, или нет. Если этот параметр отсутствует, предполагается значение по умолчанию: false .
Если обработчик был зарегистрирован дважды, один раз с перехватом (с capture ) и один — без, каждый из них должен быть удалён по отдельности. Удаление перехватывающего обработчика никак не затрагивает неперехватывающую версию этого же обработчика, и наоборот.
Примечание: useCapture требуется в большинстве основных браузеров старых версий. Если вы хотите поддерживать большую совместимость, вы всегда должны использовать параметр useCapture .
Возвращаемое значение
Поиск обработчика при удалении
В большинстве браузеров помимо типа события и функции важно лишь совпадение значений параметра useCapture / options.capture , но так как это поведение не закреплено стандартом, наилучшим способом будет указание для removeEventListener() в точности тех же параметров, что были переданы в addEventListener() .
Примечания
Если EventListener был удалён из EventTarget в процессе обработки события (например предшествующим EventListener того же типа), он не будет вызван. После удаления, EventListener не будет вызываться, однако его можно назначить заново.
Вызов removeEventListener() с параметрами, не соответствующими ни одному зарегистрированному EventListener в EventTarget , не имеет никакого эффекта.
Пример
Это пример добавления и последующего удаления обработчика событий.
var div = document.getElementById("div"); var listener = function (event) /* do something here */ >; div.addEventListener("click", listener, false); div.removeEventListener("click", listener, false);
Совместимость с браузерами
BCD tables only load in the browser
Gecko примечания
- В версиях Firefox младше версии 6 браузер бросает исключение, если параметр useCapture не был явно указан как false. В Gecko младше 9.0, addEventListener() бросает исключение, если параметр listener равен null ; в настоящее время метод отрабатывает без ошибки, но при этом не производит никаких действий.
Opera примечания
- В Opera 12.00 параметр useCapture — опциональный (source).
WebKit примечания
- Несмотря на то, что WebKit явно добавил » [optional] » к параметру useCapture в Safari 5.1 и Chrome 13, это работало и до изменений.
Спецификация
Полифилы для поддержки старых браузеров
addEventListener() и removeEventListener() отсутствуют в старых браузерах. Это ограничение можно обойти, вставив следующий код в начале ваших скриптов, что позволяет использовать addEventListener() и removeEventListener() в версиях, не поддерживающих эти методы нативно. Тем не менее, этот метод не работает в Internet Explorer версии 7 и ниже, так как расширение Element.prototype не поддерживалось в более ранних версиях Internet Explorer ранее 8.
if (!Element.prototype.addEventListener) var oListeners = >; function runListeners(oEvent) if (!oEvent) oEvent = window.event; > for ( var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId oEvtListeners.aEls.length; iElId++ ) if (oEvtListeners.aEls[iElId] === this) for (iLstId; iLstId oEvtListeners.aEvts[iElId].length; iLstId++) oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); > break; > > > Element.prototype.addEventListener = function ( sEventType, fListener /*, useCapture (will be ignored!) */, ) if (oListeners.hasOwnProperty(sEventType)) var oEvtListeners = oListeners[sEventType]; for ( var nElIdx = -1, iElId = 0; iElId oEvtListeners.aEls.length; iElId++ ) if (oEvtListeners.aEls[iElId] === this) nElIdx = iElId; break; > > if (nElIdx === -1) oEvtListeners.aEls.push(this); oEvtListeners.aEvts.push([fListener]); this["on" + sEventType] = runListeners; > else var aElListeners = oEvtListeners.aEvts[nElIdx]; if (this["on" + sEventType] !== runListeners) aElListeners.splice(0); this["on" + sEventType] = runListeners; > for (var iLstId = 0; iLstId aElListeners.length; iLstId++) if (aElListeners[iLstId] === fListener) return; > > aElListeners.push(fListener); > > else oListeners[sEventType] = aEls: [this], aEvts: [[fListener]] >; this["on" + sEventType] = runListeners; > >; Element.prototype.removeEventListener = function ( sEventType, fListener /*, useCapture (will be ignored!) */, ) if (!oListeners.hasOwnProperty(sEventType)) return; > var oEvtListeners = oListeners[sEventType]; for ( var nElIdx = -1, iElId = 0; iElId oEvtListeners.aEls.length; iElId++ ) if (oEvtListeners.aEls[iElId] === this) nElIdx = iElId; break; > > if (nElIdx === -1) return; > for ( var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId aElListeners.length; iLstId++ ) if (aElListeners[iLstId] === fListener) aElListeners.splice(iLstId, 1); > > >; >
Смотрите также
- EventTarget.addEventListener() .
- Non-standard EventTarget.detachEvent() (en-US).
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 6 янв. 2024 г. by MDN contributors.
Руководство по программированию на C#. Подписка и отмена подписки на события
Необходимость подписки на событие, опубликованное другим классом, может возникнуть, когда требуется написать пользовательский код, вызываемый при инициировании такого события. Например, можно подписаться на событие кнопки click , чтобы приложение выполняло некоторое действие при нажатии пользователем кнопки.
Подписка на события в интегрированной среде разработки Visual Studio
- Если окно Свойства закрыто, в представлении Конструктор щелкните правой кнопкой мыши форму или элемент управления, для которого требуется создать обработчик событий, и выберите пункт Свойства.
- Вверху окна Свойства щелкните значок События.
- Дважды щелкните событие, которое требуется создать, например событие Load . Visual C# создаст пустой метод обработчика событий и добавит его в код. Код можно также добавить вручную в представлении Код. Например, приведенные ниже строки кода объявляют метод обработчика событий, который будет выполнен при вызове классом Form события Load .
private void Form1_Load(object sender, System.EventArgs e) < // Add your form load event handling code here. >
Строка кода, требуемая для подписки на событие, также создается автоматически в методе InitializeComponent в файле Form1.Designer.cs проекта. Она имеет следующий вид:
this.Load += new System.EventHandler(this.Form1_Load);
Подписка на события программными средствами
- Определите метод обработчика событий, сигнатура которого соответствует сигнатуре делегата для события. Например, если событие основано на типе делегата EventHandler, то следующий код представляет заглушку метода:
void HandleCustomEvent(object sender, CustomEventArgs a) < // Do something useful here. >
publisher.RaiseCustomEvent += HandleCustomEvent;
Чтобы указать обработчик событий, можно также воспользоваться лямбда-выражением:
public Form1() < InitializeComponent(); this.Click += (s,e) =>< MessageBox.Show(((MouseEventArgs)e).Location.ToString()); >; >
Подписка на события с помощью анонимной функции
Если вам не нужно будет позже отменять подписку на событие, можно использовать оператор присваивания сложения ( += ) для привязки анонимной функции как обработчика событий. В следующем примере предположим, что объект с именем publisher имеет событие с именем RaiseCustomEvent и что класс CustomEventArgs также был определен и содержит некие относящиеся к событию сведения. Обратите внимание на то, что классу подписчика требуется ссылка на publisher , чтобы подписаться на его события.
publisher.RaiseCustomEvent += (object o, CustomEventArgs e) => < string s = o.ToString() + " " + e.ToString(); Console.WriteLine(s); >;
Отменить подписку на событие не так просто, если для подписки использовалась анонимная функция. Чтобы отменить подписку в этом случае, в коде, где была выполнена подписка на событие, сохраните анонимную функцию в переменной делегата, а затем добавьте делегат к событию. Мы рекомендуем не использовать анонимные функции для подписки на события, если в будущем вам нужно будет отменить подписку. Дополнительные сведения об анонимных функциях см. в статье Лямбда-выражения.
Отмена подписки
Чтобы предотвратить вызов обработчика событий при инициировании события, подписку на событие необходимо отменить. Во избежание утечки ресурсов отменять подписку на события следует до удаления объекта подписчика. До тех пор пока подписка на событие не отменена, делегат многоадресной рассылки, лежащий в основе события в публикующем объекте, будет ссылаться на делегат, инкапсулирующий обработчик событий подписчика. Если ссылка присутствует в публикующем объекте, объект подписчика не будет удален при сборке мусора.
Отмена подписки на событие
- Чтобы отменить подписку на событие, воспользуйтесь оператором присваивания вычитания ( -= ).
publisher.RaiseCustomEvent -= HandleCustomEvent;
См. также
- События
- event
- Практическое руководство. Публикация событий, соответствующих рекомендациям .NET
- Операторы — и -=
- Операторы + и +=
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
События! Как грамотно подписаться/отписаться?
У меня возникли воросы на который я, к сожалению, не нашел однозначного ответа. Есть два класса A , B . У класса B есть public ObservableCollection , у которого есть событие CollectionChanged . Я подисываюсь на данное событие из класса A и B .
B.ObservableCollection.CollectionChanged += Hello; this.ObservableCollection.CollectionChanged += Hello1;
- Как грамотно отписать всех подписок в классе A от события?
- Как грамотно отписать всех подписок в классе B от события?
- Почему считается плохим тоном отписываться так: CollectionChanged = null ? Что произойдет?
Отслеживать
задан 7 июл 2018 в 2:50
299 2 2 серебряных знака 10 10 бронзовых знаков
3. Это разве сработает?
7 июл 2018 в 6:55
@АндрейNOP Я незнаю, потому и спрашиваю, что произойдет. 🙂 Я пологаю John дал ответ на это.
7 июл 2018 в 9:22
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Если ссылок на объект к которому мы подписались больше нет, то объект будет собран сборщиком мусора => отписка произойдет автоматически=> беспокоится в этом случае не нужно.
Однако, если у вас долгоживущие объекты и в определенным периоды вы хотите слушать, а в какие-то нет, то отписывайтесь явно.
Отслеживать
ответ дан 7 июл 2018 в 5:38
24.8k 12 12 золотых знаков 64 64 серебряных знака 163 163 бронзовых знака
Это точно? Подписчик не хранит ссылку на объект?
7 июл 2018 в 6:55
Я думаю, что да. А зачем подписчику хранить ссылку на издателя? Издатель хранит адреса функций, которые должен вызвать при наступлении события.
7 июл 2018 в 7:05
Ну да, согласен, там связь обратная, тот кто предоставляет события, хранит ссылки на подписчиков (точнее делегат хранит ссылку на класс, в котором он определен)
7 июл 2018 в 7:09
Для начала нужно чётко понимать, как работают события и делегаты. Когда вы подписываетесь, то передаёте событию делегат на метод, который он будет впоследствии вызывать. То есть связь однонаправленная classA -> eventA -> delegateB -> сlassB и в результате из класса B мы не можем знать, подписано что-то на него или нет.
1) Для подписки/отписки от события между разными экземплярам классов есть множество путей и у каждого свои плюсы и минусы. Вот почитайте про события подробнее. Расписывать здесь не вижу смысла, но прочитать эту статью рекомендую.
2) Если происходит подписка метода на событие одного экземпляра класса, то отписывать не нужно. Так как в результате у вас событие будет вести на тот же класс и сборщик мусора, если не имеется других ссылок на этот класс, удалит его.
3) От события можно отписывать сразу всех через присвоение null, проблема лишь в том, что это возможно только из класса, которому это событие принадлежит. Для всех других классов доступно лишь два метода Add и Remove, то есть подписка (добавления делегата) и отписка (удаление делегата). В вашем случае у вас присвоить null не получится, так как CollectionChanged принадлежит ObservableCollection, к которому изнутри у вас нет доступа.
Можно ли как-то отписать всех от события? C#
В C# нет прямого способа отписать всех подписчиков от события с помощью синтаксиса типа `Method -= MyAction;`. Однако, существует несколько способов, как можно отписать всех подписчиков от события:
1. Создание нового экземпляра события: Один из способов отписать всех подписчиков от события — создать новый экземпляр события. Это можно сделать путем создания нового экземпляра делегата для события. Например:
«`csharp
event Action MyEvent = null;
«`
При этом все предыдущие подписки на событие `MyEvent` будут потеряны, и новые подписчики должны будут заново подписаться на событие.
2. Использование рефлексии: Другой способ — использовать рефлексию для получения списка подписчиков и удаления каждого из них вручную. Это более сложный и не рекомендуемый подход, так как рефлексия может быть медленной и неэффективной во время выполнения.
«`csharp
// Получение информации о событии с помощью рефлексии
EventInfo eventInfo = typeof(YourClass).GetEvent(«MyEvent»);
// Получение текущих подписчиков события
Delegate[] subscribers = eventInfo.GetInvocationList();
// Отписка от события для каждого подписчика
foreach (Delegate subscriber in subscribers)
eventInfo.RemoveEventHandler(this, subscriber);
>
«`
Обратите внимание, что использование рефлексии может быть сложным и подвержено ошибкам, поэтому не рекомендуется применять его в обычных сценариях.