Recent Articles: 3/10/06 - The Rewards and Pitfalls of Going Online 1/14/06 - How to Lose Weight Without Starving: IT Consolidation Strategy for Educational Institutions 12/20/05 - Getting It Together: The Benefits of Web-Based Application Integration
This "Solid Blue Blog" is intended as a repository for tips and tweaks discovered while fiddling with assorted geekware, including but not limited to VB.Net, Coldfusion, Windows XP, the web, hardware, and other software packages. Provide feedback on these entries (or supply your own tips and tweaks) by e-mailing Solid Blue. Enjoy!
7/13/06 - Microsoft Outlook XP - Eliminating that annoying address book pop-up message.
If you have Adobe Acrobat or other Outlook plug-ins installed, you may occassionally get an error when trying to create a new message like this:
"A program is trying to access email addresses..."
You are given the option of trusting the program (in this case Outlook itself) for a number of minutes or not trusting it at all. This message is incredibly annoying as it happens every time you try to create a message and there is no way to turn it off from within Outlook. Why does Outlook seem to not trust itself? Because the message editor that opens when trying to create a new message uses the set of plug-ins that other software installs, in this case, Adobe Acrobat. It is these plug-ins that Outlook does not intrinsically trust.
This annoying message can be turned off by a registry modification. As always, only experts should modify the Windows registry. Find the key:
HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Outlook\Addins\PDFMOutlook.PDFMOutlook
and change the entry "LoadBehavior" from 3 to 0 or 1.
In my case, 1 worked, but I've heard 0 works for some. That annoying message should now be gone!
6/25/06 - Visual Basic.Net - More erroneous error messages from Microsoft.
Here's one that ate up far too much of my would-be productive time yesterday.
I've been developing a web application using a MySQL database in ASP.Net. I learned quickly that MySQL Connector for .Net has a tendency to intermittently close an open connection on its own, so I wrote a little Disconnect() function and called it immediately after every Connect() function while communicating with the MySQL database. I used this Connect/Disconnect combo about 50 times in various places in this application, and everything was just fine.
Then I created a new web form using a new stored procedure I hadn't used anywhere else in the application. Upon running the new web form, I got the following error at my .Fill method:
"There is already an open DataReader associated with this Connection which must be closed first."
Odd, since no where in my code was I even using a DataReader control. I checked all occurrences of my Connect and Disconnect pairs, thinking I may have accidentally left a connection open. Nope. So I created a blank web form, made it the start page, and added only the code that pulls data from the new stored procedure in the Load event, and still got the same error. Next, I created a completely new connection to the database which was used just for this one MySQLCommand object. Incredibly, I was told there was an open DataReader for this brand new connection as well!
I'll spare you all the cursing, hair-pulling, and dog-kicking and cut to the chase. Turns out the problem was with the stored procedure. I had written a SQL statement that passed all syntactical checks but caused an error when executed. For whatever reason, the error that ASP.Net threw was the one about the open DataReader, which couldn't have been more useless in diagnosing the problem.
The moral of the story? Don't trust ASP.Net error messages 100% of the time unless you are an utter glutton for punishment.
6/20/06 - Windows - Accessing your favorite websites with less frustration.
If you're like me, you have about 1,000 links stored in your "Favorites" folder, pointing to your favorite places to visit on the web. If you're not like me, you've probably got them organized consistently into subfolders and arranged just the way you like them. I like to use a lot of folders to organize my favorites, too, but I find that while using the touchpad to access them on my laptop, I get frustrated.
I'm not a touchpad afficianado. In fact, I despise them. I'll never understand the people who swear by them, but there are times that I can't find my mouse and am forced to use the touchpad on my laptop. The problem is that the scheme Windows uses for accessing subfolders in Internet Explorer involves a delayed drill-down. That is, to access the items in the subfolder that pops up next to the main folder, you have to keep your pointer hovering over the main folder while you scroll to the right to select an item from the subfolder. Using my touchpad, I almost never end up hovering over the folder I want by the time I reach the subfolder to the right. Improving my touchpad skills is a lost cause at this point, so I found a better way to keep my pointer over the folder I want.
The width of the dropdown for "Favorites" is determined by the longest entry in the Favorites folder. So if I have five folders named "Media", "Fun Stuff", "Miscellaneous", "Work-Related", and "The Most Incredible Sites Anyone On This Planet Has Ever Seen In Their Entire Life And Then Some," the last of these will make the width of the dropdown huge and make it hard for me to keep my pointer hovering over the folder I want. The simple solution is just to rename the folder something else, like "Incredible Sites." It seems obvious in retrospect, but my laziness (simply accepting the name of a page when I save it under my "Favorites" rather than entering something shorter) has caused me aggravation I could do without. Sometimes solving the little niggles rather than just accepting them can make all the difference between letting the stress get to you and staying in control of it.
6/6/06 - Visual Basic.Net - Programmatically changing a web form's background image.
Seems like it should be easy, but the body element of a web form doesn't come with any inherent properties to set the background image. It's easy to set the background at design time, but what if you want to dynamically change the background based on the user's actions?
First, you have to make the body of the page a server control and assign an ID to it:
<body id="bodyElement" runat="server">
Then, you have to declare a generic HTML control in the code-behind with the name of the id you assigned to the body element:
Public Class MyPage
Protected bodyElement as HtmlGenericControl
End Class
Finally, you can refer to the body element and assign attributes to it. I am changing the background property, but you could just as easily change the bgColor or any other property:
bodyElement.Attributes("background") = "MyPicture.gif"
6/3/06 - Visual Basic.Net - Setting a default button for the "Enter" key.
Imagine you have a login page and you want the login credentials to be passed when the user hits the "Enter" key on their keyboard. It seems sometimes ASP.Net decides to arrange this little function for you and other times, it just doesn't. So how do you force it to behave every time? Just add this line to the Load event of your page:
Page.RegisterHiddenField("__EVENTTARGET", "btnSubmit")
Substitute the name of your button for btnSubmit and be sure to use two underscore characters before EVENTTARGET. This is one of those hidden methods that apparently Microsoft doesn't want you to know about. Why? Who knows, but there are an awful lot of useful, hidden little things in .Net -- you just have to know about them and they work just fine.
5/31/06 - Visual Basic.Net - Programmatically clicking a button.
There are times when you want to programmatically click a button, say to re-bind data to a control after changes have been made to it. Rather than duplicate the code to, in essence, re-retrieve the data, it might be nice just to trigger the clicked event for the Retrieve button through code. But what do you do about the arguments the event handler expects for the clicked event? A simple way to cheat is just to pass dummy arguments, like this:
Dim obj as Object
Dim evarg As EventArgs
btnRetrieve_Click(obj, evarg)
5/6/06 - Visual Basic.Net - Programmatically manipulating user controls on web forms.
More VB.Net fun! To change the behavior of a user control through code from a second user control or page, there are some hoops you have to jump through, including a wonderfully annoying bug brought to you by Microsoft.
When you add a user control created at design time to a page or another user control, no code is automatically created to allow you to access the user control from it's container. To make any reference to the user control through code-behind pages, it must be explicitly declared in the code for the class. So I drop a user control of class MyControl onto a page called MyPage and I have renamed it MyControl1. I must add a line in the declarations section of the MyPage class before I can refer to MyControl1 in code, like this:
Public Class MyControl
Protected WithEvents MyControl1 As MyControl
If I don't, I get an undeclared object error. Incidentally, don't hope for Microsoft to fix this "acknowledged bug." A similar and much more obtrusive bug involving random changes to pages when switching between Design and HTML view has been "acknowledged" by Microsoft since .Net was released, and apparently there are no plans to fix the bug because, I quote: "It's too hard."
In order to refer to objects on a user control, I must create properties for the user control, and manipulate the control through these properties. So, if I have placed a textbox control on my user control MyControl, I must create the following property as part of the user control class to refer to it from any page on which I use my user control:
Public Property MyText (ByVal Value as String)
Get
MyText = MyTextbox.Text
End Get
Set(ByVal Value As String)
MyTextbox.Text = Value
End Set
End Property
I can then do the following from MyPage, which uses MyControl (assuming I have declared the MyControl instance as described above):
MyControl1.MyText = "This text has been changed programmatically from a containing page"
User controls carry with them a number of peculiarities, but fortunately, the benefits of using user controls on web projects are worth it in the end.
4/23/06 - Visual Basic.Net - Moving a list item from one listbox to another.
Imagine two listboxes side by side with buttons to copy list items between them. It's common sense to "copy" the list item like this:
'Store list item in a variable.
Dim liAAA as ListItem
liAAA = lbxAAA.Items(lbxAAA.SelectedIndex) < /FONT > 'Create the item in the destination listbox. lbxBBB.Items.Add(liAAA) 'Remove the item from the source listbox. lbxAAA.Items.Remove(lbxAAA.SelectedIndex) Should work fine, right? What actually happens is that the list item liAAA, being a variable of type ListItem, still has it's .Selected property set to "True." Thus, the new row added to lbxBBB is considered "selected" because it was created directly from the liAAA variable. But when you attempt to copy a second list item to lbxBBB, you get the following error: A ListBox cannot have multiple items selected when the SelectionMode is Single. Why does this happen? The second list item you copied is also marked as "selected," meaning the destination listbox ends up with two SelectedIndex's, which is only allowed when the .SelectionMode property of the listbox is set to accept multiple selected list items. To resolve this problem, unselect the list item prior to adding it to the destination listbox, like this: 'Unselect list item. liAAA.Selected = False < /FONT > I believe this behavior is a result of all variables in .Net being actual objects with properties that persist throughout the life of the variable. The agony of trying to solve a problem like this can serve as a reminder of the new nature of variables (and virtually everything else) in .Net -- they're all objects with properties, for worse as well as for better. 4/15/06 - MySQL - Accessing MySQL .Net Connector through the DLL. If your site host doesn't support MySQL Connector/.Net on their web servers, you can still expose the MySQL Connector objects for your ASP.Net project. Copy MySql.Data.dll from the MySQL Connector install directory to the /bin folder of your web project (in with the .dll created by your project). Add a reference to the MySQL dll, browsing to the one you copied to your /bin directory. Be sure to include an "Imports MySql.Data.MySqlClient" statement to expose the namespace and then develop away! When deploying your web app, the copiled code will search for the MySql.Data.dll in the project's bin folder, so simply copy that dll along with your project dll to your production web server. Your data access code should work just fine, thus allowing you to avoid using the slower ODBC driver to access your MySQL database.
'Create the item in the destination listbox.
lbxBBB.Items.Add(liAAA)
'Remove the item from the source listbox.
lbxAAA.Items.Remove(lbxAAA.SelectedIndex)
Should work fine, right? What actually happens is that the list item liAAA, being a variable of type ListItem, still has it's .Selected property set to "True." Thus, the new row added to lbxBBB is considered "selected" because it was created directly from the liAAA variable. But when you attempt to copy a second list item to lbxBBB, you get the following error:
A ListBox cannot have multiple items selected when the SelectionMode is Single.
Why does this happen? The second list item you copied is also marked as "selected," meaning the destination listbox ends up with two SelectedIndex's, which is only allowed when the .SelectionMode property of the listbox is set to accept multiple selected list items.
To resolve this problem, unselect the list item prior to adding it to the destination listbox, like this:
'Unselect list item.
liAAA.Selected = False < /FONT > I believe this behavior is a result of all variables in .Net being actual objects with properties that persist throughout the life of the variable. The agony of trying to solve a problem like this can serve as a reminder of the new nature of variables (and virtually everything else) in .Net -- they're all objects with properties, for worse as well as for better. 4/15/06 - MySQL - Accessing MySQL .Net Connector through the DLL. If your site host doesn't support MySQL Connector/.Net on their web servers, you can still expose the MySQL Connector objects for your ASP.Net project. Copy MySql.Data.dll from the MySQL Connector install directory to the /bin folder of your web project (in with the .dll created by your project). Add a reference to the MySQL dll, browsing to the one you copied to your /bin directory. Be sure to include an "Imports MySql.Data.MySqlClient" statement to expose the namespace and then develop away! When deploying your web app, the copiled code will search for the MySql.Data.dll in the project's bin folder, so simply copy that dll along with your project dll to your production web server. Your data access code should work just fine, thus allowing you to avoid using the slower ODBC driver to access your MySQL database.
I believe this behavior is a result of all variables in .Net being actual objects with properties that persist throughout the life of the variable. The agony of trying to solve a problem like this can serve as a reminder of the new nature of variables (and virtually everything else) in .Net -- they're all objects with properties, for worse as well as for better.
4/15/06 - MySQL - Accessing MySQL .Net Connector through the DLL.
If your site host doesn't support MySQL Connector/.Net on their web servers, you can still expose the MySQL Connector objects for your ASP.Net project. Copy MySql.Data.dll from the MySQL Connector install directory to the /bin folder of your web project (in with the .dll created by your project). Add a reference to the MySQL dll, browsing to the one you copied to your /bin directory. Be sure to include an "Imports MySql.Data.MySqlClient" statement to expose the namespace and then develop away!
When deploying your web app, the copiled code will search for the MySql.Data.dll in the project's bin folder, so simply copy that dll along with your project dll to your production web server. Your data access code should work just fine, thus allowing you to avoid using the slower ODBC driver to access your MySQL database.
3/17/06 - Visual Basic.Net - Convincing a child class defined in a separate module to play well with it's parent class.
It's nice and neat to contain class definitions within their own modules in VB.Net, but if a class is inherited from another module-contained class, the scope has to be appropriate for the inheritance to work.
Example: clsChild is inheriting clsParent, which is defined in module Parent.vb. If clsChild is to be "Public" in scope (assuming clsParent is also "Public"), it must be given its own module, and cannot, for instance, be included in the code for a form. In other words, if clsParent is to be given its own module Parent.vb, clsChild must be given its own module Child.vb.
If you are like me, you sometimes don't realize you want to use a module to contain a class until you've already defined it elsewhere (like in the code for a form). This little tip prevents the compiler error regarding scale when you decide to move a parent class to its own module to make the code tidier.
3/15/06 - Windows XP - Removing those annoying popup ballons from the system tray.
Note - Registry changes should not be made lightly. They can severely mess up your Windows installation.
If you're sick of those popup ballons constantly popping out of your system tray to remind you yet again that "your computer may be at risk" or similar complaints, a simple registry change can remove them, although the system tray icons and little popping sound will remain.
Start the Registry Editor (Start Menu -> Run... -> type "regedit.exe") and locate the key [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] and right click on the right pane and select "New" -> DWORD Value. Name the new value "EnableBallonTips". The data segment will default to "0x00000000 (0)".
Those annoying bubbles are now history!
Email: Question:
Copyright 2005-2006 Solid Blue Development