UpdatePanel uppför sig ibland underligt när man använder kontroller med egen rendering inuti. Microsoft ger den något kryptiska ledtråden:
All other controls work inside UpdatePanel controls. However, in some circumstances, a control might not work as expected inside an UpdatePanel control. These circumstances include the following:
Registering script by calling registration methods of the ClientScriptManager control.
Rendering script or markup directly during control rendering, such as by calling the Write method.
Antag att vi har en egen kontroll med kod som:
- C#
protected override void Render( HtmlTextWriter writer )
{
writer.WriteBeginTag( "div" );
writer.WriteAttribute( "onclick", Page.ClientScript.GetPostBackEventReference( this, "SomeArgument" ) );
writer.Write( ">" );
writer.Write( "..." );
writer.WriteEndTag( "div" );
}
Om vi använder en sådan kontroll inuti en UpdatePanel kommer den mycket riktigt inte att uppföra sig "as expected". Postbacken kommer att uppdatera hela sidan, inte bara innehållet i vår UpdatePanel.
Varför blir det så?
Det första som händer är att koden ovan genererar markup enligt:
- C#
<div onclick="__doPostBack( 'ctl07','SomeArgument' )">...</div>
Funktionen __doPostBack postar normalt hela sidan. Ajax-scriptmanagern har dock inkluderat kod som ersätter __doPostBack med sin egen variant som så småningom hamnar i funktionen:
- C#
function Sys$WebForms$PageRequestManager$_doPostBack(eventTarget, eventArgument) {
...
var clientID = this._uniqueIDToClientID(eventTarget);
var postBackElement = document.getElementById(clientID);
...
Parametern eventTarget har i vårt fall värdet "ctl07". Variabeln clientID kommer att ha samma värde (_uniqueIDToClientID byter ut lite specialtecken för att översätta mellan server och client-id:n). Däremot kommer postbackElement inte att hittas i dokumentet. Detta gör att koden går vidare och postar med orginalhanteraren.
Det krävs en djupare undersökning än det finns plats för här för att utreda varför AJAX-ramverket kräver ett motsvarande element i DOM:en, men om man är mest intresserad av att få det att fungera är lösningen att ändra koden till:
- C#
protected override void Render( HtmlTextWriter writer )
{
writer.WriteBeginTag( "div" );
writer.WriteAttribute( "id", ClientID );
writer.WriteAttribute( "onclick", Page.ClientScript.GetPostBackEventReference( this, "SomeArgument" ) );
writer.Write( ">" );
writer.Write( "..." );
writer.WriteEndTag( "div" );
}
Markupen kommer nu att innehålla ett id motsvarande postbackens mottagare och vi kommer att få en asynkron postback.