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.
+1 für gutes Design Sounds – David
faszinierend. Können Sie vielleicht ein Beispiel geben? –