ASP.Net 自定义服务器控件不触发自定义事件

发布于 2024-12-09 12:41:59 字数 6667 浏览 1 评论 0原文

我创建了一个自定义服务器控件。它看起来很棒,渲染的 HTML 也符合它应有的样子。我最初让它扩展了 ControlContainer,现在它扩展了 WebControl(两者的行为相同)。它有两个属性:ImageUrl 和 Text。本质上,它将呈现一个通用 HTML 标签,其中包含一个 和 标签。

我的问题是暴露的 ServerClick 事件(我相信由 NamingContainer 提供)似乎没有触发。如果我添加任何 ASP 按钮(链接、图像或常规)并关联到该 Click 事件,它就会触发,但当然我还有额外的渲染内容。它成功运行 javascript 并执行 __dopostback 调用。但它不能看到给定的控件 ID 或其他内容,因为该事件永远不会被触发。

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(&#39;ctl00$MainContent$btnT4&#39;,&#39;&#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(&#39;ctl00$MainContent$btnT5&#39;,&#39;&#39;)" id="MainContent_btnT5" />

我必须相信我已经很接近了,但只是缺少一些东西。今天调整了几个小时,请帮忙!

编辑

感谢@James的回答,我所做的就是将以下内容添加到上面示例的顶部。它成功了,但现在发射了两次。不知道为什么?这就是我当前的问题:

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
  }
}

I have created a custom server control. It looks great and the rendered HTML is also as it should be. I initially had it extending the ControlContainer and now it extends the WebControl (both behave the same.) It has two properties, ImageUrl and Text. Essentially it will render a generic HTML tag with an and tags within it.

My problem is that the ServerClick event that is exposed (by NamingContainer I beleive) doesn't seem to fire. If I add any of the ASP buttons (Link, Image or regular) and associate to that Click event it fires but of course I have extra rendered content. It successfully runs the javascript and does the __dopostback call. But it must not see the given control ID or something because the event never gets fired.

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();
    }
    }
}

Here is my markup. I put in this control and then a regular ASP:Button. That regular button's event gets hit! Not mine.

<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" />

And here is the rendered HTML:

<button id="MainContent_btnT4" class="PButtonCombo" onclick="javascript:__doPostBack('ctl00$MainContent$btnT4','')"><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('ctl00$MainContent$btnT5','')" id="MainContent_btnT5" />

I have to believe I am close but just missing something. Been tweaking it for hours today, PLEASE HELP!

EDIT:

Thanks to @James answer, all I did was add the following to the top of the above example. It did the trick but now fires twice. Not sure why? So that is my current question:

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);
    }

EDIT 2 == SOLUTION

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
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

似最初 2024-12-16 12:41:59

尝试实现 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 接口来触发 TextBox 的 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

Try implementing the IPostBackEventHandler interface:

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

Here's an article that explains the implementation of the IPostBackEventHandler interface:
http://msdn.microsoft.com/en-us/library/system.web.ui.ipostbackeventhandler.aspx

EDIT

If your events are in some way dependent on data, you need to implement the IPostBackDataHandler interface. For example, you would use the IPostBackDataHandler interface to fire the OnTextChanged event of a TextBox:

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

    public virtual void RaisePostDataChangedEvent()
    {

    }
}

Here's an article that explains the implementation of the IPostBackDataHandler interface:
http://msdn.microsoft.com/en-us/library/system.web.ui.ipostbackdatahandler.aspx

南城旧梦 2024-12-16 12:41:59

您需要查看 IPostBackEventHandler

如果您没有在控件中实现此接口,ASP.net 引擎将不会将事件转发到您的控件。

You need to look into IPostBackEventHandler

If you dont implement this interface in your control ASP.net engine wont forward the events to your control.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文