このような長い質問を投稿することを事前にお詫び申し上げます。信じられないかもしれませんが、ここに表示されているものは、実際には手元にある問題/コードのかなり凝縮されたバージョンを表しています。そして、より良い、または別のアプローチに関する指針をいただければ幸いですが、夜に眠れるように、これを理解したいと思います:)
個別の aspx ページ間で確認メッセージを渡す必要があることに気付きました。クエリ文字列値は「スティッキー」(つまり、後続のすべてのポストバックで持続する) ため、クエリ文字列変数を使用しないことを選択し、これに一連の条件付きロジックを追加することに対処したくありませんでした。
とにかく、Session を使用して通知を特定の URL に関連付ける非常に単純なクラスを考え出しました。次に、マスター ページのPage_Loadイベントをフックして、現在の URL に対して表示する通知をこのクラスに照会します。見つかった場合は、NotificationMessage ユーザー コントロールを動的に読み込み、メッセージ コンテンツを表示します。
異なるaspxページ間で通知を渡そうとすると、すべてが期待どおりに機能します。予想どおり、コンテンツ ページがそれ自体に通知を追加しようとすると、うまくいきません (つまり、「入力したデータが無効です。やり直してください」)。その理由は非常に明確です。コンテンツ ページが自身の通知を追加するまでに、マスター ページのPage_Loadイベントはすでに発生しているため、ページのライフサイクルでは遅すぎて何の役にも立たないからです。関連するコードを以下に貼り付けます。
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);
}
}
上記で言及したライフサイクルを考慮して、現在のページに通知が追加されるたびにイベントが発生するように NotificationManager クラスを変更しました。マスター ページはそのイベントをインターセプトし、Page_Loadが既に発生している場合は、LoadNotifications メソッドを最初からやり直します。
//bind the event on the page constructor
public MyMasterPage()
{
NotificationManager.Instance.NotificationAdded += this.NotificationAdded;
}
private void NotificationAdded(string forUrl)
{
if (_pageLoaded){
LoadNotifications(forUrl);
}
}
残念ながら、これは機能しません。このコードを何度も確認しましたが、マスター ページが NotificationMessage UserControl を読み込み、適切なプレースホルダーに問題なく追加したにもかかわらず、最終的な aspx HTMLにはその UserControl のマークアップが含まれていません。UserControl のPage_Load内にブレークポイントを配置し、実行中に実際にヒットしていることを確認しました。
コンテンツ ページ内から UserControl を動的に読み込み、マスター ページを完全にバイパスすると、問題なくレンダリングされます。
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);
}
}
}
念のため、UserControl の動的読み込みを取り除き、代わりにマスター ページ マークアップでの静的宣言と、コントロールの Visible プロパティのコード ベースの切り替えを選択しました。まだサイコロはありません!
誰かがこの難問に光を当てることができれば、私は大いに感謝します.