【问题标题】:Using custom WebControl as DefaultButton for Panel使用自定义 WebControl 作为面板的 DefaultButton
【发布时间】:2011-01-09 04:18:47
【问题描述】:

我创建了一个自定义 Web 控件来充当带有图像的按钮。我希望能够将其设置为 ASP.NET 面板控件的 DefaultButton 参数的目标。我实现了IButton接口,使用控件加载页面时没有报错。但是,当我在该面板内的文本框中按 Enter 键时,不会引发控件的 Click 事件。当我用标准的 ASP.NET 按钮替换我的控件时,一切正常。

我有一个测试页,其面板包含一个文本框、一个自定义按钮的实例和一个标准的 asp.net 按钮。这些按钮连接到一个事件处理程序,该处理程序会将文本框更改为调用者的 ID。

当面板的 DefaultButton 设置为 ASP.NET 按钮时,在下一个框中按 Enter 可以正常工作 - 页面回发,并且文本框填充了标准按钮的名称。当面板的 DefaultButton 设置为我的按钮时,在文本框中按 Enter 会导致页面回发,但不会触发 Click 事件。手动单击按钮可以正常工作。

有谁知道我必须向我的自定义控件添加什么以使其处理来自 Panel 控件的事件?我正在寻找在 Button 的源代码中使用 Reflector,但无法确定启用此行为的原因。

下面我贴出了控件的源码,以及测试页的相关源码。

控制来源:

public class NewButton : WebControl, IPostBackEventHandler, IButtonControl
{
    public NewButton() : base(HtmlTextWriterTag.A) { }

    public event EventHandler Click;

    public event CommandEventHandler Command;

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

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

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

    protected virtual void OnCommand(CommandEventArgs e)
    {
        if (Command != null)
            Command(this, e);
    }

    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        base.AddAttributesToRender(writer);

        writer.AddAttribute(HtmlTextWriterAttribute.Class, "Button");
        writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(this, "Click"));
    }

    protected override void RenderContents(HtmlTextWriter writer)
    {
        // base.RenderContents(writer);

        writer.WriteFullBeginTag("span");
        writer.WriteFullBeginTag("span");

        if (!String.IsNullOrEmpty(ImageUrl))
        {
            writer.WriteBeginTag("img");
            writer.WriteAttribute("src", Page.ResolveClientUrl(ImageUrl));
            writer.Write(HtmlTextWriter.SelfClosingTagEnd);
            writer.Write(" ");
        }

        writer.WriteEncodedText(Text);
        writer.WriteEndTag("span");
        writer.WriteEndTag("span");
    }

    public void RaisePostBackEvent(string eventArgument)
    {
        if (this.CausesValidation)
        {
            Page.Validate(this.ValidationGroup);
        }
        OnClick(EventArgs.Empty);
        OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
    }

    public bool CausesValidation
    {
        get { return ViewState["CausesValidation"] as bool? ?? true; }
        set { ViewState["CausesValidation"] = value; }
    }

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

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

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

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

调用它的代码:

<asp:Panel ID="Panel1" runat="server" CssClass="StandardForm" DefaultButton="NewButton1">
    <asp:TextBox runat="server" ID="text1" Columns="40" />
    <MyControls:NewButton ID="NewButton1" runat="server" Text="Test" OnClick="OnClick" />
    <asp:Button runat="server" ID="OldButton1" OnClick="OnClick" Text="Test" />
</asp:Panel>

代码背后:

   protected void OnClick(object sender, EventArgs args)
    {
        text1.Text = "Click event received from " + ((WebControl) sender).ID;
    }

控件呈现如下:

<div id="ctl00_MainContent_Panel1" class="StandardForm" onkeypress="javascript:return WebForm_FireDefaultButton(event, 'ctl00_MainContent_NewButton1')">
    <input name="ctl00$MainContent$text1" type="text" size="40" id="ctl00_MainContent_text1" />
    <a id="ctl00_MainContent_NewButton1" class="Button" onclick="__doPostBack('ctl00$MainContent$NewButton1','')"><span><span>Test</span></span></a>
    <input type="button" name="ctl00$MainContent$OldButton1" value="Test" onclick="javascript:__doPostBack('ctl00$MainContent$OldButton1','')" id="ctl00_MainContent_OldButton1" />
</div>

【问题讨论】:

  • 我很想看到这个问题的答案。我自己也经历过,太不耐烦了,不能走到这一步。我最终创建了一个 JavaScript 来捕获字段中的输入键并提交按钮。

标签: asp.net postback custom-server-controls


【解决方案1】:

WebForm_FireDefaultButton 函数的工作方式是显式查找相关元素上的 click() 事件。请注意,我指的是调用 element.click() 的能力,而不是 OnClick 属性。浏览器会自动为某些元素链接它,但不是链接,这是您的控件呈现的方式。如果您使用 LinkBut​​ton,您会注意到相同的行为。有几种不同的方法可以解决这个问题。您可以在这篇文章中覆盖 WebForm_FireDefaultButton javascript 函数:

Link Button on the page and set it as default button, work fine in IE but not in Mozila

或者你可以在你的控件中添加一些代码来正确连接客户端点击功能,可能是这样的......虽然这不是我的想法:

protected override void OnPreRender(EventArgs e)
{
    string clickString = string.Format("document.getElementById('{0}').click = function() {{ {1} }};", this.ClientID, Page.ClientScript.GetPostBackEventReference(this, "Click"));

    Page.ClientScript.RegisterStartupScript(this.GetType(), "click_hookup_" + this.ClientID, clickString, true);
}

【讨论】:

  • 我昨天在看 FireDefaultButton 的代码,注意到它在寻找 .click(),而不是 onclick。我尝试使用它的方法没有奏效 - 你的第二个解决方案没有问题。我宁愿使用它也不愿覆盖 WebForm_FireDefaultButton 函数。
【解决方案2】:

查看客户端标记(在浏览器中查看源代码);此功能应该在源代码中呈现类似的内容:

javascript:return WebForm_FireDefaultButton(event, 'ct100$bodyplaceholder$newbutton1')";

如果设置正确,则在您的页面中...如果第二个参数与您的按钮不正确匹配,它将无法正确触发。这可能有几个原因:

  1. 您是在渲染阶段渲染客户端/唯一 ID 还是调用 AddAttributesToRender。需要 ClientID 属性,因为它是将客户端元素链接到功能的方式,并且必须将其呈现给 id 属性。这发生在 AddAttributesToRender 方法中。
  2. 如果在该 JS 方法中看到 null,则它无法获取客户端 ID,通常是因为该属性已被覆盖。

HTH。

【讨论】:

  • JavaScript 在标记中正确呈现:
    这里的 ID 与我的按钮的 ID,所以不是这个。
  • 您的按钮标记是什么样的?你也可以发一下吗?
猜你喜欢
相关资源
最近更新 更多
热门标签