DefaultButton belülről

Valamikor régen ASP.NET 1.1 alatt nagyon sokat küzdöttünk azzal, hogy kezeljük azt az esetet, amikor a felhasználó valamelyik kontrollunkon állva rácsap az Enter gombra. Szerencsére a 2.0 verziótól kezdve ott van a DefaultButton tulajdonsága a HtmlFormnak és a Panelnek, ami látszólag megoldja ezt a problémát.

Sajnos előfordulhat, hogy az ember ezzel a hibaüzenettel találkozik:

The DefaultButton of ‘form1’ must be the ID of a control of type IButtonControl. smile_sarcastic

Kezdjünk el nyomozni, mi is történik! A nyomozás során természetes Lutz Roeder .NET Reflectorja játssza Watson doktor szerepét.

Panel

A Panel osztály AddAttributesToRender metódusában a következőt találjuk:

    Control button = this.FindControl( this.DefaultButton );
    if( !( button is IButtonControl ) )
    {
        throw new InvalidOperationException( SR.GetString( "HtmlForm_OnlyIButtonControlCanBeDefaultButton", 
new object[] { this.ID } ) ); } this.Page.ClientScript.RegisterDefaultButtonScript( button, writer, true );

A bökkenő a this.FindControlnál van, ez ugyanis általában csak a közvetlen gyermek elemeket fogja végignézni. Ha összetett kontrollunk van, akkor bizony nehezen fogja megtalálni benne a gombot. Nem baj, ássunk tovább:

A RegisterDefaultButtonScript a következő kódot rendeli a hivatkozott kontroll onkeypress eseményéhez:

    string text = "javascript:return WebForm_FireDefaultButton(event, '" + button.ClientID + "')";

HtmlForm

A HtmlForm osztály ugyanezt a metódust hívja meg, csak előtte máshogy készíti elő a terepet:

    Control button = this.FindControl( this.DefaultButton );
    if( ( button == null ) && ( this.Page != null ) )
    {
        char[] anyOf = new char[] { '$', ':' };
        if( this.DefaultButton.IndexOfAny( anyOf ) != -1 )
        {
            button = this.Page.FindControl( this.DefaultButton );
        }
    }
    if( !( button is IButtonControl ) )
    {
        throw new InvalidOperationException( SR.GetString( "HtmlForm_OnlyIButtonControlCanBeDefaultButton", 
new object[] { this.ID } ) ); } page.ClientScript.RegisterDefaultButtonScript( button, writer, false );

Itt már két FindControl találunk, és a Page szintű csak akkor hívódik meg, ha az első nem talál semmit és a DefaultButton értékeként megadott ID $ vagy : karaktereket tartalmaz. Ha ilyet szeretnénk, akkor kódból kell beállítanunk az értékét és a gomb UniqueID tulajdonságát kell használnunk. Az MSDN ezt kifejezetten ajánlja, ha master page-content page környezetben vagyunk.

Ez így bármennyire is logikusnak hangzik, a fenti megoldást nem sikerült működésre bírnom egy olyan Login kontroll esetén, amelynek renderelését CSS control adapter határozta meg. Ennek pedig az az oka, hogy a FindControl a vezérlő hierarchiát nézi végig, nem pedig a keletkezett kódot, a control adapterek pedig nem küzdenek a vezérlő fa felépítésével, hanem csak generálják a HTML-t.

Mi lett a megoldás? Az én esetemben megoldást (HACK!-et) jelentett, hogy a WebForm_FireDefaultButton javascript függvényt közvetlenül hozzáadtam egy DIV elemhez. Igen, ez nem szép…

 

Technorati tags: ,

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s