.NET Discussion

.NET Issues, Problems, Code Samples, and Fixes

Shameless Plug: Quotidian Word

The site is now live! Check it out: http://www.quotidianword.com. For those who know me, you know that I am a perfectionist and that I pour every ounce of me into whatever project I’m in. This site is no exception. It has some very cool technical features as well as simply just being easy, fun, and actually educational if you use it right. My favorite feature is the dynamic signature bar that you can drop in a forum signature:

QuotidianWord.com

You should see that this image will change every day, staying current with the current word. It’s a cool way to keep your signature fresh and interesting (at least I think so ūüôā ) Anyways, I hope you enjoy using the site as much as I do, and as much as I enjoyed making it!

June 22, 2009 Posted by | ASP.NET, Portfolio | , , , | 3 Comments

jQuery: Awesome

Back in the day, I discovered jQuery, but never really did anything with it. I always wanted to learn, but really never had the time. I do now. Let me tell you something:

jQuery is friggin awesome.

Let me preface with the fact that I know little to no JavaScript. I once wrote one function to add the current date to a textbox in JS and it took me around half the day. However, in that same amount of time about two weeks ago, I was able to nearly completely understand how jQuery works. After a week, I was helping out others with their problems.

Don’t get me wrong, jQuery can’t do everything, but it sure can do some powerful stuff. For instance, AJAX is a breeze. For one project I had to make an AJAX call to check to see if someone was posting a comment as someone else while logged in as themselves, so I had to write my AJAX function myself. It took me 53 lines of JS and maybe 3 days to get it working right (along with a TON of research). When I wanted to apply that same function to my new project, I thought I would give jQuery a chance.

Eight lines of code. Actually, technically one line of code because I broke it into several lines:

function MakeCall(url,doAsync,callback) {
$.ajax({
url: url,
async: doAsync,
dataType: "text",
success: callback
});
}

Of course I have to handle the “callback” in the function that’s calling the MakeCall() function, but the actual making the call has been reduced by 85%. And it’s easier to maintain and reuse! This isn’t all that jQuery is good for. I believe jQuery’s strongest feature is its document manipulation. If you want to change something, all you have to do is select the element or class and, well, change it. For instance, if you have a div with an id of “myDiv”, to change the CSS class on it, you just do:

$("#myDiv").addClass("someClass");

Really, that’s it. If you wanted to do that when something is clicked, you could do:

$("#myLink").click(function () { $("#myDiv").addClass("someClass"); });

No, for real. That’s all you have to do. You can also manipulate things on page load:

$.(document).ready( function () { //run functions here });

The last and I think one of the most important aspects of jQuery is that it is VERY well documented, VERY ardently followed, and VERY well supported. You can even get Intellisense in Visual Studio 2008! I couldn’t possibly go through all the cool stuff that jQuery can do. You’ll have to see for yourself. It truly is amazing, and it is, as I was told, “brain-dead-stupid easy to learn”.

June 12, 2009 Posted by | AJAX, CSS, Javascript, jquery, Tips & Tricks, Visual Studio.NET | 1 Comment

My Foray into Regular Expressions with ASP.NET

I know it’s been a while since I posted here. I’ve been working pretty diligently on my newest creation, Quotidian Word, which will essentially be a “word-a-day” site that encourages users to actually learn the word and use it actively in everyday speech or writing. Right now it’s only an email harvester so that I can send an email to those interested when it’s ready, but I’m nearing the launch point every day ūüôā

Anyways, the point of this post is to discuss my dip into the world of Regular Expressions. I needed to come up with a way to find the word I wanted in a sentence. Easy enough, right? Just mySentence.Contains("myword") and there you go. It would be nice if that’s all I had to do, but English is a funny language. Every word can assume many forms. For instance, if I want to find the word “entry” in a sentence, I also would like to find “entries”. Or more simply, if i’m looking for “dog” I also want to find “dogs”. Using the mySentence.Contains() method, I would not find “entries” and I would find only the “dog” in “dogs”.

Enter regular expressions.

I had previously shied away from them because when one looks at a regular expression (aka “regex”), it can be rather intimidating. Take this stock regular expression that comes with Visual Studio as a default for finding an email address:

\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

Your reaction may be the same as mine was: WTF. But when you try to enter an email in a textbox validated by this regex, it knows if you are or not. So my problem was still, how do I find all forms of any word I choose? I took a couple factors into mind, such as, I will mostly be using more obscure words with less common roots, so that will help a bit, and I won’t be using too many really short words that can be blended into other words in a sentence.

My first thought was ok, how about I first try to find the whole word, then the whole word plus a suffix, then the whole word minus a letter plus a suffix, then a the whole word minus two letters plus a suffix:

\bentry\b|((\bentry|\bentr|\bent)(s|es|ies)\b)

I used the word “entry” as an example here. “\b” means either the beginning or the end of a word and “|” means “or”. The rest is just separated by parens. This worked out ok for a while until I realized that the English language has something like a thousand suffixes. I knew regexes were more powerful than that. There had to be an easier way.

And there was! I was sort of on the right track with the losing of the last two letters. In English, most words either simply append a suffix (dog -> dogs), drop one letter and append a suffix (happy -> happiness) or drop two letters and append a suffix (cactus -> cacti). Aside from the word “person” (person -> people) I could not think of an instance where a word dropped three or more and would profide me with enough remaining information to actually distinguish it from other words in the sentence. If you can, let me know.

So after a bit more research, and the testing from a handy regex tool called Expresso, my regex eventually evolved into: (?:ent(?:r|ry)?).+?\b

Explanation: “ent” is what I called the “root” of the word, essentially the letters remaining after the last two have been stripped off. “(?:” is a grouping that means “find whatever’s here, but don’t actually match it alone”. This way it doesn’t find only “ent” or “r” or “ry” and match it, but rather matches the whole thing all together. The clause “(?:r|ry)?” means find “r” OR “ry” (in addition to what comes before it, so “entr” or “entry”). The “?” at the end means the whole clause before it is optional, meaning if it’s not there, it’s ok. The “.+” means find any character after the previous clause for as many repetitions as you can, so for instance, if the word in the sentence is “entries” it will first find the “ent” then the “r” then any characters that follow “ies” up until the end of the word, “\b”. The “?” at the end of the “.+” just means take as few characters as possible up to the next clause, which is the “\b”.

Whew! That’s a lot. I found that this found about 99% of the words that I would be using in all their various forms. But then I got to thinking, what about prefixes? What if someone used something like “anti” or “pre” or something in front of a word to change it just slightly? Hence, my (nearly) final product:

(?:(?:\b\w+)?{1}(?:{2}|{3})?).+?\b

where {1} is the word minus the last two letters, {2} is the penultimate letter, and {3} is the last two letters. The optional clause at the beginning takes care of any prefix if it happens to exist.

Great! All done. It can pull it out of a string, no problem. Now if someone enters the word in a sentence in my textbox it will find…it… crap. It doesn’t work as is with the RegexValidator in ASP.NET on textboxes. Why? Because the validator is looking at the whole string in the textbox to see if it fits the regular expression. For instance, the email regular expression assumes that whatever you enter into that textbox is going to be an email, nothing else. If you enter a sentence into a textbox, it assumes that whatever you enter into that textbox is going to fit the regex.

In order to counter this problem, I put in a simple fix: I prepended and appended my regex for textboxes with “.*”, which means that it will find any characters before or after the word we’re looking for. Done! … Right?

So I thought, until I realized that when people enter sentences, usually they do so in multiline textboxes, as they’re easier to see everything you’re doing. This regex works until the user hits the “Enter” key and inserts a new line. After much research and hair pulling, I eventually found the solution:

^(.|\r|\n)*(?:(?:\b\w+)?{1}(?:{2}|{3})?).+?\b(.|\r|\n)*$

with {1},{2}, and {3} meaning the same thing. The interesting thing about the “.” character in regexes is it means “match any character…..except new lines and carriage returns”, which means if you’re using multiline textboxes, you have to account for that. So I had to prepend “^(.|\r|\n)*” and append “(.|\r|\n)*$” to my already unwieldy regex. “\r” is a carriage return and “\n” is a new line. The “^” symbol means start at the beginning of the string, and the “$” means continue to the end of the string, with the “*” symbols meaning repeat as often as necessary.

To finalize the product, I simply plugged all of this information into a shared function that returns the proper regex (based on a parameter that determines if I’m using it on a regular string, a textbox, or a multiline textbox) and set my validator’s ValidationExpression at runtime based on the word I was looking for. It actually works pretty well… so far…. ūüôā

All in all, I think I like regexes. They are undoubtedly powerful and can save many programming hours if you know how to use them. I know the initial function I was using to find words in a sentence took me maybe two hours to write and it didn’t even work all the time. It was also about 200ish lines of code. My new function using regexes is 17 lines of actual code, and 7 of that is a Select statement for string/textbox/multiline textbox.

While the initial learning curve is quite steep for regexes, if you’re serious about programming, I highly suggest that you take a day or two to learn them, as that day or two investment could save you weeks or months down the line of your programming career.

Some regex resources:

What’s your craziest regex?

May 15, 2009 Posted by | ASP.NET, Javascript, Regex, VB.NET, Visual Studio.NET | 1 Comment

ASP.NET: Create a User Control Property with Selectable Options

I guess I’ve always taken those little options for granted whenever I want to pick something in a control, say what mode to put a textbox in (text, multiline, or password), because when I wanted to add something similar for a user control, I had no idea how to do it. Thanks to the friendly and extremely helpful¬†people at StackOverflow, I was able to grok the answer.

Intellisense options

Here’s the scenario: you have a user control in your .aspx page with one property, say “addedorapproved” as in the above image. You want the options “Added” and “Approved” to show up as your selectable options. To do so, you must complete the following steps:

  1. Create an enum with your available options:
    Enum AddApproveOptions
    Added
    Approved
    End Enum
  2. Create your private member as your Enum:
    Private _addedapproved As AddApproveOptions
  3. Create your property as your Enum:
    Public Property AddedOrApproved() As AddApproveOptions
    Get
    Return _addedapproved
    End Get
    Set(ByVal value As AddApproveOptions)
    _addedapproved = value
    End Set
    End Property

¬†And that’s it! You should see the little Intellisense box pop up with your options for your new property!

February 5, 2009 Posted by | ASP.NET, Tips & Tricks, VB.NET, Visual Studio.NET | 4 Comments

BlogEngine.NET: How To Customize Your Blog With New Class Objects

I’ve been working pretty extensively with BlogEngine.NET¬†over the past few months and have learned a lot about its inner workings. My project (www.madcowultimate.com) has essentially used the BlogEngine.NET platform (connected to a MySQL database) as a base to create a full-fledged website. Of course, all of the customization I’ve done to the core would mean that I am stuck with this version (1.4.5.0) of the platform, but so far I am okay with that. It serves my purposes for the most part, and everything else I can make work to fit my needs.

One of the major parts of customizing the core to shape the BE.NET platform into your custom solution is creating your own business classes. For instance, in my site, I needed a way for my teammates to check the status of practice, since some of them come in from out of town and would probably prefer to know if practice is on or off for that day before driving in. Thus, I created the Practice class in the BlogEngine.Core namespace to populate a widget displaying the status.

How did I do this? Well, I wish it was as easy as 1, 2, 3, but this project is a little more complex than that. I have definitely learned a lot by wading through the code, but I have also made some mistakes and wasted some time trying things out that did not work. I will break it down for you into manageable chunks, but you will still need to know certain things, like SQL (or MySQL), data table architecture, how classes and objects fundamentally work, and a little bit about inheritance and abstraction.

The following will assume that you have successfully created your blog on your webserver and that you are hooked up to a database (I will use MySQL in this example). I would highly recommend you back up your entire project before embarking on any changes that may affect your blog (especially changes to the core).

First things first, open BE.NET in Visual Studios and expand BlogEngine.Core. You should see a list of familiar-looking classes like Post.cs, Page.cs, and Category.cs. To create your own class, you will essentially need to model your class after these. Right-click on BlogEngine.Core and go to Add > Class… and type the name for your new class. For the purposes of this article, we’ll call it MyObject.cs.

At the top where you import classes, you will need to add at least “using BlogEngine.Core.Providers”, in addition to any other classes you will need (you can, of course, add any you need later). This will make it easier to hook your object up to the data provider. Next, put your object in the “BlogEngine.Core” namespace and have your object inherit the BusinessBase, like so:

namespace BlogEngine.Core
{
public class MyObject: BusinessBase
{
}
}

Inheriting the BusinessBase will do a lot of your work for you when it comes to managing your object, like knowing which properties have been changed and saving your data. Next you’ll want to create your constructor. You won’t use this very frequently (more on that later), but you still need to have it:

public MyObject(int id)
{
base.Id = id;
}

After this, create whatever properties you need using the following template:

private bool _myproperty;
public bool MyProperty
{
get { return _myproperty; }
set
{
if (value != _myproperty) MarkChanged(“MyProperty”);
_myproperty= value;
}
}

This alerts the BusinessBase when something has been changed so that it may take the appropriate action when you need to save your data. You can (and should) also create a read-only ID property by just returning the base ID:

public int MyObjectID
{
get { return Id; }
}

Of course you may create your own methods if you would like, but they are not required. The last step in your basic class construction is to override the base methods for data retrieval/storage/deletion. These are abstract methods delineated by the BusinessBase you inherited, so they are required by your class. When you are done, they should look like this:

protected override void ValidationRules()
{
//nothing
}

protected override MyObject DataSelect(int id)
{
return BlogService.SelectMyObject(id);
}

protected override void DataUpdate()
{
BlogService.UpdateMyObject(this);
}

protected override void DataInsert()
{
if (IsNew)
BlogService.InsertMyObject(this);
}

protected override void DataDelete()
{
BlogService.DeleteMyObject(this);
}

You may have noticed at this point that your Intellisense isn’t coming up with the methods “SelectMyObject” or “UpdateMyObject” when you type in BlogService. This is because we need to add them to your BlogService class. This class is created to separate data access and business so any kind of data provider can be used without any change to how the class functions, therefore making it extremely flexible.

Before you modify your BlogService.cs class, you will need to add the abstract methods to your BlogProvider.cs class, which is in the “Providers” folder. This is where you create the outline for the methods you just outlined in your class. You probably can do this before the last step in your class construction (so that Intellisense will show up, thereby preventing any typos) but it’s not necessary so long as you’re keeping track of what you’re doing. Go ahead and add the following somewhere in that class file:

public abstract MyObject SelectMyObject(int id);
public abstract void InsertMyObject(MyObject obj);
public abstract void UpdateMyObject(MyObject obj);
public abstract void DeleteMyObject(MyObject obj);

This will create the framework for data access to your object that will be inherited by the respective providers.

Now go ahead and open your BlogService.cs class located in the “Providers” folder. Don’t worry too much about what is going on here, just know that a lot of work has been done on your behalf so that it is this simple (two lines of code!) to hook up your object to your data provider of choice per action required by your object. If you really want to look, expand the region in this file called “Provider Model” and look at the details. When you’re done adding your static methods for your object, it should look something like this:

public static MyObject SelectMyObject(int id)
{
LoadProviders();
return _provider.SelectMyObject(id);
}

public static void InsertMyObject(MyObject obj)
{
LoadProviders();
_provider.InsertMyObject(obj);
}

public static void UpdateMyObject(MyObject obj)
{
LoadProviders();
_provider.UpdateMyObject(obj);
}
public static void DeleteMyObject(MyObject obj)
{
LoadProviders();
_provider.DeleteMyObject(obj);
}

Finally, once all your structures are completed, you’ll need to add the actual functionality to your data access. This is done in the DbBlogProvider.cs file, also located in the “Providers” folder. As you will see, because this class inherits the BlogProvider class, it is mandatory that it include (and provide the behavior for) the methods you just described in the BlogProvider.cs. This becomes most obvious when you start typing your methods and Intellisense finishes the rest of your method signature.

This is the point at which you should start creating your data tables that are going to be accessed and modified by your blog, as you will need to know what tables to access and what fields to call in your SQL string!

After you have created your tables, you should go back to the DbBlogProvider file and create a region for your object’s data access methods and start filling them in with the appropriate SQL. Since I don’t know what your objects requirements are, I can’t really help you any further than this, other than to tell you to take a look at how other objects’ data is being accessed for the same behavior (for example, look at how a post is selected, inserted, updated, and deleted) and model yours off of theirs. This part probably takes the longest, since you need to know what to get and how to get it, but if you follow the other objects’ examples, you’ll see that you can benefit from a lot of copy and paste action.

After you complete all of your data access functions, you’re pretty much done! Now, how do you get an instance of the object you just built? Not in the typical manner, which would be to use the “new” keyword, but rather using the BusinessBase’s static .Load() function, or MyObject.Load(id);. Of course, once you’re done modifying the core, don’t forget to build it (right-click on BlogEngine.Core > Build)! If you get any errors, be sure to fix them, as your project will not work until the Core can compile.

I’m somewhat certain this covers the basic complexity involved in the creation of a new, custom object. I hope this saves someone some time! I wish I had known this before going into this project, as I know it would have saved me a lot of time and figuring out. Good luck, and let me know if I forgot anything, as I will gladly add it.

kick it on DotNetKicks.com

September 30, 2008 Posted by | ASP.NET, BlogEngine.NET, C#, MySQL, Tips & Tricks, Visual Studio.NET | , , , , | 2 Comments

BlogEngine.NET: The First Stumbling Block

Let me start off by saying that BlogEngine.NET is a fantastic piece of software with a ton of awesome features and is relatively easy to use.

That said, I’ve spent nearly all of my free time in the past month building a custom site using the BE.NET framework as a base, and while it’s been frustrating at times (I basically had to teach myself C#), I learned a lot about programming just by getting into the core and messing around and seeing how things are linked up and organized. It’s been working great on my local machine (first hooked up to my local MySQL database and then hooked up to the hosted MySQL database) and I was really excited to upload it and get it going.

I fired up good ol’ FileZilla, took a deep breath, and hit “Upload” and watched with mounting anticipation as the 700-some files in the queue slowly (actually, really quickly, but it seemed slow) dwindled. Finally, it was time! I opened my browser, typed in my URL, and held my breath as IE7’s thinking circle went round and round.

That’s when disaster struck.

The YPOD popped up¬†with an unfamiliar error message:¬†“Unable to find the requested .Net Framework Data Provider. ¬†It may not be installed.” Exqueeze me? What does that even mean?? My first instinct was that there was something wrong with my Web.Config file, so I checked there. Some idiot (read: me) forgot to change over the local DB string to the hosted DB string. Fixed. Uploaded. Ta-da!….. ? What? Still not working? Oy… this is going to be a long night…

Well, I did some digging and found out that my instincts were correct and that there is probably an issue with my Web.Config. I found a CodePlex thread by someone who got the same error and tried their solution, but to no avail. I also created my own thread, but as of this writing, no one has responded to my cry for help. I found this tutorial by Al Nyveldt and my spirits were raised again because he is one of the authors of the damn software, but again they were dashed when his tips were also unable to help me out. I even downloaded his sample Web.Config and applied it to my own.

I downloaded the latest MySQL/ASP.NET connector (5.2.3.0 as of now), placed it in my /bin folder and modified the versions in the Web.Config to match (they are 5.1.6.0 in the Web.Config). Still nothing.

With frustration and utter lack of any idea where to turn, I emailed both Mads Kristensen¬†and Nyveldt beseeching them for advice on what to do. I don’t expect an answer (as I’m sure they get 290352268 emails a day from guys like me who are too dumb to figure out their software), but hopefully they will help me out.

Unfortunately, there is no happy ending to this story as of yet… no magical fix that I can present to you that will get you out of the same rut. But maybe I’ve pointed you in the right direction where someone’s suggestions may help you.¬† If you have any ideas, please please please post them or email me. If it works, I will definitely post your solution with a link to whatever site you want. I would not be surprised if it’s a one-line fix in my Web.Config that makes me smack my forehead. With a hammer.

Thanks in advance for any help you can provide!

EDIT: I’ve received a bit of help from the wonderful nberardi¬†and we (he) came to the conclusion that my host is running a pre-5.1 MySql/ASP.NET connector (they are running an outdated MySql.Data assembly) [5.0.5.0, to be exact]). The 5.1 release included support for Roles and Memberships, so anything older than that will not work with this engine.¬†Should they update it (or I go elsewhere) I will keep you posted.

8/30: SOLVED! But you’ll never guess what the problem was. You ready for this? My hosting company had a stray character in their Machine.config file that was right by the DbProviderFactories node… no, I’m not kidding. Everything is working fine now… I will post more on this tool later.

August 27, 2008 Posted by | BlogEngine.NET, Bugs, C#, Errors, MySQL | 5 Comments

State of the Coder: Code Complete 2, Promo Codes, BlogEngine.NET

I just recently purchased Code Complete 2¬†by Steven McConnell, and am quite excited to read it, especially after all the coding I’ve done recently.¬† I’ve heard some great things about the book, and being a self-taught programmer, I’m pretty excited to learn the right way to do and think about some things.¬† I can’t really review it yet (as I’ve read maybe 4 paragraphs in the preface as of this writing), but I will share some of the tips that I glean from this work as I get through it (more regularly than I have been doing).

I’ve been working on a few projects here, some for business and others for pleasure, and they’ve kept me busy. One of which is the building of a Promo Code engine into my site at www.columbussupply.com. Let me tell you, it’s no easy task, especially since PayPal does not accept negative amounts (pretty hard to apply a discount!), but I’m sure I’ll figure it out in time.¬† The problem has three parts: 1) how to display the discount to the user (easy), 2) how to track the promo/prevent it from being abused¬†(harder), and 3) how to transfer the information to PayPal/Google Checkout so that the transaction appears seamless to the user (hardest).

This third part has gotten me stuck a little.¬†I don’t want to change the display to the user, but I need to find a way to transmit the discount to PayPal. One idea was apply the discounted amount to the last item in the cart (that has a price higher than the discount) with a note on it that mentions the promo code. That may work, but it may be confusing and is definitely kludgy. Anyone have any ideas how to combat this?

As for my pleasure work, I’ve been hacking away furiously at the newly released 1.4.5.0 version of BlogEngine.NET, which has been pretty fun, for my Ultimate Frisbee team’s website, www.madcowultimate.com (as of this writing, there’s nothing there, but there will be very soon).¬†BE.NET is¬†a great open-source blogging framework that is very¬†well-designed and somewhat easily customizable. The official version is in C#, but there’s also a VB.NET version floating around. I considered the VB.NET version for a bit, but I decided to stick with the C# version for a few reasons, the main being I realize I need to learn C#, and that some of the techniques they use in this app are so advanced that I wouldn’t know what they were in VB.NET or C# or even English. So far I’ve had pretty good success and I’ve learned a whole bunch about the language as well as good coding practices. I would suggest that even if you don’t want to use it, you should download it¬†just to look at how it was built (how often do you get to peek at the work of professional .NET coders?).¬†

I’ve discovered (reported, and corrected!) a few bugs, added some new features, built my own theme, and created my own widgets (somewhat) successfully. I’ve also opted to use the MySQL option included with the app, which has been awesome for me because that’s the DB I’m most comfortable with.¬† Overall, I’d rate this app very highly because there are a ton of features that you can use (even though I probably won’t use half of them) and it is so easy to modify.¬† Occasionally you may have to dip into the Blogengine.Core if you REALLY want to customize things (such as create your own data access methods), but so long as you don’t mess around too much, you should be fine.

Anyone else having a good ol’ time with BE.NET? I’d like to see your work!

August 15, 2008 Posted by | ASP.NET, Tips & Tricks, Google, PayPal, MySQL, C#, Books | | Leave a comment

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 | ASP.NET, Tips & Tricks, Visual Studio.NET | 9 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 | ASP.NET, Generics, GridView, MySQL, Tips & Tricks | | 20 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 | ASP.NET, CSS, Javascript, VB.NET | | 3 Comments