Anyname Donotcare
Anyname Donotcare

Reputation: 11393

How to open a page in a new tab in the rowcommand event of gridview?

I have the following code :

protected void gv_inbox_RowCommand(object sender, GridViewCommandEventArgs e)
{
    int index = Convert.ToInt32(e.CommandArgument);

    if (e.CommandName == "sign")
    {
        Session["TransYear"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_TransYear")).Value);
        Session["MailNumber"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_MailNumber")).Value);
        Response.Redirect("Signature.aspx", false);
        //Response.Write("<script>");
        //Response.Write("window.open('Signature.aspx','_blank')");
        //Response.Write("</script>");
    }
}

I want to open the page in a new tab or window . The commented code do that but when refresh the original page cause errors .how to open Signature.aspx in a new window or tab in the correct way in the row command event of my gridview .

Upvotes: 4

Views: 9480

Answers (6)

Amit Bagga
Amit Bagga

Reputation: 648

Why are we using post backs for opening a link in a different window for the URL.

While creating the control link we can embed the values required by signature.aspx on the link control as Querystring and it will be just a simple browser click.

I hope this is simple and clean.

Upvotes: 1

Adrian Salazar
Adrian Salazar

Reputation: 5319

First of all, the exercise here is how to pass simple values from one page to another.

In your case those are only Keys/Values so you can pass them via GET.

You need to render this every row, instead of the command button.

<a href="Signature.aspx?TransYear=value1&MailNumber=value2" target="_blank">
    Sign
</a>

In this example, value1 and value2 are the values that you were writing into HDN_TransYear and HDN_MailNumber respectively.

In Signature.aspx you had to do something like this if you wanted to use the session variables:

Session["TransYear"]
Session["MailNumber"]

Now it should be changed to this:

Request.QueryString["TransYear"]
Request.QueryString["MailNumber"]

That will normally make what you asked for. But...

If you say that this method is insecure, that anyone could play with the querystring variables by changing the parameter values, then...

Compute a signature for each row, put this signature as a third param in your querystring and validate the values and the signature in the other side.

How to compute the signature, well, it is up to you. That's your secret sauce. There are lots of hashing functions and salting algorithms.

As a very simple example:

string signature = CRC32(HDN_TransYear + "stuff that you only know" + HDN_MailNumber)

Then your link should look something like this:

<a href="Signature.aspx?TransYear=2012&MailNumber=1&sig=8d708768" target="_blank">
    Sign
</a>

In Signature.aspx you use the values from the querystring and the "stuff you only know" to calculate the CRC32 signature again and validate against the signature passed as parameter in the querystring.

No dramas.

Upvotes: 4

andri
andri

Reputation: 1021

Why do you want to set the session before opening the new window?

If setting the session after opening the new window is okay, I think you can do it in the code behind of Signature.aspx, considering you have the required parameters passed as query strings as @David pointed out.

Upvotes: 2

DiskJunky
DiskJunky

Reputation: 4971

We've used the following code successfully for some number of years now. These several methods are extracted out of a larger general-purpose module but I think I've included everything...

public class Utilities
{
    /// <summary>
    /// This will return the first parent of the control that is an update panel
    /// </summary>
    /// <param name="source">The source control</param>
    /// <returns>The first parent found for the control. Null otherwise</returns>
    public static UpdatePanel GetFirstParentUpdatePanel(Control source)
    {
        Page currentPage = source.Page;
        UpdatePanel updatePanel = null;
        Type updatePanelType = typeof(UpdatePanel);
        object test = source.Parent;
        while (test != null && test != currentPage)
        {
            // is this an update panel
            if (test.GetType().FullName == updatePanelType.FullName)
            {
                // we've found the containing UpdatePanel
                updatePanel = (UpdatePanel)test;
            }

            // check the next parent
            test = ((Control)test).Parent;
        } // next test

        return updatePanel;
    }

    /// <summary>
    /// This will open the specified url in a new window by injecting a small script in
    /// the current page that is run when the page is sent to the client's browser.
    /// This method accounts for the presence of update panels and script managers on the
    /// page that the control resides in.
    /// </summary>
    /// <param name="source">The control that the call is being made from</param>
    /// <param name="url">The URL to bring up in a new window</param>
    public static void RedirectToNewWindow(Control source, string url)
    {
        // create the script to register
        string scriptKey = "_NewWindow";
        string script = "window.open('" + url + "');";
        RegisterControlScript(source, scriptKey, script);
    }

    /// <summary>
    /// This will register a script for a specific control accounting for the control's UpdatePanel
    /// and whether or not there is a script manager on the page
    /// </summary>
    /// <param name="source">The control that will be affected by the script</param>
    /// <param name="scriptKey">A unique key for the script</param>
    /// <param name="script">The script that will affect the control</param>
    public static void RegisterControlScript(Control source, string scriptKey, string script)
    {
        // get the control's page
        Page currentPage = source.Page;

        // does the control reside in an UpdatePanel
        UpdatePanel updatePanel = GetFirstParentUpdatePanel(source);

        // did we find the UpdatePanel
        if (updatePanel == null)
        {
            // register the script on the page (works outside the control being in an update panel)
            currentPage.ClientScript.RegisterStartupScript(currentPage.GetType(), scriptKey,
                                                           script, true /*addScriptTags*/);
        }
        else
        {
            // register the script with the UpdatePanel and ScriptManger
            ScriptManager.RegisterClientScriptBlock(source, source.GetType(), scriptKey,
                                                    script, true /*addScriptTags*/);
        } // did we find the UpdatePanel
    }
}

Then, for you're usage, you'd call

protected void gv_inbox_RowCommand(object sender, GridViewCommandEventArgs e)
{
    int index = Convert.ToInt32(e.CommandArgument);

    if (e.CommandName == "sign")
    {
        Session["TransYear"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_TransYear")).Value);
        Session["MailNumber"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_MailNumber")).Value);
        Utilities.RedirectToNewWindow(gv_inbox, "Signature.aspx");
    }
}

Not the most concise code as I've extracted these helper methods but you get the idea. The code above will work on c#2.0 and up and will work regardless of UpdatePanel nesting or even if no UpdatePanels are used at all

Upvotes: 2

Jesse
Jesse

Reputation: 8759

What you want to do is use the ScriptManager to make the JavaScript call.

The JavaScript snippet you had defined works, however, you need the ScriptManager to take care of executing it for you.

String js = "window.open('Signature.aspx', '_blank');";
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Open Signature.aspx", js, true);

The issue with using Response.Write is that during PostBack, the browser will not execute script tags. On the other hand, when using ScriptManager.RegisterClientScriptBlock, the ASP.NET ScriptManager will execute the code automatically.

UPDATE - 2013/02/14

As suggested in Vladislav's answer, use ClientScript vs. ScriptManager; the difference is ClientScript is for synchronous postbacks only (no asp:UpdatePanel), and ScriptManager is for asynchronous postbacks (using asp:UpdatePanel).

Additionally, per the author's comment below - enclosing the asp:GridView in an asp:UpdatePanel will eliminate the browser message confirming a refresh. When refreshing a page after a synchronous postback (no asp:UpdatePanel), the browser will resend the last command, causing the server to execute the same process once more.

Finally, when using an asp:UpdatePanel in conjunction with ScriptManager.RegisterClientScriptBlock, make sure you update the first and second parameters to be the asp:UpdatePanel object.

ScriptManager.RegisterClientScriptBlock(updatePanel1, updatePanel1.GetType(), "Open Signature.aspx", js, true);

Upvotes: 5

Vladislav
Vladislav

Reputation: 2982

I would rather use ClientScript.RegisterStartupScript(this.GetType(), "Open Signature.aspx", js, true); and you don't need to refresh your page. The script block will fire after the page has recovered from the postback.

And just a suggestion: - is it possible in your case to use DataKeys to retrieve values for TransYear and MailNumber instead of using HiddenFields

Upvotes: 2

Related Questions