C# динамическая подписка события

  1. Лучшая практика - связывать события, используя JavaScript, а не в вашем HTML.
  2. Вы уже назначаете событие, когда звоните jQuery.on.
  3. Выполнение onchange="this.form.submit() приведет к перезагрузке, отправка формы об изменении приведет к отправке текущей страницы. Вы должны следовать наилучшей практике, а также назначить событие submit в своей форме, используя jQuery $form.on('submit', cb) или лучше vanillaJS form.addEventListener('submit', cb, false).
  4. Вы используете неправильный event из ready вместо on.
  5. Не используйте id, кроме как на вашем <form />, если вы не хотите начинать с ограничения его присутствия 1 на страницу по странным причинам.
  6. jQuery устарел, вы должны удалить его в новых проектах. Селекторы теперь существуют в современных браузерах, и их анимация использует слишком много JavaScript и не использует CSS3.

$(document).ready(function () {
  $("[name='value']").on('change', function (e) {
    e.preventDefault();
    $.ajax({
      type: "GET",
      url: "localhost:1234/",
      crossDomain: true,
      dataType: "json",
      data: $("#rati").serialize(),
    });
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="get" id="rati">
  <select name="value">
    <option value="default" selected="selected"></option>
    <option value="Authors">Authors</option>
    <option value="Papers">Papers</option>
    <option value="countries">Countries</option>
    <option value="Organisations">Organisations</option>
  </select>
</form>

31
задан DAC 5 September 2008 в 14:38
поделиться

8 ответов

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

 using System;
 using System.Linq;
 using System.Linq.Expressions;
 using System.Reflection;

 class ExampleEventArgs : EventArgs
 {
    public int IntArg {get; set;}
 }

 class EventRaiser
 { 
     public event EventHandler SomethingHappened;
     public event EventHandler<ExampleEventArgs> SomethingHappenedWithArg;

     public void RaiseEvents()
     {
         if (SomethingHappened!=null) SomethingHappened(this, EventArgs.Empty);

         if (SomethingHappenedWithArg!=null) 
         {
            SomethingHappenedWithArg(this, new ExampleEventArgs{IntArg = 5});
         }
     }
 }

 class Handler
 { 
     public void HandleEvent() { Console.WriteLine("Handler.HandleEvent() called.");}
     public void HandleEventWithArg(int arg) { Console.WriteLine("Arg: {0}",arg);    }
 }

 static class EventProxy
 { 
     //void delegates with no parameters
     static public Delegate Create(EventInfo evt, Action d)
     { 
         var handlerType = evt.EventHandlerType;
         var eventParams = handlerType.GetMethod("Invoke").GetParameters();

         //lambda: (object x0, EventArgs x1) => d()
         var parameters = eventParams.Select(p=>Expression.Parameter(p.ParameterType,"x"));
         var body = Expression.Call(Expression.Constant(d),d.GetType().GetMethod("Invoke"));
         var lambda = Expression.Lambda(body,parameters.ToArray());
         return Delegate.CreateDelegate(handlerType, lambda.Compile(), "Invoke", false);
     }

     //void delegate with one parameter
     static public Delegate Create<T>(EventInfo evt, Action<T> d)
     {
         var handlerType = evt.EventHandlerType;
         var eventParams = handlerType.GetMethod("Invoke").GetParameters();

         //lambda: (object x0, ExampleEventArgs x1) => d(x1.IntArg)
         var parameters = eventParams.Select(p=>Expression.Parameter(p.ParameterType,"x")).ToArray();
         var arg    = getArgExpression(parameters[1], typeof(T));
         var body   = Expression.Call(Expression.Constant(d),d.GetType().GetMethod("Invoke"), arg);
         var lambda = Expression.Lambda(body,parameters);
         return Delegate.CreateDelegate(handlerType, lambda.Compile(), "Invoke", false);
     }

     //returns an expression that represents an argument to be passed to the delegate
     static Expression getArgExpression(ParameterExpression eventArgs, Type handlerArgType)
     {
        if (eventArgs.Type==typeof(ExampleEventArgs) && handlerArgType==typeof(int))
        {
           //"x1.IntArg"
           var memberInfo = eventArgs.Type.GetMember("IntArg")[0];
           return Expression.MakeMemberAccess(eventArgs,memberInfo);
        }

        throw new NotSupportedException(eventArgs+"->"+handlerArgType);
     }
 }


 static class Test
 {
     public static void Main()
     { 
        var raiser  = new EventRaiser();
        var handler = new Handler();

        //void delegate with no parameters
        string eventName = "SomethingHappened";
        var eventinfo = raiser.GetType().GetEvent(eventName);
        eventinfo.AddEventHandler(raiser,EventProxy.Create(eventinfo,handler.HandleEvent));

        //void delegate with one parameter
        string eventName2 = "SomethingHappenedWithArg";
        var eventInfo2 = raiser.GetType().GetEvent(eventName2);
        eventInfo2.AddEventHandler(raiser,EventProxy.Create<int>(eventInfo2,handler.HandleEventWithArg));

        //or even just:
        eventinfo.AddEventHandler(raiser,EventProxy.Create(eventinfo,()=>Console.WriteLine("!")));  
        eventInfo2.AddEventHandler(raiser,EventProxy.Create<int>(eventInfo2,i=>Console.WriteLine(i+"!")));

        raiser.RaiseEvents();
     }
 }
28
ответ дан 27 November 2019 в 22:32
поделиться

Возможно подписаться на событие с помощью Отражения

var o = new SomeObjectWithEvent;
o.GetType().GetEvent("SomeEvent").AddEventHandler(...);

, http://msdn.microsoft.com/en-us/library/system.reflection.eventinfo.addeventhandler.aspx

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

Hope это помогает.

3
ответ дан 27 November 2019 в 22:32
поделиться

Это не абсолютно общее решение, но если все Ваши события имеют форму, пустую Foo (возразите o, T args), где T происходит из EventArgs, затем можно использовать контравариантность делегата, чтобы выйти сухим из воды. Как это (где подпись KeyDown не является тем же как подписью Щелчка):

    public Form1()
    {
        Button b = new Button();
        TextBox tb = new TextBox();

        this.Controls.Add(b);
        this.Controls.Add(tb);
        WireUp(b, "Click", "Clickbutton");
        WireUp(tb, "KeyDown", "Clickbutton");
    }

    void WireUp(object o, string eventname, string methodname)
    {
        EventInfo ei = o.GetType().GetEvent(eventname);

        MethodInfo mi = this.GetType().GetMethod(methodname, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);

        Delegate del = Delegate.CreateDelegate(ei.EventHandlerType, this, mi);

        ei.AddEventHandler(o, del);

    }
    void Clickbutton(object sender, System.EventArgs e)
    {
        MessageBox.Show("hello!");
    }
8
ответ дан 27 November 2019 в 22:32
поделиться
public TestForm()
{
    Button b = new Button();

    this.Controls.Add(b);

    MethodInfo method = typeof(TestForm).GetMethod("Clickbutton",
    BindingFlags.NonPublic | BindingFlags.Instance);
    Type type = typeof(EventHandler);

    Delegate handler = Delegate.CreateDelegate(type, this, method);

    EventInfo eventInfo = cbo.GetType().GetEvent("Click");

    eventInfo.AddEventHandler(b, handler);

}

void Clickbutton(object sender, System.EventArgs e)
{
    // Code here
}
2
ответ дан 27 November 2019 в 22:32
поделиться

То, что Вы хотите, может быть достигнуто с помощью внедрения зависимости. Например блок приложений Microsoft Composite UI делает точно, что Вы описали

0
ответ дан 27 November 2019 в 22:32
поделиться

Сделайте Вы имеете в виду что-то как:

//reflect out the method to fire as a delegate
EventHandler eventDelegate = 
   ( EventHandler ) Delegate.CreateDelegate(
       typeof( EventHandler ),    //type of event delegate
       objectWithEventSubscriber, //instance of the object with the matching method
       eventSubscriberMethodName, //the name of the method
       true );

Это не делает подписки, но даст методу для вызова.

Редактирование:

Сообщение было разъяснено после этого ответа мой пример не поможет, если Вы не будете знать тип.

Однако все события в .NET должны следовать за шаблоном стандартного события, поэтому, пока Вы следовали за ним, это будет работать с основным EventHandler.

-1
ответ дан 27 November 2019 в 22:32
поделиться

Попробуйте LinFu - он имеет универсальный обработчик событий, который позволяет Вам связать с любым событием во времени выполнения. Например, вот Вы, можно связать обработчик с событием Click динамической кнопки:

// Note: The CustomDelegate signature is defined as:
// public delegate object CustomDelegate(params object[] args);
CustomDelegate handler = delegate
                         {
                           Console.WriteLine("Button Clicked!");
                           return null;
                         };

Button myButton = new Button();
// Connect the handler to the event
EventBinder.BindToEvent("Click", myButton, handler);

LinFu позволяет Вам связать свои обработчики с любым событием, независимо от подписи делегата.Приятного отдыха!

можно найти его здесь: http://www.codeproject.com/KB/cs/LinFuPart3.aspx

2
ответ дан 27 November 2019 в 22:32
поделиться

Недавно я написал серию сообщений в блоге, описывающих события модульного тестирования, и один из обсуждаемых мной методов описывает динамическую подписку на события. Я использовал отражение и MSIL (испускание кода) для динамических аспектов, но все это красиво обернуто. Используя класс DynamicEvent, события могут быть подписаны динамически следующим образом:

EventPublisher publisher = new EventPublisher();

foreach (EventInfo eventInfo in publisher.GetType().GetEvents())
{
    DynamicEvent.Subscribe(eventInfo, publisher, (sender, e, eventName) =>
    {
        Console.WriteLine("Event raised: " + eventName);
    });
}

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

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

http://gojisoft.com/blog/2010/04/22/event-sequence-unit-testing-part-1/

1
ответ дан 27 November 2019 в 22:32
поделиться
Другие вопросы по тегам:

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