Использование свойства Panel.DefaultButton с контролом LinkButton в ASP.NET

Aug 25
2007 12:53 (ASP.NET, Программирование) · English (24,084 views)

В ASP.NET есть существенное ограничение — на странице может быть только одна серверная форма. Даже если вы разрабатываете сложную страницу, которая выглядит как несколько форм с разными submit-кнопками, в действительности у вас есть только одна форма. Возникает следующая проблема: как браузер понимает, какая кнопка должна сработать, когда пользователь нажимает ENTER? Он использует первый контрол Button (что обычно неверно), а если вы используете LinkButton‘ы, они вообще не сработают. В ASP.NET 2.0 было добавлено новое свойство контролам Panel и HtmlFormDefaultButton, которое используется для указания ID контрола, реализующего интерфейс IButtonControl (обычно Button и LinkButton). Этот контрол сработает, когда пользователь нажмет ENTER. Но существует одна большая проблема: контрол LinkButton не сработает в Firefox по нажатию ENTER. В этой статье я покажу, почему возникает проблема и предложу ее решение.

Рассмотрим, как работает DefaultButton в ASP.NET. Вот простой пример:

<asp:Label runat="server" ID="lblHello" />
<asp:Panel runat="server">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <asp:LinkButton ID="lbHello" runat="server" Text="Click me" OnClick="lbHello_Click" />
</asp:Panel>
protected void lbHello_Click(object sender, EventArgs e)
{
    lblHello.Text = String.Format("Hello, {0}", txtFirstName.Text);
}

Когда вы попытаетесь нажать кнопку ENTER в поле ввода, форма будет отправлена на сервер, но событие Click контрола LinkButton не сработает. Давайте укажем свойство DefaultButton панели.

<asp:Panel runat="server" DefaultButton="lbHello">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <asp:LinkButton ID="lbHello" runat="server" Text="Click me" OnClick="lbHello_Click" />
</asp:Panel>

Отлично! Идеально работает в Internet Explorer, но как насчет Firefox? Упс, у нас проблема. Вы можете найти решение в конце заметки, но сначала я хотел бы показать, почему возникает эта проблема. Когда вы указываете свойство DefaultButton, ASP.NET генерирует следующий код:

<div onkeypress="javascript:return WebForm_FireDefaultButton(event, 'lbHello')">
</div>

Вот метод WebForm_FireDefaultButton, определенный в библиотеке JavaScript ASP.NET:

function WebForm_FireDefaultButton(event, target) {
    if (event.keyCode == 13 && !(event.srcElement && (event.srcElement.tagName.toLowerCase() == "textarea"))) {
        var defaultButton;
        if (__nonMSDOMBrowser) {
            defaultButton = document.getElementById(target);
        }
        else {
            defaultButton = document.all[target];
        }
        if (defaultButton && typeof(defaultButton.click) != "undefined") {
            defaultButton.click();
            event.cancelBubble = true;
            if (event.stopPropagation) event.stopPropagation();
            return false;
        }
    }
    return true;
}

Проблема возникает в коде typeof(defaultButton.click) != “undefined” — Firefox не определяет метод click() для элемента a, поэтому форма будет отправлена на сервер без параметра __EVENTTARGET, и событие не сработает. Простейшее решение — определить метод click() для a:

var b = document.getElementById('<%= lbHello.ClientID %>');
if (b && typeof(b.click) == 'undefined') {
    b.click = function() { 
        var result = true;
        if (b.onclick) result = b.onclick();
        if (typeof(result) == 'undefined' || result) {
            eval(b.getAttribute('href'));
        }
    }
}

Наш метод click() имитирует поведение элемента a: сначала он вызывает метод onclick() (атрибут OnClientClick контрола LinkButton), и если тот возвращает false — прекращает обработку. Затем он делает eval атрибуту href (где ASP.NET размещает вызов __doPostBack).

Давайте создадим свой контрол, который инкапсулирует эту логику:

using System;
using System.Web.UI.WebControls;

namespace App_Code
{
    public class LinkButtonDefault : LinkButton
    {
        protected override void OnLoad(System.EventArgs e)
        {
            Page.ClientScript.RegisterStartupScript(GetType(), "addClickFunctionScript",
                _addClickFunctionScript, true);

            string script = String.Format(_addClickScript, ClientID);
            Page.ClientScript.RegisterStartupScript(GetType(), "click_" + ClientID,
                script, true);
            base.OnLoad(e);
        }

        private const string _addClickScript = "addClickFunction('{0}');";

        private const string _addClickFunctionScript =
            @"  function addClickFunction(id) {{
            var b = document.getElementById(id);
            if (b && typeof(b.click) == 'undefined') b.click = function() {{
                var result = true; if (b.onclick) result = b.onclick();
                if (typeof(result) == 'undefined' || result) {{ eval(b.getAttribute('href')); }}
            }}}};"
;
    }
}

И соответствующий .aspx файл:

<%@ Register Namespace="App_Code" TagPrefix="ac" %>
<asp:Label runat="server" ID="lblHello" />
<asp:Panel runat="server" DefaultButton="lbHello">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <ac:LinkButtonDefault ID="lbHello" runat="server" Text="Click me" OnClick="lbHello_Click" />
</asp:Panel>

Безусловно, код JavaScript должен быть вынесен из кода C#, но для моего примера этого достаточно. Если вы используете библиотеку ASP.NET AJAX, вы должны вызывать метод ScriptManager.RegisterStartupScript вместо ClientScriptManager.RegisterStartupScript.

Надеюсь, заметка поможет вам. Комментарии приветствуются.

22 отзывов на 'Использование свойства Panel.DefaultButton с контролом LinkButton в ASP.NET'

Подписаться на комментарии по RSS или TrackBack на 'Использование свойства Panel.DefaultButton с контролом LinkButton в ASP.NET'.

1
parthiban
сказал 06.09.2007 в 13.42

asp.net panel scroll bars not visible in opera.why?

2
сказал 19.09.2007 в 16.25

hi
I am using Aspnet ajax in my application, i used asp button for submiting a form, beacuse asp:Button work in both condition when Javascript is enable or disabled.
but asp:button are not look good in mac broswer so client do want asp:Button/asp:ImageButton in whole application.
Please advise What would be the replcaement of asp:Button/asp:ImageButton which will work in both condition when Javascript is enable or disabled.

Thanks

Regards
Raghvendra
to_raghvendra@yahoo.com

3
сказал 19.09.2007 в 16.47

asp:LinkButton works only when JavaScript is enabled, you right. I see only one solution: add two buttons at the same time (for browsers that does not support JavaScript — asp:Button, visible by default, and asp:LinkButton for ones, that support JavaScript), and switch their visibility using JavaScript. Something like this:

<asp:Button runat="server" ID="btnSubmit" Text="submit" />
<asp:LinkButton runat="server" ID="lbSubmit" style="display:none" Text="submit" />
<script type="text/javascript">
    document.getElementById("<%= btnSubmit.ClientID %>").style.display = 'none';
    document.getElementById("<%= lbSubmit.ClientID %>").style.display = '';
</script>

But of course this is not perfect solution. BTW, you could use images as background of the asp:Button or asp:ImageButton, and they would look perfectly in Safari.

4
Tyler Thompson
сказал 27.09.2007 в 19.52

That worked perfectly! Thank you for your post.

5
сказал 25.10.2007 в 20.45

[...] is one solution that creates their own “click” event for the LinkButton. You can look at it here (this solution does work as well, i just found it too much). I wanted something simpler, Simple is [...]

6
сказал 14.11.2007 в 7.39

[...] But of course if you are using a LinkButton, then its a whole another ball game. None of the techniques described above might work for you. But you are in luck, this page has what you need to get around that — http://kpumuk.info/asp-net/using-panel... [...]

7
сказал 12.12.2007 в 23.27

One simple way to get around the Linkbutton issue and the firefox issue is to set up a “shadow” button on the page with a style="display:none;"

So, say I have a login form, I will put a link button on the form in case the user is going to click it directly. Then, just underneath it I will add a hidden asp:Button, with display:none, and tie that to the same event as the regular login linkbutton.

Works in both IE7 and FF2 as far as I can tell, and doesn’t require any javascript — just a stupid workaround.

8
Тимур
сказал 15.02.2008 в 8.53

Работает идеально, спасибо! Но… Очень бы хотелось, чтобы работало в опере по Ctrl + Enter (автозаполнение). Есть идеи?
Спасибо.

9
Chris
сказал 23.02.2008 в 5.49

Dave’s solution is the way to go.

10
uttam
сказал 10.03.2008 в 15.43

Hi guys i found solution finally.

Setting link button as Default button for FIREFOX as well as IE:
use this fallowing code–>

in .aspx file—————————

function clickButton(e,buttonid) {
    debugger;
    var bt = document.getElementById(buttonid);
    if (typeof(bt) == 'object') {
        if (navigator.appName.indexOf("Netscape") > -1) {
            if(e.keyCode == 13) {
                if (bt && typeof(bt.click) == 'undefined') {
                    bt.click =  addClickFunction1(bt);
                }
            }
        }
        if (navigator.appName.indexOf("Microsoft Internet Explorer") > -1) {
            if (event.keyCode == 13) {
                bt.click();
                return false;
            }
        }
    }
}

function addClickFunction1(bt) {
    debugger;
    var result = true;
    if (bt.onclick) result = bt.onclick();
    if (typeof(result) == 'undefined' || result) {
        eval(bt.href);
    }
}

————————-

in aspx.cs file (write code for the text boxes u required)

aspx.cs file(C#.net code)—>
in Page_Load Event

txtUserName.Attributes.Add("onkeypress", "javascript:return clickButton(event,'" + btnSearch.ClientID + "');");
11
uttam
сказал 10.03.2008 в 15.50

reg Above Code–>
Please read this for the reference of the above code , and read the ID’s for the textbox’s and Link Buttons

for the above code in aspx form ,we have
a
asp Text box with id “txtUserName”
and
a
link button with id “btnSearch”

like

12
Jared Holgate
сказал 21.04.2008 в 13.16

This solution worked perfectly. Thank you very much.

13
Martin
сказал 22.04.2008 в 14.38

Solution is ok. Unfortunatelly, this does not work under Firefox 3.

Anyone know how to do it?

14
Ramana
сказал 22.05.2008 в 5.59

Hi uttam,

i am implemented what you are given the code in my aspx page, but in FireFox again its not working, when i enter key in textbox the cursor goes to next button, could you please give me any idea.

Thanks
Ramana

15
Simon
сказал 09.06.2008 в 11.42

Hi,

I have implemented this fix and it seems to be ok in most cases. However, if I have a form with asp.net validators then it only works once. e.g. Enter an invalid entry, press enter and the correct button is clicked. However, press enter again, and the wrong one is clicked!

Anyone have any ideas? Thanks in advance.

Simon.

16
mdespesse
сказал 16.06.2008 в 12.45

It seems that firefox 3 automatically htmlencode hrefs. So our :

javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOption[...]

becomes :

javascript:WebForm_DoPostBackWithOptions(new%20WebForm_PostBackOption[...]

which obviously doesn’t work as expected.
To have it work again, change the end of addClickFunctionScript to :

eval(unescape(b.href));
17
mdespesse
сказал 16.06.2008 в 13.25

After some research, it seems that DOM specs stand that href attribute should be an URI and that to get the exact content of href, one should use :

eval(b.getAttribute('href'))
18
сказал 16.06.2008 в 15.48

Nice point, mdespesse! Thanks for sharing your experience.

19
Jared Holgate
сказал 18.06.2008 в 10.14

Mdespesse’s point in 17 makes this solution work perfectly in FF3. Thanks.

20
сказал 21.08.2008 в 0.42

Based on Dave’s solution (post #7).

<asp:Panel ID="pnNewstatus" runat="server" DefaultButton="btnHiddenSubmit">
New Status:
<asp:TextBox ID="txbNewStatus" runat="server"/>
<asp:LinkButton ID="lnkBtnNewStatusCancel" runat="server" Text="Cancel" />
<asp:LinkButton ID="lnkBtnNewStatusSubmit" runat="server" Text="Submit" />
<asp:Button ID="btnHiddenSubmit" runat="server" />
</asp:Panel>

and then, on the code behind:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  btnHiddenSubmit.Attributes.Add("style", "display:none;")
End Sub

Protected Sub lnkBtnNewStatusSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkBtnNewStatusSubmit.Click, btnHiddenSubmit.Click
'Do What you need to do for those clicks
End Sub
21
Marlon Bohol
сказал 21.08.2008 в 4.32

This is what i did in ASP.NET code behind and it works pretty well in both IE and FF:

Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
        JavaScriptLoad()

    Private Sub JavaScriptLoad()

        Dim addClickFunctionScript As StringBuilder = New StringBuilder()

        addClickFunctionScript.Append("  function addClickFunction(id) {{ ")
        addClickFunctionScript.Append(" var b = document.getElementById(id); ")
        addClickFunctionScript.Append(" if (b && typeof(b.click) == 'undefined') b.click = function() {{ ")
        addClickFunctionScript.Append(" var result = true; if (b.onclick) result = b.onclick(); ")
        addClickFunctionScript.Append(" if (typeof(result) == 'undefined' || result) {{ eval(b.getAttribute('href')); }} ")
        addClickFunctionScript.Append(" }}}}; ")

        Dim addClickScript As String = "addClickFunction('{0}');"
        Dim ClickScript As String = String.Format(addClickScript, lnkLogin.ClientID)

        Page.ClientScript.RegisterStartupScript(Me.GetType(), "addClickFunctionScript", addClickFunctionScript.ToString(), True)
        Page.ClientScript.RegisterStartupScript(Me.GetType(), "click_" + lnkLogin.ClientID, ClickScript, True)

    End Sub

corresponding .aspx file

<asp:Panel runat="server" DefaultButton="lbHello">
    First name: <asp:TextBox runat="server" ID="txtFirstName" />
    <asc:LinkButton ID="lbHello" runat="server" Text="Click me"  />
</asp:Panel>
22
Jake H
сказал 11.09.2008 в 18.17

The simplest, cross-browser approach I’ve seen is at this guy’s site:

http://weblogs.asp.net/jeff/archive/2005/07/26/420618.aspx

Just one line and you’re all set…
MyPasswordTextBox.Attributes.Add(”onKeyPress”, “javascript:if (event.keyCode == 13) __doPostBack(’” + MySubmitButton.UniqueID + “‘,”)”)

Оставить отзыв

Вы можете использовать простые теги форматирования HTML (вроде <a>, <ul> and others). Чтобы вставить пример код, используйте <code lang="php">$a = "hello";</code> (поддерживаемые языки: ruby, php, yaml, html, csharp, javascript). Также Вы можете использовать <code>$a = "hello";</code>, синтаксис не будет подсвечен. Если вы не хотите использовать тег <code>, замените символ < на &lt;.

Отправить

 
Copyright © 2005 - 2008, Dmytro Shteflyuk