在Ajaxified Wizard Control中设置默认按钮

时间:2009-07-29 15:09:33

标签: asp.net asp.net-ajax wizard

我的ASP.NET Web表单上有一个Wizard控件。我在代码隐藏中的ApplicationWizard PreRender事件中的每个步骤上设置默认按钮,如下所示:

Page.Form.DefaultButton = ApplicationWizard.FindControl("StepNavigationTemplateContainerID").FindControl("StepNextButton").UniqueID;

这是完美的工作,但当我ajaxify向导控件它不起作用。默认按钮设置为我在初始加载表单时指定的控件(StartNextButton),但在其他步骤中不更新为StepNextButton。我做错了什么?

6 个答案:

答案 0 :(得分:1)

经过一两天的拉扯我的头发后,我设法破解了这个...希望这有助于其他人像我一样感到沮丧:

任何发现此帖子的人都知道这里的直观答案,将表单的默认按钮设置为向导的“下一步”按钮,什么都不做。因此,下一个合乎逻辑的步骤是通过代表用户单击按钮来尝试围绕问题进行设计。假设我在代码隐藏中将下面的处理程序附加到我的文本框中,并且myButtonId是我需要的按钮的id作为我的默认值:

            function textKeyDown(e) {
                if (e.keyCode == 13) {
                    var myBtn = $get(myButtonId);
                    myBtn.click();
                }
            }

你会认为上面的工作会很好,但事实证明,迫使向导按钮点击是一个非常偷偷摸摸的冲突 - 页面上的第一个按钮也会点击,覆盖我点击的初始按钮点击通过脚本和创建非常奇怪的结果。在我的例子中,我母版页中的第一个按钮是一个显示Home的按钮,当用户点击它时,它们会返回到他们的主页。因此,在我试图强制向导的下一个按钮单击时,我最终会回到我的主页,看起来没有任何理由。在附加到PageRequestManager.initializeRequest之后,我能够看到我有两个单独的回发启动:1表示我的强制向导按钮单击,1表示我当时甚至不在我的雷达上的按钮 - 主页按钮。

所以,长话短说,如果我从后面的代码中更新表单的默认按钮(Page.Form.DefaultButton),然后从后面的代码中发出这个脚本并从我的文本框中引用它,所有工作只是细:

    public static void ExampleAssignDefaultButton(WizardStepBase activeWizardStep, TextBox myTextBox, IButtonControl myButton)
    {
        // create the format string for the script
        string javaScript = @"function defaultButton(src, evt){{
                                if(evt.keyCode == 13){{
                                    var btn = $get('{0}');
                                    setTimeout(new function() {{ btn.click(); }}, 5);
                                }}
                            }}";

        // format it ...
        javaScript = String.Format(javaScript, ((WebControl)myButton).ClientID);
        // register it...
        ScriptManager.RegisterClientScriptBlock(activeWizardStep, activeWizardStep.GetType(), "defaultButton", javaScript, true);

        // assign it to my textbox
        myTextBox.Attributes.Add("onkeydown", "defaultButton(this, event);");

        // also update the form's default button:
        myTextBox.Page.Form.DefaultButton = ((WebControl)myButton).UniqueID;
    }

值得注意的是,我总是从主动向导步骤的OnPreRender事件中调用上述方法。值得注意的是,因为我的向导中每个步骤只有一个文本框,所以我只需要将此行为分配给一个控件。我没有尝试过这个修复范围,以便在整个页面上按下Enter键,但我无法想象它在该上下文中的行为会有太大不同。如果每步有很多输入,则可能不需要在向导中的每个控件上捕获Enter键。

所以,你有它 - 只需要12个小时的故障排除来做一些应该花费大约10分钟的事情。

快乐的编码。

答案 1 :(得分:1)

感谢Brian,在使用RadAjax和多个用户控件以及多种类型的面板时,您的脚本帮助我设置了自己的脚本。您可以通过从控件而不是脚本中传递按钮ID来简化defaultButton。

在页面中:

function defaultButton(btnid, src, evt) {
    if (evt.keyCode == 13) {
        var btn = $get(btnid);
        setTimeout(new function () { btn.click(); }, 5);
    }
}

在代码中:

Private Sub WizardStep_PreRender(sender As Object, e As System.EventArgs) Handles wsUserPass.PreRender, wsCompanyCode.PreRender, wsSetPassword.PreRender
    Dim button As WebControl = Nothing
    Dim activeWizardStep As WizardStepBase = CType(sender, WizardStepBase)
    Select Case activeWizardStep.StepType
        Case WizardStepType.Step
            button = activeWizardStep.FindControl("StepNavigationTemplateContainerID").FindControl("StepNextButton")
        Case WizardStepType.Start
            button = activeWizardStep.FindControl("StartNavigationTemplateContainerID").FindControl("StartNextButton")
        Case WizardStepType.Finish
            button = activeWizardStep.FindControl("FinishNavigationTemplateContainerID").FindControl("FinishButton")
    End Select
    If button Is Nothing Then Return
    Dim ctrls = FindControls(Of RadTextBox)(activeWizardStep)
    For Each ctrl In ctrls
        ctrl.Attributes.Add("onkeydown", String.Format("defaultButton('{0}', this, event);", button.ClientID))
    Next
    pnlMain.DefaultButton = button.UniqueID
End Sub

Public Shared Function FindControls(Of T)(ctrl As Control) As List(Of T)
    Dim controls As New List(Of T)
    If ctrl.Controls.Count > 0 Then
        For Each subctrl In ctrl.Controls
            If [Type].ReferenceEquals(GetType(T), subctrl.GetType()) Then
                controls.Add(subctrl)
            Else
                controls.AddRange(FindControls(Of T)(subctrl))
            End If
        Next
    End If
    Return controls
End Function

(注意,UniqueID对我不起作用,不得不将其更改为ClientID)

答案 2 :(得分:0)

答案 3 :(得分:0)

默认按钮的定义是什么?如果它是一个按钮,当你在文本表单字段(输入类型=文本)时应该调用并按回车键,然后在每个浏览器中它是表单中的第一个提交或图像按钮(输入类型=提交|图像)如果存在的话。

您可以做的是向所有控件添加客户端脚本,[enter]上的提交表单等规则适用(例如输入类型=“文本”)。

服务器端示例(可以在Form_Init中使用)只是为了一个想法:

SomeTextBox.Attributes.Add("onkeydown",
    "if((event.keyCode&&event.keyCode==13)){" +
    Page.ClientScript.GetPostBackEventReference(StepNextButton, "") +
    ";return false;}" +
    "if((event.keyCode&&event.keyCode==27)){" +
    Page.ClientScript.GetPostBackEventReference(CancelButton, "") +
    ";return false;}");

keyCode == 13是回车键
keyCode == 27是一个转义键

答案 4 :(得分:0)

我想我终于搞砸了! javascript中的(调试)警报消息使其工作的事实使我指向了正确的方向......

我不得不在javascript中添加几行以使其工作,以便我的方法如下所示:

private void SetDefaultButtonScript(WizardStepBase activeWizardStep, IButtonControl myButton)
    {
        string clientID = ((WebControl)myButton).ClientID;
        string uniqueID = ((WebControl)myButton).UniqueID;

        // create the format string for the script 
        string javaScript = @"function defaultButton(btnid, evt) {{ 
                                if (evt.keyCode == 13) {{ 
                                    __doPostBack('{0}', '');
                                    var btn = $get('{1}');
                                    btn.focus();
                                    return;
                                }} 
                            }} 
                            ";
        javaScript = String.Format(javaScript, uniqueID, clientID); 

        // register it... 
        ScriptManager.RegisterClientScriptBlock(activeWizardStep, activeWizardStep.GetType(), "defaultButton", javaScript, true);

        foreach (Control c in activeWizardStep.Controls)
        {
            if (c is TextBox)
            {
                ((TextBox)c).Attributes.Add("onkeydown", "defaultButton(this, event);"); 
            }
            //TODO child controls of controls to find all text boxes, any other controls etc
        }

        Page.Form.DefaultButton = uniqueID;
    } 

我正在使用__doPostBack而不是点击,但这不是问题。

答案 5 :(得分:0)

我认为你不需要任何脚本。问题似乎是页面上有多个提交按钮。因此,您必须告诉asp.net您要将哪一个用作“默认”提交。您必须在页面生命周期中的正确时间告诉它。我不确定它是否是最佳的,但在PreRender事件中这样做似乎有效。只添加了以下代码的基本ajaxified向导似乎使用了正确的按钮:

Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
    MyBase.OnPreRender(e)
    Select Case LoginWizard.ActiveStep.StepType
        Case WizardStepType.Start
            Page.Form.DefaultButton = LoginWizard.FindControl("StartNavigationTemplateContainerID").FindControl("NextStart").UniqueID
        Case WizardStepType.Step
            Page.Form.DefaultButton = LoginWizard.FindControl("StepNavigationTemplateContainerID").FindControl("NextStep").UniqueID
        Case WizardStepType.Finish
            Page.Form.DefaultButton = LoginWizard.FindControl("FinishNavigationTemplateContainerID").FindControl("LastStep").UniqueID
    End Select
End Sub