Sunday, August 17, 2008

Default button & Default focus in user controls.

Возникла задача устанавливать фокус ввода на нужный контрол внутри user control и выбирать кнопку, которую надо нажать, когда в TextBox нажимают "Enter".

1) Для назначения чего нажимать при нажатии "Enter" легко удалось найти решение в инете:
пишется джава-скрипт

function TestEnterKey(btn)
{
if (document.all)
{
if (event.keyCode == 13)
{
event.returnValue=false;
event.cancel = true;
document.getElementById(btn).click();
}
}
}


и метод, который будет его привязывать к контролу
    /// <summary>
/// Adds js to TextBox, that hits Button on pressing "Enter".
/// </summary>
/// <param name="baseControl">Control, that contains textbox and button.</param>
/// <param name="textBoxName">Text box, to which js should be added.</param>
/// <param name="buttonName">Button, that we should hit on pressing Enter.</param>
public static void AddDefaultButton(this Control baseControl, string textBoxName, string buttonName)
{
TextBox tb = ((TextBox) baseControl.FindControl(textBoxName));
tb.Attributes.Add("onkeypress",
"TestEnterKey(\"" +
baseControl.FindControl(buttonName).ClientID +
"\");");
}


теперь это можно использовать так:
PasswordRecovery1.UserNameTemplateContainer.AddDefaultButton("UserName", "SubmitButton");
PasswordRecovery1.QuestionTemplateContainer.AddDefaultButton("Answer", "SubmitButton1");


2) Сложнее оказалось с выставлением контрола, который будет выбираться по умолчанию.
Мне не удалось найти решение, которое меня полностью удовлетворило. В основной своей массе решения были пригодны либо только для серверных контролов и использовали методы Focuse(), SetFocuse(control), либо привязывали джава-скрипт к событию формы типа <form ... onload="some_java_script">. Последнее решение наиболее близко подходит к тому, что надо было мне. Но с ним есть беда: как привязывать джава-скприпт из user control? если внитри user control есть несполько панелек, и только одна из них видима в тот или иной postback, или, например, контрол состоит из шагов мастера, что собственно тоже самое, тогда надо определить несколько контролов, которые будут дефолтными и только на один из них в итоге будет выставлен фокус.

Короче такого решения я не нашил и пришлось написать велосипед.
Сделал так:
Написал метод:
    /// <summary>
/// Adds client-side script, that sets focus to the specified control.
/// </summary>
/// <param name="sender">Control that should be focused.</param>
/// <param name="e">Some other stuff, that isn't used here.</param>
public static void SetFocus(object sender, EventArgs e)
{
Control control = (Control) sender;
if (control != null)
{
string script = string.Format("setFocus(\"{0}\");", control.ClientID);
control.Page.ClientScript.RegisterStartupScript(typeof(string), Guid.NewGuid().ToString(), script, true);
}
}

, который привязывает к странице следующий скрипт:
function setFocus(ctrl)
{
var control = document.getElementById(ctrl);
if( control != null )
{
control.focus();
}
}

в итоге использовать это можно так:
PasswordRecovery1.UserNameTemplateContainer.FindControl("UserName").PreRender += Utils.SetFocus;
PasswordRecovery1.QuestionTemplateContainer.FindControl("Answer").PreRender += Utils.SetFocus;

No comments: