.NET Discussion

.NET Issues, Problems, Code Samples, and Fixes

Visual Studio.NET: How To Comment/Uncomment Large Blocks of Code

Just a quick tip that I find extremely useful: To comment a large block of code (at least for VB.NET, I don’t know if it works in C#, but I assume it does), highlight the area you want to comment out and hold Ctrl and press K and then C. To uncomment, highlight the commented area and hit Ctrl + K + U. The mass uncommenting merely removes the forward-most apostrophe, so if you have actual comments in your commented code that were included in your initial highlighted region, they will remain comments upon uncommenting.

I use this technique a lot for debugging large areas of code.

April 14, 2008 Posted by Some.Net(Guy) | ASP.NET, Tips & Tricks, Visual Studio.NET | | 2 Comments

ASP.NET: How To Use BulkEditGridview To Save Hours In Database Editing

The GridView is a fantastic, versatile, and powerful tool. Unfortunately, it is also unrealistic in several aspects. Say you have a page in your website’s administrative back-end that is to update all of your prices for your products. With a typical GridView, if you wanted to update, say, 10 of these prices, you will require at minimum 20 postbacks, which depending on the speed of your server can be a lengthy process. Now imagine that you have over 1000 lines to edit. 2000 postbacks, minimum… sound like a daunting task that may take you hours in just waiting for your server to respond?

What if I told you that you could edit an unlimited number of records in a GridView with one click, one postback, and one call to your database, and that only the records you modified would be updated? What if I told you it was way, way easier than you think? You may think I am crazy at first if you have any experience with GridViews, but let me introduce you to the panacea of GridView woes, a little tool created by Matt Dotson called BulkEditGridView (more recently moved to this location on CodePlex). I have implemented this tool into nearly every editing application I have that requires a GridView and it has shaved not minutes or hours, but days of off time waiting for the server to post back.

I have been using this tool for quite some time now, but have waited until I had a full understanding of its power and nuances before I posted about it.  The links I provided you will give you more background on the why and how its production came about (and where to download it), but the documentation on its use is a bit on the scattered side. That’s where I come in!

To give you a bit of perspective, the BulkEditGridView is little more than a custom user control that inherits the GridView. However, the functionality it provides is considered more “real world applicable”, because on binding, it places every row in the GridView in Edit mode automatically. You may then either tab through columns or click through records you wish to edit, and then once you’re done with ALL your editing, you click your designated save button and everything is updated! It also knows which rows were edited and stores them in a Generics List Of(GridViewRow) called DirtyRows, which can be accessed programmatically.

Enough already, you say. How do I use it? Here’s a step-by-step of how I have implemented it. Please note that this is how I have implemented it. There may be better ways, but this is how it has worked for me. In this documentation, I am going to assume you have downloaded and installed the .dll for this control.

Step 1: Add BulkEditGridView to your .aspx page

Remember, it is essentially a GridView, so add it like you would to any other page. You may specify bound columns, template columns, or anything of the like the same way you would a regular GridView. The only extra property you must specify is the SaveButtonId property. This is just a button you have placed on your page that when pressed will make the BulkEditGridView work its magic.

Step 2: Add Save Button to page

As mentioned in the previous step, the BulkEditGridView requires that you specify which button is to be pressed for it to run. Any codebehind for this button is not required, but I typically add some catch-all code for when no edits have been made:


Protected Sub btnSaveChanges_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
	If BulkEditGridView1.DirtyRows.Count = 0 Then
		litMsg.Text = "No bulk updates made."
	End If
End Sub

Step 3: Define your RowUpdating Event Handler

This is where all the magic happens. When your Save Button is pressed, if you have any DirtyRows the RowUpdating event will fire for each row in that collection. You should create your RowUpdating event the same way you would for a regular GridView, but include the following modifications:

  1. Declare a Static counter variable (Static count As Integer), and immediately increment it at the beginning of your event handler. This will come in handy later.

  2. Declare a Static sql string variable (Static sql As String) or System.Text.StringBuilder if you are looking to optimize. This is where you will store all of your UPDATE strings for your database so that once you have iterated through all your rows, you may send them to your database to be run all at once. In other words, rather than update your database every time the RowUpdating event is called, return the sql string from your update function that you would typically run and add it on to a growing string of calls to make.

  3. At the end of the RowUpdating event, include some conditional code like:

    
    If count = BulkEditGridView1.DirtyRows.Count Then
    	Dim rowIndexes As New StringBuilder
    	For Each row As GridViewRow In BulkEditGridView1.DirtyRows	'find out which rows were updated
    		rowIndexes.Append(row.RowIndex + 1 & ", " ) 'real count, not 0 based
    	Next
    	rowIndexes.Remove(rowIndexes.Length - 2, 2)	'get rid of final comma
    	msg = "Rows " & rowIndexes.ToString & " have been updated."
    	AddOrUpdateData(sql.ToString) 'your function to call your database
    	BindGridView() 'your function to bind your GridView
    	litMsg.Text = msg
    End If
    

    The preceding code does four things: it checks to see if it has completed running the RowUpdating for each modified row (remember that static count variable?), it iterates back through the DirtyRows so that you may relay back to the user which rows were updated, it updates your database using one call (the AddOrUpdateData function, which is however you call your database to make updates), and it re-binds your GridView. NOTE: when building your SQL string, remember to end your separate UPDATE commands with a semicolon!

Some notes to consider:

  • If you are using template fields, do NOT include controls you wish to modify (textboxes, etc) inside of a Panel control. For some reason it will not detect them. What I did to get around this (if I wanted to display a panel on RowDataBound based on a variable, for instance) is I created two Literals: one where I would want to place the <div style="display:none;"> and one for the closing div tag.

  • At least for me, Intellisense doesn’t work for the BulkEditGridView in the .aspx sourcecode edit mode, so either know your stuff or drop a regular GridView into your page first, build it the way you want, and then copy and paste the guts into a BulkEditGridView once you’re done.

  • Once you update all your items and rebind your BulkEditGridView, it will show up again in edit mode. To toggle this “Bulk Edit” mode, I have sometimes created one BulkEditGridView and one normal GridView on the same page, and then a button to bind and show one and hide the other. For me it has created a seamless user experience and only costs you one postback.

And that’s it! I know this is a long post, but when you get used to using this amazing control, you will see that it boils down to only a few different things you need to change to get it working for you.

kick it on DotNetKicks.com

April 6, 2008 Posted by Some.Net(Guy) | ASP.NET, Generics, GridView, MySQL, Tips & Tricks | | No Comments

ASP.NET: Images in DropDownLists?

I am having a major dilemma; apparently there is no easy way to add images to list items in a DropDownList. This to me seems ludicrous. I would like my user to be able to pick an icon from a dropdown and afterwards be able to grab that value to update my database. I’ve seen it done elsewhere, I just don’t remember where. I’ve seen solutions like EasyListBox, but I’m not about to shell out $100 for this little bit of functionality, and I’ll be damned if I’m gonna stare at their advertisements in their demo version. I’ve also seen people suggest a DHTML (CSS/Javascript) solution from DynamicDrive.com, but I was unable to find any sort of applicable solution.

THERE MUST BE A WAY. Please help!

Status: Unsolved
Solution: None yet.

March 15, 2008 Posted by Some.Net(Guy) | ASP.NET, CSS, Javascript, VB.NET | | 1 Comment

ASP.NET: How to Integrate Both Google Checkout and PayPal In 3 Steps

Trying to get Google Checkout and PayPal to work with a custom .NET site or solution has been a problem for as long as they’ve been around. If you don’t know what you’re doing, it can be a daunting task, and sometimes even if you do know what you’re doing! Well, I am going to take the guesswork out of this chore once and for all, as I have recently discovered the ultimate way to integrate these payment gateways into your website.

If you’re saying, “Wait a second, haven’t you already written an article on this?” you are correct. However, the solution I present to you here is infinitely simpler and requires fewer moving parts. The only reason I didn’t take the previous article down is because it does present interesting information about nesting MasterPages.

The Solution

In their documentation, PayPal and Google Checkout both mention that you must put their code into your site exactly as they have it, using the HTML forms they way they have structured them. This is not true. There are only a few bits of information that are required, and so long as they are present in an acceptable fashion, your pass-off to these gateways will work smoothly and flawlessly.

  1. Get rid of your form tags. That’s right. Lose the form tags. You will only need your <form runat="server"> tag, no more nested HTML forms. W3C compliancy, here we come! However, don’t lose the information contained in your old <form> tag attributes. You’ll still need some of that.

  2. Create image buttons for Google Checkout and PayPal. While they don’t have to be image buttons (for functionality’s sake), both Google and PayPal will get upset if you have standard buttons instead of their images as checkout buttons. It is in this button where the magic happens - the button has a property called PostBackURL. This is where you will put the action string from your form. For instance, PayPal’s PostBackURL value is “https://www.paypal.com/us/cgi-bin/webscr”. Google’s will be “https://checkout.google.com/cws/v2/Merchant/[your merchant number]/checkoutForm”. You can put both Google’s and PayPal’s buttons next to each other. Here is some sample code:
    <asp:imagebutton id="btnSubmitPaypal" runat="server" imageurl="/images/checkout-paypal.gif" alternatetext="Purchase Using Paypal" postbackurl="https://www.paypal.com/us/cgi-bin/webscr" />

  3. Create your hidden inputs to transfer information to PayPal and Google Checkout (from the same page, no extra postbacks!). However you dynamically create your hidden input tags, keep doing it. Just keep this in mind: Google Checkout and PayPal have no tags in common except one, the “item_name_x” (where “x” is a number) tag. If this is the same for both Google Checkout and PayPal, leave it alone and only have one! If you must have two (as I do), make sure you put Google’s tags before PayPal’s. This is important because Google reads the first tags that match what it’s looking for and ignores everything else. PayPal will take the last tag that matches its requirements.

    I mention this because Google Checkout has an “item_description_x” attribute that will take additional information about the item where PayPal does not, meaning that PayPal users have to cram all the info about their product into the “item_name_x” tag. Thus, if you change the order, Google will display double information (PayPal’s “item_name_x” plus their own “item_description_x” tag) and PayPal will display only what you want to transfer to Google Checkout (the last “item_name_x” tag).

  4. BONUS: Hook up Google Analytics. For those advanced users who want to hook up their Google Analytics, you still can using this method. The asp:button element has an attribute called OnClientClick. Put the following as the value for this attribute in your Google Checkout image button: setUrchinInputCode();

For those looking for some sample code on how to dynamically generate your input tags, simply create a literal somewhere on the page and populate it with the following function:

Public Function CreateCheckoutTag(ByVal att As String, ByVal value As String) As String
		Dim input As String = "<input type=""hidden"" name=""" & att & """ value=""" & CleanText(value) & """ />"
		Return input
	End Function

Where the CleanText(value) function cleans any possible special characters from the value. Not necessary, but recommended.And that’s it! Three or four easy steps and you’re ready to use both Google Checkout and PayPal Website Payments on your website! I hope this saves someone 60 or 70 hours of their life, as it would have mine had I known about it three years ago :)

kick it on DotNetKicks.com

February 27, 2008 Posted by Some.Net(Guy) | ASP.NET, Google, MasterPages, PayPal, Tips & Tricks, UpdatePanel | | 9 Comments

ASP.NET: How To Hide Table Rows In An HTML Table

While I am absolutely an advocate of table-less design, tables are still useful when used correctly. For instance, it is correct to use a table to display tabular data, or to show a form. I came across this extremely simple, but not well-known way to show and hide HTML table rows via the server. Say you have a table:

<table>
<tr>
<td>Hello, World!</td>
<tr>
<tr>
<td>Goodbye, World!</td>
<tr>
</table>

If you want to be able to control your rows on the backend, simply make your <tr> a server tag! I know this seems simple, but at first to me, it appeared counter-intuitive. To do this, change your <tr> to read: <tr id="yourID" runat="server">. Then in your CodeFile you can access its properties, such as yourID.Visible!

Very simple, but hey, the best tricks are.

January 31, 2008 Posted by Some.Net(Guy) | ASP.NET, Tips & Tricks | | 1 Comment

ASP.NET and AJAX: Error Making Forms Visible With UpdatePanel

While converting a site to a MasterPage-driven site, I ran across an issue involving UpdatePanels, Panels and Forms. The scenario is that in my MasterPage, I have an UpdatePanel that wraps my ContentPlaceHolder, thereby applying the AJAX functionality to all pages associated with that MasterPage. The content page in question has a panel that is invisible until a button is pressed. The contents of the panel are two non-server forms for PayPal and Google Checkout. Before I converted the site to MasterPages and AJAX, the functionality performed correctly, but afterwards, the site would hang (ie, not complete the server side action), and the browser would produce the Javascript error:

“Unknown runtime error”

I tried many different combinations of contents for the panel, but the only one that seemed to produce the error was whenever a form was present inside the panel. This was very frustrating, as no one around the internet community really seemed to have run across this error, and modifying the MasterPage to account for this single scenario would be a nightmare.

A working solution I came up with for this rare error is to wrap your content (on your .aspx page) with another UpdatePanel and set your triggers to post back when the button is pressed. While the client may have to suffer another postback, it’s not as bad as a total loss of functionality.

If you can find a more elegant solution to this problem, I would love to hear it!

EDIT (2/29/08): I believe the error occurs whenever you are using nested HTML forms within your runat=”server”. If you’re looking to post to another form, please see my article on integrating PayPal and Google Checkout.

January 18, 2008 Posted by Some.Net(Guy) | AJAX, ASP.NET, Errors, Google, Javascript, MasterPages, PayPal, UpdatePanel | | No Comments

ASP.NET: How to Convert Your Site To A MasterPage Site in 3 Steps

Once you have your design converted into HTML/CSS, why should you have to worry about breaking it every time you create a new page? Abstract yourself from this with MasterPages, while still enabling yourself to easily make design changes. MasterPages are wonderful for standardizing your site and your design, in addition to making it easier to maintain and to build new pages. They are a very powerful and easily customizable way to template your site. This article is for those who don’t have much or any experience with MasterPages or are converting an old ASP.NET site to a MasterPage-driven site. If this is you, don’t be afraid—You can do it in just three easy steps!

1. Create a new MasterPage

Right click your project, go to “Add” and then “New Item…” and select MasterPage. Name it something useful, like “main.master” and hit ok. You should be presented with a barebones XHTML skeleton. Notice that your skeleton has this tag in it: <asp:contentplaceholder id="ContentPlaceHolder1" runat="server" />. This is the location where your content will be loaded from your .aspx pages. Fill your new MasterPage with the XHTML that you wish to use on every page. If you want some things to change based on certain variables, you can do so in the codebehind. Treat the MasterPage like any other .aspx page. The only thing different about it (on a basic level) is that it does not contain your content, but rather what encompasses your content.

2. Link your old pages to your MasterPage in the Page Directive

In your <%@ Page directive, add the following attribute: MasterPageFile="~/YourMasterPage.Master"

3. Tell the MasterPage What Content Goes Where

If you only have one ContentPlaceHolder, you will add the following tag around all of your content in your .aspx pages: <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">Hello, World!</asp:Content>, where “ContentPlaceHolder1″ is the ID of the placeholder in your MasterPage that you linked to in step 2. If you have more than one ContentPlaceHolder in your MasterPage, simply wrap the tags around the correlating content.

And that’s it! That’s really all there is to it! Just apply steps 2 and 3 to each of your .aspx pages. There is an optional step for those who may have changed their pages’ codebehind inheritance:

4. Change CodeFile Inheritance

Simply replace whatever inheritance you have with Inherits System.Web.UI.Page

Please read my articles ASP.NET: How To Easily Reference MasterPage Members and my ASP.NET and AJAX: So Freaking Easy series for more tips on how to get yourself set up even better using MasterPages.

kick it on DotNetKicks.com

January 11, 2008 Posted by Some.Net(Guy) | AJAX, ASP.NET, CSS, MasterPages | | 1 Comment

ASP.NET: Dynamically Adding Controls

I am currently undergoing an upgrade on a legacy project trying to bring it into the “Web 2.0 AJAX” era and ran into a problem with dynamically uploading user controls. My perusings of the internet led me to a four-part series by Dave Reed (part of the ASP.NET team) entitled Truly Understanding Dynamic Controls. Even though it was written in 2006 (oh-so-long-ago), I believe that it is a must-read for any ASP.NET developer, even if you think you know how dynamic controls work.

Thanks so much for this article, Dave! It has truly been a lifesaver!

January 4, 2008 Posted by Some.Net(Guy) | AJAX, ASP.NET, Tips & Tricks | | No Comments

ASP.NET: How To Convert An ArrayList To A String Array

Here’s a quick helper post for those looking to convert an ArrayList into a String array. I ran into this problem because I code in VB.NET and the C# code is different.

In VB:


'if you have an ArrayList named data
 Dim str() As String = data.ToArray(GetType(String))

In C#:

//if you have an ArrayList named "data"
string[] strings = (string[])data.ToArray(typeof(string));

Hope this helps!

December 19, 2007 Posted by Some.Net(Guy) | ASP.NET, C#, Tips & Tricks, VB.NET | | 5 Comments

ASP.NET: How To Name A Variable Or Property Using .NET’s “Reserved” Words

Let’s say you want to give your class a boolean property named Error that gets turned on or off if something goes awry in your code. You would think that you can’t do this because the word “Error” is reserved by .NET. However, there is a way. All you have to do is put square brackets around the word! For instance:

Public Property [Error]() As Boolean

Easy, no?

December 13, 2007 Posted by Some.Net(Guy) | ASP.NET, Tips & Tricks | | 2 Comments