CrossPagePostback in new window...

Hey All,

As you may know to postback a page to another page i..e Cross Page Postback you set the PostBackUrl to the page you would like to post the page to. But what if you would like to post back the page and have it open in a new window. I thought easy just set the forms target before it does the postback and presto. But this is not posible as when you overrides the target the nexttime you postback on that page it will still open in a new window and also as the action of the page is overriden for the Cross page postback to work nothing works anymore.

To fix this I knew I had to somehow remember the current action before a postback, change the target, post the form, reset action and target. This has prooved painful. I have created a custom Button control and found that the scripts etc for doing the crosspage postback are added in the AddAttributesToRender method. I have overriden this event and changed it so that it adds the scripts I would like. And then call the base.AddAttributesToRender method. Problem with this is the base method will add its script again, I think the only way to stop this is do a complete override of the AddAttributesToRender method and basically replicate what the current control does. I am just doing this as a test at the moment so am not doing this.

The other trick is to make sure the form is doing a client side script postback, this helps in being able to change the target and reset it back again. Because I originally was not doing this and could not get it working.

The code below works and in my tests I could not find an issue using it. Cross page postbacks in a new window work fine and subsuquent postbacks also work ok. If anyone has any better ideas on howto override this script another way please let me know....

Code:

    public class CustomButton : Button {
        
        protected override void AddAttributesToRender(HtmlTextWriter writer) {
            System.Text.StringBuilder currentScript = new System.Text.StringBuilder();               
           
            // Get the current onclientclick script.
            currentScript.Append(this.OnClientClick);

            // Get the script from our attributes and then remove the onclick
            // attribute.
            if (base.Attributes["onclick"] != null) {
                currentScript.Append(base.Attributes["onclick"]);
                base.Attributes.Remove("onclick");
            }

            // Get postback options, and make sure we are doing a client script submit,
            // this helped in fixing the issue of changing the action and reverting back,
            // granted it needs js but the cross page postback needs js anyway.
            PostBackOptions opt = this.GetPostBackOptions();
            opt.ClientSubmit = true;

            // Get the postback script.
            string postback = this.Page.ClientScript.GetPostBackEventReference(opt, false);
           
            if (postback != null) {              
                               
                if (this.PostBackUrl != string.Empty) {
                    // Remember the current action.
                    currentScript.Append("var oldAction = document.forms[0].action;");
                    // Change target to a new form.
                    currentScript.Append("document.forms[0].target='_blank';");
                }
               
                // Add the postback script.
                currentScript.Append(postback + ";");               
               
                if (this.PostBackUrl != string.Empty) {
                    // Reset target back to self.
                    currentScript.Append("document.forms[0].target='_self';");
                    // Reset the action.
                    currentScript.Append("document.forms[0].action=oldAction;");
                    // Return false to stop page submitting.
                    currentScript.Append("return false;");
                }

            }

            // Add our new onclick attribute.
            if(currentScript.Length > 0)
                writer.AddAttribute("onclick", currentScript.ToString());

            base.AddAttributesToRender(writer); 

        }

        protected override void Render(HtmlTextWriter writer) {
            // Render using our custom decerator which allows us to emit the onclick
            // that the base button control adds...
            base.Render(new ButtonWriter(writer));
        }

        private class ButtonWriter : HtmlTextWriter {
            internal ButtonWriter(HtmlTextWriter writer)
                : base(writer) {
            }
            public override void AddAttribute(HtmlTextWriterAttribute key, string value) {
                if (key == HtmlTextWriterAttribute.Onclick)
                    return;
                base.AddAttribute(key, value);
            }
            public override void AddAttribute(string name, string value) {
                base.AddAttribute(name, value);
            }
        }
       
    }

 

Update:

Thanks to this blog I found on creating a decorator to hook  into rendering:

http://haacked.com/archive/2006/01/18/usingadecoratortohookintoawebcontrolsrenderingforbetterxhtmlcompliance.aspx

I can do something like this:

        private class ButtonWriter : HtmlTextWriter {
            internal ButtonWriter(HtmlTextWriter writer)
                : base(writer) {
            }
            public override void AddAttribute(HtmlTextWriterAttribute key, string value) {
                if (key == HtmlTextWriterAttribute.Onclick)
                    return;
                base.AddAttribute(key, value);
            }           
        }

So when AddAttribute(HtmlTextWriterAttribute key, string value) is called which looking at reflector that is what the base button does I ignore any onclick attribute. In my code I use the AddAttribute(string name, string value) signature so it will still be added. Not perfect yet but closer. And then just override the render method to make use of our new decorator:

 protected override void Render(HtmlTextWriter writer) {
            base.Render(new ButtonWriter(writer));
 }


We now emit the old client script code and only have our custom code. The code above has been updated to reflect the new CustomButton...

---

Thanks 

Stefan 

7 Comments

  • Very helpful article. Could you give a sample of this ?

  • Panos,

    Would you like a sample project? if so send me an email @ stefan.sedich@gmail.com and let me know what you would like and I will try get something to you soon.


    Thanks

    Stefan

  • Hello this should work perfect for your example. Basically your would create the custom button control, add it to your page and set the postbackURL to the page you would like to post to. It would handle posting to a new window. If you would like I could create a control and supply the dll and source code for you. I would create a new button and add a Target property to it. This would allow to set a target for your cross page postbacks apart from _blank.

    Send me an email @ stefan.sedich@gmail.com if you are interested or would like more help with this.


    Thanks
    Stefan

  • Hi,

    Glad to hear it worked. If you are talking about adding javascript to the button when you click on it you could try adding an onclick attribute. Or even setting the OnClientClick property to the javascript you would like to run on click.


    Thanks
    Stefan

  • This code is exactly what we require however I'm unsure how to go about using it. I've been coding in .net for a good few months now and thought I was getting to know most of it quite well but I've got stuck with this one.

    A few simple pointers should do the trick!

    Thanks!!

  • how can i put it running. iam mostly new in this.
    Do i have to make a cs? and then?

    Thank you!

  • Thank you for sharing this solution!
    As my web application is written in VB.Net, I translated your code to VB.Net and it's working just fine.

Comments have been disabled for this content.