Ormai sono abituato ad evitare a tutti i costi i popup nelle applicazioni web. Tuttavia mi rendo conto che c'è ancora qualcuno che non riesce a farne a meno, a torto o a ragione non mi interessa sapere. Durante la track web dei CommunityDays sono stato molto incuriosito da una domanda che è venuta dal pubblico e che recitava più o meno così: "è possibile effettuare il cross-page postback in un popup impostando il PostBackUrl?". La risposta naturale è no, ma quest'oggi, per puro diletto ho provato a capire se questo è proprio vero. In effetti se ragioniamo bene sul problema è evidente che esiste almeno un modo di effettuare il postback in una nuova finestra del browser, cioè impostando l'attributo "target" della form. Però impostare questo attributo a runtime mediante javascript è fattibile ma espone ad un fastidioso problema. Il mio primo tentativo è stato quello "semplice" di usare l'evento "OnClientClick" come segue:

btnPopup.OnClientClick = "document.forms[0].target = '_blank';";

Impostare l target in questo modo funziona perfettamente, ma lascia la form in uno stato inconsistente che fa si che tutti i controlli presenti effettuino il postback nella nuova finestra dopo che il pulsante è stato azionato per la prima volta. In effetti la cosa migliore sarebbe quella di ripristinare il target originale dopo il postback, ma in questo l'evento OnClientClick non ci può essere di aiuto perchè il runtime quando fa il merge degli script aggiunge il codice per il postback subito dopo quello immesso in questo attributo. La soluzione perciò è solamente quella di estendere il controllo Button per modificarne il rendering:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Text.RegularExpressions;

namespace Elite.Web.UI.WebControls
{
    
/// <summary>
    /// 
Summary description for ButtonEx
    
/// </summary>
    
public class ButtonEx : Button
    {
        
private string postBackTarget;

        
public ButtonEx()
        { }

        
protected override void Render(HtmlTextWriter writer)
        {
            
if (!string.IsNullOrEmpty(this.PostBackUrl) && 
                !
string.IsNullOrEmpty(this.PostBackTarget))
            {
                
using (StringWriter tempWriter = new StringWriter())
                {
                    
using (HtmlTextWriter htmlWriter = new HtmlTextWriter(tempWriter))
                    {
                        
base.Render(htmlWriter);
                        
                        Regex rx = 
new Regex(
                            @"onclick=""javascript:(?<code>[^""]*)""", 
                            RegexOptions.IgnoreCase);

                        writer.Write(
                            rx.Replace(
                                tempWriter.ToString(), 
                                
new MatchEvaluator(Evaluator)));
                    }
                }
            }
            
else
                base
.Render(writer);
        }

        
private string Evaluator(Match match)
        {
            
return string.Format(
                @"onclick=""javascript:document.forms[0].target='{0}';{1};" + 
                 "setTimeout(&quot;document.forms[0].target=''&quot;, 100);""",
                
this.PostBackTarget, 
                match.Groups["code"].Value);
        }

        
public string PostBackTarget
        {
            
get return postBackTarget; }
            
set { postBackTarget = value; }
        }
    }
}

Il codice è in effetti un po' tirato, lo confesso, ma è davvero l'unico modo che sono riuscito a trovare, dopo aver analizzato la classe Button del framework, per iniettare il codice prima e dopo la generazione del postback. in sostanza nel metodo render viene fatto generare il codice del pulsante in una stringa, e tramite una regular expression si effettua la sostituzione all'interno dell'evento onclick. Questo codice viene poi immesso nuovamente nel flusso del rendering. In questo modo impostando la proprietò PostBackTarget del ButtonEx si otterrà il sospirato postback in popup. L'unica curiosità che rimane è il fatto che ho dovuto usare un timeout di 100 millisecondi per reimpostare il target. Infatti semplicemente impostando la proprietà subito dopo WebForm_DoPostBackWithOptions non si ottiene l'effetto desiderato.

powered by IMHO 1.3

 


per leggere il post originale o inviare un commento visita il seguente indirizzo: ASP.NET 2.0: Postback in a popup