2009-08-25 9 views
0

Ich entschuldige mich im Voraus für das Posten einer so langen Frage. Ob Sie es glauben oder nicht, das, was Sie hier sehen, stellt tatsächlich eine ziemlich verkürzte Version des Problems/Codes zur Verfügung. Und während ich alle Hinweise auf einen besseren oder anderen Ansatz schätzen würde, würde ich auch sehr gerne den Grund dafür, dass ich nachts schlafen kann :)Laden von Steuerelementen außerhalb von Page_Load ist ein No-No?

Ich kam zu einer Anforderung, um Bestätigungsmeldungen zwischen verschiedenen übergeben Aspx Seiten. Ich habe mich gegen die Verwendung einer Query-String-Variable entschieden, da die Werte der Query-Zeichenfolge "sticky" sind (d. H. Sie bleiben bei allen nachfolgenden Postbacks bestehen), und ich wollte mich nicht damit befassen, eine Menge Bedingungslogik hinzuzufügen.

Wie auch immer, ich habe eine sehr einfache Klasse entwickelt, die Session verwendet, um Benachrichtigungen bestimmten URLs zuzuordnen. Ich hakte dann meine Masterseite Page_Load Ereignis, um diese Klasse für alle Benachrichtigungen abzufragen, die für die aktuelle URL angezeigt werden sollten. Wenn dies gefunden wird, lädt es dynamisch ein NotificationMessage-Benutzersteuerelement und zeigt den Nachrichteninhalt an.

Alles funktioniert wie erwartet beim Übergeben von Benachrichtigungen zwischen verschiedenen Aspx-Seiten. Wie vorauszusehen ist, funktionieren die Dinge nicht, wenn eine Inhaltsseite versucht, sich selbst eine Benachrichtigung hinzuzufügen (z. B. "Die von Ihnen eingegebenen Daten sind nicht gültig, versuchen Sie es erneut"). Der Grund ist ziemlich klar: Zu dem Zeitpunkt, zu dem eine Inhaltsseite eine Benachrichtigung für sich selbst hinzufügt, ist das Ereignis Page_Load der Masterseite bereits ausgelöst worden, sodass es im Seitenlebenszyklus zu spät ist, etwas Gutes zu tun. Der entsprechende Code wird unten eingefügt.

public class MyMasterPage:MasterPage{ 

    protected void Page_Load(object sender, EventArgs e) 
    { 
     LoadNotifications(this.Request.Url.ToString()); 
    } 


    private void LoadNotifications(string url) 
    { 
     //look for a notification 
     Notification? notification = NotificationManager.Instance.RetrieveNotification(url); 

     //there are no notifications, nothing to see here 
     if (!notification.HasValue) 
     { 
      return; 
     } 

     //there is a Notification for this url, so load it into a user control 
     NotificationMessage notificationMessageControl = (NotificationMessage)LoadControl("~/App_UserControls/NotificationMessage.ascx"); 
     notificationMessageControl.ID = "notificationMessage"; 
     notificationMessageControl.Notification = notification; 
     notificationMessageControl.Visible = true; 

     //find the placeholder on the master page 
     PlaceHolder placeHolder = (PlaceHolder)PageUtils.FindControlRecursive(this, "NotificationPlaceholder"); 

     if (placeHolder == null) 
     { 
      throw new ApplicationException("NotificationPlaceholder control not found."); 
     } 

     //insert into control 
     placeHolder.Controls.Add(notificationMessageControl); 
     placeHolder.Visible = true; 

     //remove the notification so it doesn't show up next time 
     NotificationManager.Instance.RemoveNotification(url); 


    } 

} 

In Anbetracht des oben ausgegebenen Lifecycles erwähnt, modifizierte ich die NotificationManager Klasse, so dass es ein Ereignis auslöst, wenn eine Benachrichtigung für die aktuelle Seite hinzugefügt wurde. Die Masterseite fängt dieses Ereignis ab, und wenn die Page_Load bereits ausgelöst wurde, wird die LoadNotifications-Methode erneut gestartet.

//bind the event on the page constructor 
    public MyMasterPage() 
    { 
     NotificationManager.Instance.NotificationAdded += this.NotificationAdded; 

    } 

    private void NotificationAdded(string forUrl) 
    { 
     if (_pageLoaded){ 
      LoadNotifications(forUrl); 
     } 
    } 

Leider funktioniert das nicht. Ich bin diesen Code mehrere Male durchgegangen, und trotz der Tatsache, dass die Masterseite das NotificationMessage UserControl lädt und es dem entsprechenden Platzhalter ohne Zwischenfall hinzufügt, enthält das endgültige aspx HTML nie das Markup für dieses UserControl. Ich habe Haltepunkte innerhalb der Page_Load des UserControl gesetzt und verifiziert, dass sie tatsächlich während der Ausführung getroffen werden.

Wenn ich aus dem Inneren der Inhaltsseite und umgehen die Master-Seite ganz dynamisch die Usercontrol laden, es ohne Probleme macht:

public partial class MyContentPage:Page 
{ 

    public void DoSomethingCool(object sender, EventArgs e) 
    { 
     if (MyServiceLayer.Save(foo)==false){ 
      Notification notification = new Notification(NotificationType.Error, "We’re sorry, your document was not saved."); 
      NotificationMessage notificationMessage = (NotificationMessage)LoadControl("~/App_UserControls/NotificationMessage.ascx"); 
      notificationMessage.Notification = notification; 
      notificationMessage.Visible = true; 
      PlaceHolder holder = (PlaceHolder)PageUtils.FindControlRecursive(this, "NotificationPlaceholder"); 
      holder.Controls.Add(notificationMessage); 
     } 
    } 
} 

Für das Protokoll, zog ich die dynamische Belastung des Usercontrol aus, die Entscheidung stattdessen für eine statische Deklaration im Masterseiten-Markup und einen code-basierten Toggle der Visible-Eigenschaft des Steuerelements; noch kein Würfel!

Wenn jemand etwas Licht auf dieses Rätsel werfen könnte, wäre ich sehr verpflichtet.

Antwort

2

Ich habe diese Art der Sache schon einmal ausprobiert und ich war nie völlig damit zufrieden. Was ich stattdessen getan habe, war meine ASCX auf jeder Seite (oder auf der Masterpage), und lassen Sie die ASCX seinen Zustand steuern, anstatt die ASPX mein ASCX steuern lassen.

Ich bin mir nicht sicher, dass dies für Ihre Situation jedoch helfen wird.

+0

+1 für gutes Design Sounds – David

+0

faszinierend. Können Sie vielleicht ein Beispiel geben? –

1

Es scheint, als wollten Sie, dass Ihre Informationen nach den Kontrollereignissen angezeigt werden. Sie könnten in Betracht ziehen, diese Nachrichten aggregieren zu lassen, bis alle Kontrollereignisse ausgelöst wurden, und dann alle Nachrichten von Ihrem NotificationManager in OnPreRender anstatt Page_Load herauszunehmen. Auf diese Weise können Sie die Ereignisse (wie NotificationAdded) usw. loswerden, die wahrscheinlich die Angelegenheit komplizieren.

Nicht 100%, was das Problem ist, obwohl. Es hilft manchmal zu wissen, dass die MasterPage tatsächlich eine Kontrolle auf der Seite ist, und nicht umgekehrt, wie Sie denken würden. Es unterliegt den Beschränkungen, die eine Kontrolle auf einer Seite haben würde.

HTH, Anderson