views:

288

answers:

3

I have a Page (form) that has many UserControls on it, and I'm trying to have a single button to save everything. The UserControls are actually nested, so I wanted to somehow signal to each UC that it should save itself, instead of somehow wrapping everything into one event or having a single event trigger a cascade of save events.

My plan was to use a static class (props to this answer for the code):

public static class RequestScopedFormData
{
    private const string save_key = "request_form_is_saving";

    public static bool FormIsSaving
    {
        get
        {
            object o = HttpContext.Current.Items[save_key];
            return Convert.ToBoolean(o);
        }
        set
        {
            HttpContext.Current.Items[save_key] = value;
        }
    }
}

Ideally a button on my MasterPage would set RequestScopedFormData.FormIsSaving = true, and as .NET builds the Page and its UserControls, they would know to perform a save on themselves.

The problem I'm having is that I can't get an event to fire early enough in the Page lifecycle to save the UserControls. Even if I move the saving code to the PreRender event, and I move the save ImageButton to the Page itself (instead of the MasterPage), I cannot get the FormIsSaving set to true before the UC saving check.

It happens something like this:

  • Page Page_Load
  • MasterPage Page_Load
  • UC Page_Loads and PreRenders (they are mixed, it prerenders some before it loads others)
  • MasterPage SaveButton_Click event (this is where I set my class variable)
  • MasterPage PreRender
  • Page PreRender

So unfortunately the SaveButton_Click method happens AFTER the UCs are loaded, so they never save.

+3  A: 

CHange your @Page directive to include Trace="true" - this will give you full diagnostics on what is being called and will allow you to identify the best method for the part of the life-cycle you need.

ck
+1 Thanks for the tip.
Jon Smock
Post a comment with which event you need and I'll modify the answer so it has all the info.
ck
The problem is that I can't seem to set that variable before the UC Page_Loads. If I use an ImageButton event to set it, it comes after all the UC Page_Loads (and PreRenders). Is there a way to know which method/event caused the Request/Response?
Jon Smock
Although you don't want to do it, the event cascade might be the best way to do this, it makes sense, even if it is a pain to write
ck
The hard truth. Alright, I guess I need to bite the bullet. Thanks a lot for all your help.
Jon Smock
A: 

Are your controls all derived from the same interface, or could you add a common interface to them?

Then in your save button method you could iterate through all controls on your page, then for the items that match your interface, call the Save method.

E.g.

foreach (Control cntrl in Page.Controls)
{
  if (cntrl is IMySavableControl)
  {
     cntrl.Save();
  }
}
ck
Not sure if that'll work or not, but that's a good idea - thanks again.
Jon Smock
+1  A: 

You can also check if postback was caused by the save button:

Request.Form["__EVENTTARGET"].Contains({YourSaveButton}.UniqueID)

The form variables are available earlier in the page life cycle.

Pawel Krakowiak
This is definitely what I've been looking for...except that my __EVENTTARGET seems to be blank. If I use ck's Trace=true suggestion, I don't see the UniqueID anywhere in the Request.
Jon Smock
Apparently buttons don't set the __EVENTTARGET. http://ryanfarley.com/blog/archive/2005/03/11/1886.aspx for a workaround.
Jon Smock