Ketone Cops

August 21, 2009

Modal Popup with Progress

Filed under: Ajax,ASP.NET 2.0,Javascript,programming — delroger @ 12:42 pm

I was interested in using a Modal Popup to prevent trigger-happy clicking by impatient users when my web app was doing a processing job for a few seconds.  I came across Matt Berseth’s excellent work here http://mattberseth.com/blog/2007/07/modalpopup_as_an_ajax_progress.html and decided that it would be useful to make a class file for Sample 3 on that page.  So here it is…

This assumes that you have a modal popup extender and a panel on your page that will display the animated gif.  This is the code for mine (almost identical to Matt Berseth’s):

<ajaxToolKit:ModalPopupExtender
ID=”mdlPopup” runat=”server” TargetControlID=”pnlPopup”
PopupControlID=”pnlPopup” BackgroundCssClass=”modalBackground”  />
<asp:Panel ID=”pnlPopup” runat=”server” CssClass=”updateProgress” style=”display:none”>
<div align=”center” style=”margin-top:13px;”>
<img src=”Images/ajax-loader.gif” />
<span>Processing…</span>
</div>
</asp:Panel>

The class file then looks like the code below. It contains one Sub that takes the name of your modal popup and the delay before displaying it (in milliseconds) as parameters, injecting the necessary javascript into your page for displaying the modal popup/progress when processing is occurring.

Public Class clsModalProgress
Public Shared Sub DoModalProgress(ByVal mdl As AjaxControlToolkit.ModalPopupExtender, ByVal delay As Integer)
Dim pg As Page = HttpContext.Current.Handler
If Not pg Is Nothing Then
If Not pg.ClientScript.IsStartupScriptRegistered(“progressScript”) Then
Dim t As Type
t = pg.GetType()
pg.ClientScript.RegisterStartupScript(t, “progressScript”, _
“Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequest);” & Environment.NewLine & _
“Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);” & Environment.NewLine & _
“var count;” & Environment.NewLine & _
“function beginRequest(sender, args){” & Environment.NewLine & _
”  count = setTimeout(“”showProgress()””, ” & delay & “);” & Environment.NewLine & _
“}” & Environment.NewLine & _
“function showProgress(){” & Environment.NewLine & _
”  $find(‘” & mdl.ClientID & “‘).show();” & Environment.NewLine & _
“}” & Environment.NewLine & _
“function endRequest(sender, args) {” & Environment.NewLine & _
”  clearTimeout(count);” & Environment.NewLine & _
”  $find(‘” & mdl.ClientID & “‘).hide();” & Environment.NewLine & _
“}”, True)
End If
End If
End Sub
End Class

You can simply call it in the Page_Load or Page_Prerender subs like this:

clsModalProgress.DoModalProgress(mdlPopup, 100)

In this case, the modal popup will display if processing take longer than one-tenth of a second.

February 10, 2009

Programmatically open and close Accordion Panes

Filed under: Ajax,ASP.NET 2.0 — delroger @ 1:47 pm

If you have an AJAX page in ASP.NET that contains an Accordion control, you may find you want to open and close the different panes from events other than clicking on the header. You can set the SelectedIndex property of the Accordion in your code-behind, but this does not use smooth transitions. However, you can use javascript to invoke the set_SelectedIndex method, which will contract the currently-expanded pane and expand the new one. Tip 3 on this page…

http://www.dotnetcurry.com/ShowArticle.aspx?ID=215

…shows you how to do that.

However, if you are using Master pages, the ID of the Accordion control will be different and so you will need to set this programmatically in code. Create a Sub like this…

Private Sub AccordionTransition()
If Not Page.ClientScript.IsClientScriptBlockRegistered(“changeSelectedScript”) Then
Dim t As Type
t = Me.GetType() ‘type of page
Page.ClientScript.RegisterClientScriptBlock(t, “changeSelectedScript”, _
”  function changeSelected(idx) {” & Environment.NewLine & _
”   $find(‘” & Me.MyAccordion.ClientID & “_AccordionExtender’).set_SelectedIndex(idx);” & Environment.NewLine & _
“}”, True)
End If
End Sub

… and then call this sub in your Page_Load. Note that my Accordion control is called ‘MyAccordion’ and will need to be changed, or you can make this sub more generic and pass the control ID in like this:

Private Sub AccordionTransition(ByVal ctlAccordion As WebControl)
If Not Page.ClientScript.IsClientScriptBlockRegistered(“changeSelectedScript”) Then
Dim t As Type
t = Me.GetType() ‘type of page
Page.ClientScript.RegisterClientScriptBlock(t, “changeSelectedScript”, _
”  function changeSelected(idx) {” & Environment.NewLine & _
”   $find(‘” & ctlAccordion.ClientID & “_AccordionExtender’).set_SelectedIndex(idx);” & Environment.NewLine & _
“}”, True)
End If
End Sub

Finally, to use this on your webpage, you will need to add an OnClientClick event to whichever control(s) you want to invoke the Accordion expension/contraction. So for instance, with a button you would need:

<asp:Button ID=”Button1″ runat=”server” Text=”Accordion Change” OnClientClick=”changeSelected(1); ” />

The number that is passed into the changeSelected function is the index of the accordion pane you wish to expand. The selected pane expands and any further processing you have set up for that button will continue in the code-behind. If you did not want anything else to occur in the code-behind, you would return a false event value in the click event as well:

<asp:Button ID=”Button2″ runat=”server” Text=”Accordion Change” OnClientClick=”changeSelected(1); event.returnValue=false; return false;” />

Finally, you can also set up the click event in the code behind by adding attributes to the control at Page_Load, such as:

Button2.Attributes.Add(“onclick”, “javascript: changeSelected(1);”)

This could give you more control, for instance if you were using a gridview and wanted to set particular actions for each row.

August 19, 2008

Invalid character in a Base-64 string (ASP.NET)

Filed under: ASP.NET 2.0,programming — delroger @ 11:16 am

Just came across a very peculiar problem with a website I’m developing. Some visitors to the website hit an error every time they click one of the controls on a particular page; the page loads fine the first time, but any sort of postback triggers the error. The message is:

Invalid character in a Base-64 string

and the stack trace is:

at System.Convert.FromBase64String(String s) at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) at System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState) at System.Web.UI.HiddenFieldPageStatePersister.Load()

The problem seems to be with the ViewState. The ViewState is encrypted, and when an attempt is made to decrypt it on postback, the error is triggered.  The solution is actually quite simple: in the web.config file, set the ViewState not to be encrypted, like this:

<system.web>
 <pages viewStateEncryptionMode=”Never”>
 </pages>
</system.web>

 

OK, the error is no longer produced, but why is it there in the first place?  The page works perfectly well for some visitors, but not others – and that’s when the setup is exactly the same (Windows XP, IE 7) and the same requests are going to the server.  So what’s in the ViewState for different users that is creating the problem?  Still trying to find out…

As an addendum to this post one week on, I did work out why the encryption of the ViewState was a problem.  There was quite a lot of data being stored in the ViewState: above a certain length the ViewState decryption cuts off, and therefore the string doesn’t appear like a valid one for decryption.  You can solve this by splitting the ViewState into several sections using the MaxPageStateFieldLength in the pages tag in web.config – see this post for instance:

http://weblogs.asp.net/lduveau/archive/2007/04/17/viewstate-chunking-in-asp-net-2-0-maxpagestatefieldlength.aspx

Therefore, if you want to maintain encryption on your ViewState, that’s a slightly better solution for you. Personally, I’m not convinced it matters greatly since if someone wants to decrypt your ViewState, it is trivial enough to do anyhow (see here http://www.pluralsight.com/community/media/p/51688.aspx for instance).

August 6, 2008

Creating javascript alerts in ASP.NET with UpdatePanel (or without)

Filed under: Ajax,ASP.NET 2.0,Javascript,programming,UpdatePanel — delroger @ 8:33 pm

Just thought I’d share a couple of simple methods for creating javascript alert messages from an ASP.NET webpage, both when you are using AJAX (and an update panel) or just from a standard page.

In a standard page, you can easily create an alert message in the code-behind like this: 

ClientScript.RegisterClientScriptBlock(Me.GetType(), “yourkeyname”, “alert(‘hello’);”, True)

The parameters that are passed in are the System.Type (the Page type in this case), an arbitrary name for your script ‘key’, the javascript itself as a string, and a boolean indicating whether to add the script tags – i.e., <script type=”javascript”></script> – which you might as well use since it shortens the script itself.

Likewise, creating an alert when you are using an UpdatePanel is slightly different, but simpler than you might think – you just need to make sure the System.Type is the UpdatePanel type, and use the ScriptManager rather than the ClientScript like so:

ScriptManager.RegisterStartupScript(Me.UpdatePanel1, Me.UpdatePanel1.GetType(), “yourkeyname”, “alert(‘hello’);”, True)

This is much the same as before except you are passing in the ID of your UpdatePanel along with the other parameters.

Now, since this is code that you are likely to want to re-use throughout an application, it makes sense to create a Class file for it with a couple of generic methods, like this:

Imports Microsoft.VisualBasic
Imports System.Web
Imports System.Web.UI
Public Class Messages
    Public Shared Sub CreateMessageAlertInUpdatePanel(ByVal up As UpdatePanel, ByVal strMessage As String)
        Dim strScript As String = “alert(‘” & strMessage & “‘);”
        Dim guidKey As Guid = Guid.NewGuid()
        ScriptManager.RegisterStartupScript(up, up.GetType(), guidKey.ToString(), strScript, True)
    End Sub
    Public Shared Sub CreateMessageAlert(ByVal strMessage As String)
        Dim guidKey As Guid = Guid.NewGuid()
        Dim pg As Page = HttpContext.Current.Handler
        Dim strScript As String = “alert(‘” & strMessage & “‘);”
        pg.ClientScript.RegisterStartupScript(pg.GetType(), guidKey.ToString(), strScript, True)
    End Sub
End Class

(We’re just using the Guid for the script key to ensure a new key each time we create an alert)

And that’s it! You can now create alert messages from any of your webpages simply by using:

CreateMessageAlertInUpdatePanel(Me.UpdatePanel1, “hello”)
or

CreateMessageAlert(“hi”)

July 31, 2008

Using the Clipboard to copy and paste files in ASP.NET

Filed under: ASP.NET 2.0,programming — delroger @ 9:27 pm

Before I start, I must admit I’m not entirely convinced this is a particularly useful thing to try and do, since you can accomplish the same results using System.IO and the various File methods, but anyway…

I guess I was trying to see if this was possible or not in a webpage, rather than in a Windows form – to copy a file (or files) to the server clipboard and then paste them in another location. So here’s how it’s done:

Let’s assume you have a Gridview where you have a list of files that the user can access, and they want to move them from one directory to another. They can tick a checkbox in each gridview row for the file, then click a button to ‘Copy Files’ and another button to ‘Paste Files’ to another directory.

In the code-behind, we have a Property set up called ClipboardFiles which uses a string array as its value, like this:

Property ClipboardFiles() As String()
        Get
            Dim o As Object = ViewState(“ClipboardFiles”)
            If o Is Nothing Then
                Return Nothing
            Else
                Return o
            End If
        End Get
        Set(ByVal value As String())
            ViewState(“ClipboardFiles”) = value
        End Set
    End Property

Now when the user clicks the button to Copy Files, all selected files are added to ClipboardFiles. Of course there are lots of ways you might get the names and paths of the files; in this case, I had a function that was returning an ArrayList (named ‘al’ here) of the complete path and name of the files. I then cast the ArrayList to a string array and set the ClipboardFiles property like this:

Dim strFiles As String() = CType(al.ToArray(GetType(String)), String()) 
ClipboardFiles = strFiles

Here’s the tricky bit: when the user clicks the button to Paste Files, we have to use Threading and set the Apartment State of the thread. There is a sub called PasteFiles, which we will reference in the button click, like this:

(note: needs Imports System.Threading)

Protected Sub imgPasteFile_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles imgPasteFile.Click
        Dim pasteThread As Thread = New Thread(New ThreadStart(AddressOf PasteFiles))
        pasteThread.SetApartmentState(Threading.ApartmentState.STA)
        pasteThread.Start()
        pasteThread.Join()
    End Sub

Finally, the PasteFiles sub looks like the code below. It copies the files listed in the ClipboardFiles to the Clipboard, then pastes them in a location of your choice (in this case ‘C:\Temp’, but you’d almost certainly set this programmatically).

(note: needs Imports System.Windows.Forms)

Private Sub PasteFiles()
        ‘copy files to clipboard
        If Not ClipboardFiles Is Nothing Then
            Try
                Clipboard.SetDataObject(New DataObject(DataFormats.FileDrop, ClipboardFiles))
            Catch ex As Exception
                ‘your error handler
                Exit Sub
            End Try
        End If

        ‘paste to new location
        Try
            Dim iData As IDataObject = Clipboard.GetDataObject()
            If iData.GetDataPresent(DataFormats.FileDrop) Then
                Dim clipbrd As String() = DirectCast(iData.GetData(DataFormats.FileDrop), String())
                For Each strFile As String In clipbrd
                    System.IO.File.Copy(strFile, “C:\Temp\” & System.IO.Path.GetFileName(strFile))
                Next
            End If
        Catch ex As Exception
            ‘your error handler
        End Try
       
    End Sub

This code was put together from a few snippets I found here and there, including this:

http://www.telerik.com/community/forums/thread/b311D-dcdga.aspx

and this:

http://bytes.com/forum/thread356140.html

Like I said, I’m not entirely sure how useful it really is, but it may give someone an idea about how to accomplish something similar using the Clipboard functionality. If so, glad to have helped…

Next Page »

Blog at WordPress.com.