Каков правильный способ удаления onclick listener [duplicate]

Ваш код разбит на две полностью отдельные части, серверную сторону и клиентскую сторону .

                    |
               ---------->
              HTTP request
                    |
+--------------+    |    +--------------+
|              |    |    |              |
|    browser   |    |    |  web  server |
| (JavaScript) |    |    |  (PHP etc.)  |
|              |    |    |              |
+--------------+    |    +--------------+
                    |
  client side       |      server side
                    |
               <----------
          HTML, CSS, JavaScript
                    |

Обе стороны общаются через HTTP-запросы и ответы. PHP выполняется на сервере и выводит код HTML и, возможно, JavaScript, который отправляется как ответ клиенту, где интерпретируется HTML, и выполняется JavaScript. Когда PHP завершит вывод ответа, сценарий закончится, и на сервере ничего не произойдет, пока не появится новый HTTP-запрос.

Пример кода выполняется следующим образом:


Шаг 1, PHP выполняет весь код между тегами . В результате получилось следующее:


Вызов file_put_contents не привел ни к чему, он просто написал «+ foo +» в файл. Вызов привел к выводу «42», который теперь находится в том месте, где этот код использовался.

Этот итоговый код HTML / JavaScript теперь отправляется клиенту, где он получает оценку , Вызов alert работает, а переменная foo нигде не используется.

Весь PHP-код выполняется на сервере до того, как клиент даже начнет выполнение какого-либо JavaScript. В ответе JavaScript, с которым может взаимодействовать JavaScript, нет кода PHP.

Чтобы вызвать некоторый код PHP, клиент должен будет отправить новый HTTP-запрос на сервер. Это может произойти с использованием одного из трех возможных способов:

  1. Ссылка, которая заставляет браузер загружать новую страницу.
  2. Подача формы, которая передает данные на сервер и загружает новую страницу.
  3. Запрос AJAX , который является техникой Javascript, чтобы сделать обычный HTTP-запрос на сервер (например, 1. и 2. будет), но без оставляя текущую страницу.

Вот более подробный изложение этого метода

Вы также можете использовать JavaScript, чтобы браузер открыл новую страницу с помощью window.location или отправить форму, подражая возможностям 1 и 2.

194
задан Eric 8 October 2008 в 16:24
поделиться

11 ответов

Action myDelegate = delegate(){Console.WriteLine("I did it!");};

MyEvent += myDelegate;


// .... later

MyEvent -= myDelegate;

Просто держите ссылку на делегата.

200
ответ дан Jacob Krall 24 August 2018 в 22:01
поделиться

Вид ламельного подхода:

public class SomeClass
{
  private readonly IList<Action> _eventList = new List<Action>();

  ...

  public event Action OnDoSomething
  {
    add {
      _eventList.Add(value);
    }
    remove {
      _eventList.Remove(value);
    }
  }
}
  1. Переопределить методы добавления / удаления события.
  2. Хранить список этих обработчиков событий.
  3. При необходимости очистите их все и повторно добавьте другие.

Это может не работать или быть наиболее эффективным методом, но должно выполняться.

6
ответ дан casademora 24 August 2018 в 22:01
поделиться
  • 1
    Если вы считаете, что это хромой, не публикуйте его. – Jerry Nixon - MSFT 4 March 2011 в 16:48

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

2
ответ дан Community 24 August 2018 в 22:01
поделиться

Вместо того, чтобы ссылаться на любого делегата, вы можете задействовать свой класс, чтобы вернуть список вызовов вызывающему абоненту. В основном вы можете написать что-то вроде этого (предполагая, что MyEvent объявлен внутри MyClass):

public class MyClass 
{
  public event EventHandler MyEvent;

  public IEnumerable<EventHandler> GetMyEventHandlers()  
  {  
      return from d in MyEvent.GetInvocationList()  
             select (EventHandler)d;  
  }  
}

Таким образом, вы можете получить доступ ко всему списку вызовов извне MyClass и отменить подписку на любой обработчик, который вы хотите. Например:

myClass.MyEvent -= myClass.GetMyEventHandlers().Last();

Я написал полный пост об этом tecnique здесь .

9
ответ дан hemme 24 August 2018 в 22:01
поделиться
  • 1
    Означает ли это, что я мог случайно отказаться от подписки на другой экземпляр (т. Е. Не меня), если они подписались после меня? – dumbledad 26 March 2014 в 00:53
  • 2
    @dumbledad, конечно, это будет отменять регистрацию последнего зарегистрированного. Если вы хотите динамически отказаться от подписки на определенный анонимный делегат, вам нужно как-то идентифицировать его. Я бы предложил сохранить ссылку тогда :) – LuckyLikey 2 June 2016 в 13:24
  • 3
    Это довольно круто, что вы делаете, но я не могу представить один случай, когда это может быть полезно. Но я действительно решаю вопрос OP. - & GT; +1. ИМХО, следует просто не использовать анонимных делегатов, если они должны быть отменены позже. Сохранение их глупо - & gt; лучше использовать метод. Удаление только некоторых делегатов в списке Invocation довольно беспорядочно и бесполезно. Поправьте меня если я ошибаюсь. :) – LuckyLikey 2 June 2016 в 13:35

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

Пример:

MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
    {
        Console.WriteLine("I did it!");
        MyEvent -= foo;
    };
MyEvent += foo;
136
ответ дан J c 24 August 2018 в 22:01
поделиться
  • 1
    Используя этот тип кода, Resharper жалуется на доступ к модифицированному закрытию ... этот подход надежный? Я имею в виду, уверены ли мы, что переменная 'foo' внутри тела анонимного метода действительно ссылается на анонимный метод? – BladeWise 28 July 2010 в 16:13
  • 2
    Я нашел ответ на мой дубт, и именно «foo» действительно будет ссылаться на анонимный метод itslef. Захваченная переменная изменяется, так как она захватывается до того, как анонимный метод получит ее. – BladeWise 29 July 2010 в 08:23
  • 3
    Это именно то, что мне нужно! Я отсутствовал = null. (MyEventHandler foo = delegate {... MyEvent- = foo;}; MyEvent + = foo; не работает ...) – TDaver 21 February 2011 в 11:33
  • 4
    Resharper 6.1 не жалуется, если вы объявляете его как массив. Кажется немного странным, но я буду слепо доверять своим инструментам на этом: MyEventHandler [] foo = {null}; foo [0] = ... {... MyEvent - = foo [0]; }; MyEvent + = foo [0]; – Mike Post 14 March 2012 в 05:06
  • 5
    этот поток безопасен? – LuckyLikey 2 June 2016 в 13:20

Из памяти спецификация явно не гарантирует поведение в любом случае, когда дело доходит до эквивалентности делегатов, созданных с помощью анонимных методов.

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

17
ответ дан Jon Skeet 24 August 2018 в 22:01
поделиться
  • 1
    Я, Джон, что ты меришь? Я не понимаю. решение, разоблаченное буквой «J c», не будет работать должным образом? – Eric Ouellet 17 October 2012 в 14:33
  • 2
    @EricOuellet: Этот ответ в основном представляет собой реализацию «сохранить делегат где-то в другом месте, чтобы вы могли отказаться от подписки с точно таким же делегатом, которого вы использовали для подписки». – Jon Skeet 17 October 2012 в 14:38
  • 3
    Джон, извините, я много раз читал ваш ответ, пытаясь понять, что вы имеете в виду, и где «J c» решение не использует один и тот же делегат для подписки и отмены подписки, но я не могу его подделать. Pehaps вы можете указать мне на статью, которая объясняет, что вы говорите? Я знаю о вашей репутации, и мне очень хотелось бы понять, что вы имеете в виду, все, что вы можете связать, было бы действительно оценено. – Eric Ouellet 18 October 2012 в 13:59
  • 4
    Я нашел: msdn.microsoft.com/en-us/library/ms366768.aspx , но они рекомендуют не использовать анонимный, но они не говорят, что есть какая-то серьезная проблема? – Eric Ouellet 18 October 2012 в 14:02
  • 5
    Я нашел его ... Большое спасибо (см. Ответ Майкла Блума): social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/… – Eric Ouellet 18 October 2012 в 14:11

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

В этом примере я должен использовать анонимный метод для включения параметра mergeColumn для набор DataGridViews.

Использование метода MergeColumn с параметром enable, установленным в true, позволяет событию при его использовании с false отключает его.

static Dictionary<DataGridView, PaintEventHandler> subscriptions = new Dictionary<DataGridView, PaintEventHandler>();

public static void MergeColumns(this DataGridView dg, bool enable, params ColumnGroup[] mergedColumns) {

    if(enable) {
        subscriptions[dg] = (s, e) => Dg_Paint(s, e, mergedColumns);
        dg.Paint += subscriptions[dg];
    }
    else {
        if(subscriptions.ContainsKey(dg)) {
            dg.Paint -= subscriptions[dg];
            subscriptions.Remove(dg);
        }
    }
}
0
ответ дан Larry 24 August 2018 в 22:01
поделиться

Одно простое решение:

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

MyEventHandler foo = null;
foo = (s, ev, mehi) => MyMethod(s, ev, foo);
MyEvent += foo;

void MyMethod(object s, MyEventArgs ev, MyEventHandler myEventHandlerInstance)
{
    MyEvent -= myEventHandlerInstance;
    Console.WriteLine("I did it!");
}
1
ответ дан Manuel Marhold 24 August 2018 в 22:01
поделиться
  • 1
    что, если MyEvent вызывается дважды, до запуска MyEvent -= myEventHandlerInstance;? Если это возможно, у вас будет ошибка. Но я не уверен, что так. – LuckyLikey 2 June 2016 в 13:27

Поскольку функция C # 7.0 локальных функций была выпущена, подход , предложенный в J c , становится действительно опрятным.

void foo(object s, MyEventArgs ev)
{
    Console.WriteLine("I did it!");
    MyEvent -= foo;
};
MyEvent += foo;

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

3
ответ дан mazharenko 24 August 2018 в 22:01
поделиться

В версии 3.0 можно сократить до:

MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
17
ответ дан user 24 August 2018 в 22:01
поделиться

, если вы хотите обратиться к некоторому объекту с этим делегатом, возможно, вы можете использовать Delegate.CreateDelegate (Тип, Объект target, MethodInfo methodInfo) .net считать, что делегат равен target и methodInfo

0
ответ дан user3217549 24 August 2018 в 22:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: