En ASP.NET Web Forms algunos controles disponen de un par de propiedades interesantes para mejorar la usabilidad de la interfaz de usuario. Se trata de DefaultButton y DefaultFocus que permiten decidir respectivamente qué botón del formulario va a ser el que se ejecute al pulsar ENTER y qué control tendrá el foco en el formulario cuando éste cargue.

Esto, que parece una tontería, es muy útil ya que es frecuente encontrarse por ahí páginas bastante mal hechas en las que, por ejemplo, vas a buscar algo en un cuadro de búsqueda, le das a ENTER tras introducir los términos de búsqueda en el cuadro de texto correspondiente, y en lugar de efectuarse la búsqueda lo que ocurre es que simplemente se recarga la página. El motivo es que cuando pulsas ENTER en un cuadro de texto, por defecto lo que hace cualquier navegador es enviar el formulario al servidor. Si resulta que tu código de búsqueda está en el evento Click de un botón o un ImageButton, no se lanza este evento de servidor y por lo tanto la búsqueda no se realiza. Es muy frustante.

Lo que deberíamos hacer normalmente si no existiese la propiedad DefaultButton es capturar con JavaScript el envío del formulario y sustituirlo por una llamada a la función __doPostBack que genera el evento. Un engorro absoluto para algo que debería ser inmediato. Gracias a DefaultButton basta con indicar en esta propiedad el nombre del botón deseado, y cuando se pulse ENTER estando en cualquier cuadro de texto contenido en el control en el que hemos establecido la propiedad, en lugar de enviar el formulario se lanza el evento de este botón. Fácil.

Lo mismo ocurre con el cuadro de texto o control de formulario que en el que queramos que recaiga el foco al entrar en la página. Es bastante molesto, por ejemplo, entrar a una página en la que nos solicitan unos datos y tener que pulsar con el ratón en el primer cuadro de texto libre para poder empezar a escribir. Lo suyo sería que el foco ya estuviese en el primer control automáticamente. De nuevo, conseguirlo con JavaScript es sencillo pero engorroso si tuviésemos que hacerlo en todas las páginas. Si establecemos la propiedad DefaultFocus al nombre del TextBox que queramos, ya se ocupa ASP.NET de hacerlo.

Fíjate en que estas dos propiedades, aunque se suelen aplicar en el formulario que tienen todas las páginas ASP.NET Web Forms, en realidad se puede utilizar con otros controles contenedores, fundamentalmente el control Panel, si bien cualquiera que herede de la clase Container lo posee. Según Reflector estos son los controles que lo implementan:

DefaultButton_DefaultFocus_Controles

 

Lo normal, como digo, es aplicarlo en el propio formulario de la página:

DefaultButton_DefaultFocus

o en un control Panel que contenga controles para toma de datos.

Por ejemplo, si tenemos un formulario de búsqueda con un control Textbox llamado txtTextToSearch y un botón llamado btnSearch, podríamos establecer estas propiedades en el formulario de esta manera:

   1: <form id="form1" runat="server" defaultbutton="btnSearch" defaultfocus="txtTextToSearch">

De esta forma al cargar la página el foco estará en el cuadro de texto y cuando escribamos algo en él y pulsemos ENTER se lanzará el evento Click del botón. Estupendo.

Controles dentro de Páginas Maestras (Master Pages)

Esto es estupendo en una página individual "suelta" y funciona muy bien. Pero lo normal es que en cualquier aplicación Web no trivial estemos utilizando Master Pages (a mi lo de llamarles Páginas Maestras me repele, prefiero el término en inglés o simplemente "plantillas").

Al utilizar una MP, las páginas derivadas no tienen ya un formulario, puesto que éste está en la plantilla y no en la página en sí, por lo que no podemos aplicarle estas dos propiedades directamente.

Para solucionar el problema con controles que tengamos en nuestra página derivada tenemos dos opciones bastante sencillas a priori:

  1. Utilizar un control Panel para envolver a nuestros controles y establecer la propiedad allí.
  2. Utilizar la propiedad Page.Form para acceder al formulario principal, y establecer por código DefaultButton y DefaultFocus desde el evento Load de la página.

Así, por ejemplo, podríamos intentar escribir esto:

   1: Page.Form.DefaultButton = btnLogin.ID;

El problema es que no funcionaría.

Lo que está ocurriendo es que cuando la página no deriva de una Master Page podemos simplemente establecer estas propiedades con el identificador de los controles. Pero cuando una página utiliza una MP, lo que ocurre internamente es que se genera una jerarquía más compleja en la que el contenido de la Master se convierte en un control hijo del Web Form que contiene a sus controles ContentPlaceHolder, y éstos a su vez contienen a los controles que hayamos puesto dentro de ellos al diseñar la página.

En cristiano: si el control se llamaba "btnSearch" cuando la página estaba sola, cuando utilizamos una Master Page su nombre en el lado cliente se convierte en algo similar a esto:

  ctl00$ContentPlaceHolder1$pnlSearch$btnSearch

por ejemplo, en el caso de que el botón esté dentro de un panel, que a su vez esté en un ContentPlaceHolder y este último, por supuesto, dentro de una Master Page.

Este es el valor que tendrá en el atributo "name" del control HTML correspondiente en el código fuente que se genera para la página. Pero es que en el atributo "id", lo que tendrá será algo similar a esto:

ctl00_ContentPlaceHolder1_pnlSearch_btnSearch

Por lo tanto lo que tenemos que hacer en estas propiedades es indicar el nombre correcto de lado de cliente, que no es el identificador del botón o control.

Y ¿cuál es el nombre correcto en cada caso y cómo lo obtenemos?

Podremos obtener el valor del atributo "id" usando la propiedad ClientID del control. El valor del atributo "name" se obtiene a través de la propiedad UniqueID del mismo.

Por lo tanto, en nuestro ejemplo, bastaría con escribir esto en la carga de la página:

   1: Page.Form.DefaultButton = btnSearch.UniqueID;
   2: Page.Form.DefaultFocus = txtTextToSearch.ClientID;

Fíjate que en cada caso debemos usar una propiedad diferente para obtener un identificador diferente. Esto es así porque en el caso del botón se utiliza su identificador para localizarlo en la página (con getElementById), mientras que en el caso del cuadro de texto se localiza dentro de los controles del formulario mediante su nombre (contenido en el atributo "name").

¡Espero que te sea útil!

¿Te ha gustado este post? - Aprende .NET con los cursos on-line tutelados de campusMVP:
   ·
Preparación del examen 70-515: Desarrollo Web con .NET 4.0 (Tutelado por mi)
   · Desarrollo Web con ASP.NET 4.0 Web Forms (Tutelado por mi)
   · ASP.NET 4.0 Web Forms desde cero (Tutelado por mi)
   · Desarrollo Web con ASP.NET MVC 3 
   · Silverlight 4.0 - Aplicaciones Ricas para Internet (RIA)
   · jQuery paso a paso para programadores ASP.NET
   · Visual Studio 2010 desde cero

Escrito por un humano, no por una IA