ASP.Net Пользовательский серверный элемент управления не запускает пользовательское событие

#c# #event-handling #custom-server-controls

#c# #обработка событий #пользовательские серверные элементы управления

Вопрос:

Я создал пользовательский серверный элемент управления. Это выглядит великолепно, и отображаемый HTML также соответствует тому, каким он должен быть. Изначально он расширял ControlContainer, а теперь он расширяет WebControl (оба ведут себя одинаково.) Он имеет два свойства, ImageUrl и Text. По сути, он будет отображать общий HTML-тег с тегами и внутри него.

Моя проблема в том, что событие ServerClick, которое отображается (с помощью NamingContainer, которому я верю), похоже, не срабатывает. Если я добавлю любую из кнопок ASP (ссылку, изображение или обычную) и свяжусь с этим событием Click, оно сработает, но, конечно, у меня есть дополнительный отображаемый контент. Он успешно запускает javascript и выполняет обратный вызов __dopostback. Но он не должен видеть указанный идентификатор элемента управления или что-то в этом роде, потому что событие никогда не запускается.

 using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace PLSO.Info.Web.UI {

[DefaultEvent("Submit")]
[DefaultProperty("Text")]
[ToolboxData("<{0}:ComboButton runat="server"> </{0}:ComboButton>")]
public class ComboButton : WebControl {

    private HtmlImage imageControl;
    private HtmlGenericControl spanControl;

    private static readonly object EventSubmitKey = new object();

    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Description("The text to display on the button.")]
    public string Text {
        get { return ViewState["NewText"] as string; }
        set { ViewState["NewText"] = value; }
    }

    [DefaultValue("")]
    [Bindable(true)]
    [Category("Appearance")]
    [UrlProperty()]
    [Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
    public string ImageUrl {
        get {
            EnsureChildControls();
            return this.imageControl.Src;
        }
        set {
            EnsureChildControls();
            this.imageControl.Src = value;
        }
    } // ImageUrl - Property

    public override string CssClass {
        get { return ViewState["CssClass"] as string; }
        set { ViewState["CssClass"] = value; }
    }

    [Category("Action")]
    [Description("Raised when the user clicks the button.")]
    public event EventHandler Submit {
        add { Events.AddHandler(EventSubmitKey, value); }
        remove { Events.RemoveHandler(EventSubmitKey, value); }
    }

    protected virtual void OnSubmit(EventArgs e) {
        EventHandler SubmitHandler = (EventHandler)Events[EventSubmitKey];

        if (SubmitHandler != null)
            SubmitHandler(this, e);
    }

    void ComboButton_Submit(object sender, EventArgs e) {
        OnSubmit(EventArgs.Empty);
    }

    protected override void CreateChildControls() {
        Controls.Clear();

        imageControl = new HtmlImage();
        imageControl.Src = this.ImageUrl;
        imageControl.Alt = this.Text;
        this.Controls.Add(imageControl);

        spanControl = new HtmlGenericControl("span");
        spanControl.InnerText = this.Text;
        this.Controls.Add(spanControl);

        this.Submit  = new EventHandler(ComboButton_Submit);

        ChildControlsCreated = true;
    }

    protected override void Render(HtmlTextWriter writer) {
        PostBackOptions pbo = new PostBackOptions(this);

        AddAttributesToRender(writer);
        writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);
        writer.AddAttribute("onclick", string.Format("javascript:{0}", Page.ClientScript.GetPostBackEventReference(pbo)));
        writer.RenderBeginTag(HtmlTextWriterTag.Button);
        imageControl.RenderControl(writer);
        spanControl.RenderControl(writer);
        writer.RenderEndTag();
    }
    }
}
  

Вот моя разметка. Я ввел этот элемент управления, а затем обычную ASP: Button. Попадает событие этой обычной кнопки! Не мое.

 <ucs:ComboButton ID="btnT4" runat="server" Text="Please" CssClass="PButtonCombo" ImageUrl="~/Styles/icons/edit-find.png" OnSubmit="btnT4_Submit" />
<asp:Button ID="btnT5" runat="server" Text="TEST" onclick="btnT5_Click" UseSubmitBehavior="False" />
  

И вот отрисованный HTML:

 <button id="MainContent_btnT4" class="PButtonCombo" onclick="javascript:__doPostBack(amp;#39;ctl00$MainContent$btnT4amp;#39;,amp;#39;amp;#39;)"><img src="../Styles/icons/edit-find.png" alt="Please" /><span>Please</span></button>
<input type="button" name="ctl00$MainContent$btnT5" value="TEST" onclick="javascript:__doPostBack(amp;#39;ctl00$MainContent$btnT5amp;#39;,amp;#39;amp;#39;)" id="MainContent_btnT5" />
  

Я должен верить, что я близок, но просто чего-то не хватает. Настраивал его в течение нескольких часов сегодня, ПОЖАЛУЙСТА, ПОМОГИТЕ!

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

Благодаря @James answer все, что я сделал, это добавил следующее в начало приведенного выше примера. Это сработало, но теперь срабатывает дважды. Не уверен, почему? Итак, это мой текущий вопрос:

 public class ComboButton : WebControl, IPostBackEventHandler {

    public void RaisePostBackEvent(string eventArgument) {
        OnClick(new EventArgs());
    }

    [Category("Action")]
    [Description("Raised when the user clicks the button.")]
    public event EventHandler Click;

    protected virtual void OnClick(EventArgs e) {
        if (Click != null)
            Click(this, e);
    }
  

РЕДАКТИРОВАТЬ 2 == РЕШЕНИЕ

 using System.ComponentModel;
using System.Drawing.Design;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace PLSO.Info.Web.UI {

[DefaultEvent("Submit")]
[DefaultProperty("Text")]
[ToolboxData("<{0}:ComboButton runat="server"> </{0}:ComboButton>")]
public class ComboButton : Button {

    private HtmlImage imageControl;
    private HtmlGenericControl spanControl;

    [DefaultValue("")]
    [Bindable(true)]
    [Category("Appearance")]
    [UrlProperty()]
    [Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
    public string ImageUrl {
        get {
            EnsureChildControls();
            return this.imageControl.Src;
        }
        set {
            EnsureChildControls();
            this.imageControl.Src = value;
        }
    } // ImageUrl - Property

    protected override void CreateChildControls() {
        Controls.Clear();

        imageControl = new HtmlImage();
        imageControl.Src = this.ImageUrl;
        imageControl.Alt = this.Text;
        this.Controls.Add(imageControl);

        spanControl = new HtmlGenericControl("span");
        spanControl.InnerText = this.Text;
        this.Controls.Add(spanControl);

        ChildControlsCreated = true;
    } // CreateChildControls - Method - Override

    protected override void Render(HtmlTextWriter writer) {
        PostBackOptions pbo = new PostBackOptions(this);

        AddAttributesToRender(writer);
        writer.RenderBeginTag(HtmlTextWriterTag.Button);
        imageControl.RenderControl(writer);
        spanControl.RenderControl(writer);
        writer.RenderEndTag();
    } // Render - Event - Override
  }
}
  

Ответ №1:

Попробуйте реализовать IPostBackEventHandler интерфейс:

 public class ComboButton : WebControl, IPostBackEventHandler  
{
    public void RaisePostBackEvent(string eventArgument)
    {
        OnSubmit(EventArgs.Empty); 
    }
}
  

Вот статья, в которой объясняется реализация IPostBackEventHandler интерфейса:
http://msdn.microsoft.com/en-us/library/system.web.ui.ipostbackeventhandler.aspx

Редактировать

Если ваши события каким-либо образом зависят от данных, вам необходимо реализовать IPostBackDataHandler интерфейс. Например, вы могли бы использовать IPostBackDataHandler интерфейс для запуска OnTextChanged события текстового поля:

 public class ComboButton : WebControl, IPostBackDataHandler  
{
    public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
    {
        return true;
    }

    public virtual void RaisePostDataChangedEvent()
    {

    }
}
  

Вот статья, в которой объясняется реализация IPostBackDataHandler интерфейса:
http://msdn.microsoft.com/en-us/library/system.web.ui.ipostbackdatahandler.aspx

Комментарии:

1. Извините, я имел в виду IPostBackEventHandler

2. Это сделало это (В ОСНОВНОМ) — теперь событие запускается дважды. Смотрите мой ответ ниже, чтобы я мог опубликовать код.

3. Вероятно, вам просто нужно немного переработать логику вашего обработчика событий. Какой ответ вы имеете в виду?

4. Я попытался поместить код в эти комментарии, но он обрабатывает его как абзац и, следовательно, его трудно читать. Итак, я подумал, что если бы я мог ответить на это (поскольку я не вижу ответа), это помогло бы, но это тоже не было ответом. Итак, я просто ОТРЕДАКТИРОВАЛ начальный пост — см. После инструкции EDIT.

5. Попробуйте просто переместить OnSubmit(EventArgs.Empty) в RaisePostBackEvent метод и удалить OnClick обработчик событий из CreateChildControls метода.

Ответ №2:

Вам нужно заглянуть в IPostBackEventHandler

Если вы не реализуете этот интерфейс в своем элементе управления ASP.net движок не будет пересылать события под ваш контроль.