Getting data from Microsoft SQL Server
My next exercise was to connect to the Microsoft SQL Server and fetch some data. I created a stored procedure (with Visual Studio 6 - as I don't have the universal version of 2005) that returned the data I needed. According to the book "Microsoft ADO.NET" Microsoft Press 2002 (Yes - I know it's kind of old, but I have a hard copy version, and prefer that over on-line books), I can drag a "oleDbConnection" object down to the form. So I tried that (after enabling oleDbConnection in the Visual Studio 2005 toolbox). The object appears as expected in the control-bar. But when I try to create a new connection using the Visual Studio 2005 wizard (activated from the controls properties), I get this cool error message: "The 'SQLNCLI.1" provider is not registered on the local machine". So - how do I resolve this? A google search failed to give any hints at all. But I'm using a 64-bit machine, and I know that there are some issues with 64 bit Windows and Visual Studio 2005. So I searched Microsoft Download for 'SQLNCLI' and found a download-link: Feature Pack for Microsoft SQL Server 2005 - November 2005. I downloaded and installed "sqlncli_x64.msi" and then it worked. OK problem solved. But this is not good enough. Not for a product that's also designed for novice developers. I have 20+ years of experience in solving issues like this, and this one took me only 15 - 20 minutes - but I know for a fact that two other other developers gave up Visual Studio 2005 on 64-bit windows because of this. They were unable to resolve it.
Adding the SQL command to execute the stored procedure was was trivial. The wizard even let me execute it and view the result set in Visual Studio. That's nice.
The help browser
But, unlike the sample code in the database-book from Microsoft Press, I usually use try/catch blocks to handle errors. C# programs that fails to do this bombs out with ugly error-messages whenever an error occurs. I have sophisticated classes to report errors in C++. In my C# program, I just wanted to pop up a simple message-box. So I tried the keyword "MessageBox". It's recognized by intellisense, but there is some problem. When I compile the program, the MessageBox keyword is underlined with blue color. OK. Some syntax error. I need to figure out how MessageBox is implemented in C#. I Press [F1] for help. The MSDN help browser starts up, but it gives no clue about the MessageBox syntax. In stead, it displays abstract information about the compiler error. Hey - I didn't highlight the compiler error line, or the error-code - I highlighted "MessageBox" when I pressed [F1]. That means that I want help on "MessageBox" - not "CS0118". More friction. I have to type in "MessageBox" in the filter-box in the help-browser in order to find the syntax for "MessageBox".
I hate when programs tries to be smart, and the attempt fails. In this case Visual Studio 2005 assumed that I wanted help to figure out why the compilation failed. But I understood the problem - I searched for the solution. If I highlight a verb in the C++ editor in Visual Studio 2003, the help for that verb usually shows up in the help browser - no matter what compiler error it caused. That's the logical behavior. Explaining the problem is normally less relevant than finding the solution. When they managed to do it right in Visual Studio 2003 - why did they have to change this? Do they add these annoying "features" just to make people eager to upgrade to the next version? I've used Visual Studio 2005 for a few hours - and I'm already ready to upgrade. I want to escape to something that can be used without a lot of friction - so that I can focus on what I need to do - without being slowed down by all this annoyance.
Best practice coding made difficult
In my application I just need to read trough the data-set once. So I decided to use a simple DataReader object to avoid the overhead for a full .NET TableAdapter. The result set included joins, and I had to do some manual parsing and build some internal data-structures anyway. And since I like efficient code, I wanted to cache the column index to avoid the lookup for each row in the result set. In C++, I have adopted some coding-methods to avoid program, bugs. Whenever I do a comparesion, I put the lvalue on the left side of the test. In stead of writing the common: " if (foo == 1) " I write " if (1 == foo) ". That way I get a compiler error if I misspell "==" as "=" - something that happens from time to time. I also use constant values wherever possible. If I know that a value will not change, I label it a constant. That way the compiler will complain if I try to assign the variable to a new value. Together these, and a few similar methods, saves me from hours in the debugger. I tried to use the same approach with C#. But " const int foo " could not be assigned to a non-const int. What kind of stupidness is that? A const int is still an integer - the const modifier just mean I can't change the value later on. Why won't Microsoft let me write code that is less likely to be messed up with bugs when it's modified later on? Thats stupid. When I stumbled into this silliness, I highlighted "GetOrdinal" and pressed [F1] again to see if there was a way to get the "const int" value. Bummer. The help browser again guessed that I was looking for the error number. I copied the statement to a new line, highlighted the "GetOrdinal" verb again, again - without recompiling the file - so that Visual Studio not yet had discovered the compilation error for this line. Bummer! The help browser ignores the highlighted verb. It sends "rdr.GetOrdinal" to the help browser - and that is of course to no help. I just get a chapter about "You have chosen to use local Help only for Search and F1 results, and the topic could not be found in local Help." Wow - as Microsoft use to say (at least when they launch Vista). I'm impressed. They have really made me ready for the next version of Visual Studio. The current version is definitely not made for professionals. Sure - I can type in the verb in the help-filter - but I except that a product that cost some US$ 1000 can match at least the basic features you find in almost any other integrated development environment. So far, Visual Studio 2005 is not RAD. It's SAD (Slow Application Development).
ListView is not a .NET control
I managed to get my ListView derived control to work, and I managed to fetch the data it needed from Microsoft SQL Server. Now it was time to start on the fun stuff - drawing the graphics. I made an override of the ListView method that's supposed to draw a cell. But it was never accessed by the program. After some research - it seems like the ListView is not a .NET control at all - but rather a wrapper around the native WIN32 ListView control dating back to Windows 95. That means that it does not use the "standard" .NET methods and events, and that I need to use the old Owner draw flag in order to do interesting stuff. I was pretty disappointed when I discovered this. The native Windows control is very old, and part of the reason to do this project in .NET was to get away from the outdated, native WIN32 interfaces. It turned out that the .NET 2.0 implementation of ListView can't even set the row line-height programmatically! You have to either do a lot of work (sine ListView don't even support the MeasureItem event), or you can trick ListView to change the line-height by setting an icon of the desired height for the line.
This is not good enough. As a direct result of Microsoft neglect of supplying core .NET controls, there exist a large number of "ListView" like controls on the Internet - some free and some commercial. The problem, as I see it, is that a multicolumn list control is a core part of almost any user interface in a Windows program. Programmers, such as myself, should not have to implement or purchase core components in order to do trivial tasks like this. That was acceptable with MFC 10 years ago - but not today. Today I expect that a bright new "RAD" environment from a major vendor supplies all the core components I need in order to derive my own versions to meet more specialized needs. It's frankly speaking provoking to have to spend time figuring out how to set the line-height in a multi-column list control - because Microsoft did not care to add a method for this. I could have used a free or commercial ListView control - but what if it contains bugs? What about security flaws? Would it work with 64-bit Windows? Will it be supported in 10 years (My project will probably have a life-span of at least 10 years). In wxWidgets, setting the line-height and drawing individual cells would have been simple. The same goes for Java. How come that Visual Studio 2005, at a cost of US$1000, cannot do the same as it's free competitors?
Another interesting "feature" is that in some cases, exceptions are lost. I had a bug in the method that filled the list-view from the dataset. The bug triggered an exception - but the program never complained - it just displayed an empty list. I had to use a try/catch block around the code inside the method. Somehow, Microsoft must have missed one of the basic uses of exceptions. In the old days, before OO concepts were developed, the programmer had to check for errors after every method that was called. And the program had to deal with the error there and then. That lead to complex code, and it slowed down the coding. Then "exceptions" were invented, and the programmer could write code as if everything was going OK, and deal with any kind of error in appropriate places. With exceptions, it's up to the coder to decide where he wants to deal with the errors. But Microsoft obviously disagree. In stead of passing the exceptions to the higher levels, or at least present an error-dialog, the exceptions are just ignored, and the program moves on as if everything is fine. That means that programs can contain serious bugs that are very hard to find, because .NET pretends that there are no errors. I read about this in one of the books about .NET 1, but I expected it to be fixed in .NET 2.
Date picker blues
In order to draw the time frames for the projects, the program needs to know what time frame we are interested in. I added two date-picker controls over the toolbar (somehow, Microsoft never cared to add support for date-pickers for the toolbar) and connected them to their own user property values. No problems at all - until the program run. The property values were totally ignored. So was my attempts to modify the time when the program run. I could change it interactively, but not with code. If I changed the start-date to "January 1st 2007", the date-picker showed February 1st 2007. I concluded that the data-binding was broken (probably a bug in .NET 2) and removed it. Then I added code to set the values from the user property value when the program started. But the program totally ignored the new date I set. I traced the code in the debugger, and confirmed that the code was working as it should - except that the date-picker kept the old (default) value. (I've been struggling with Microsoft's broken day/time libraries before. The DataPicker in MFC will only work if you set the value with one of the many SetValue overrides. This is confirmed as a bug from Microsoft, and documented - but never fixed.). I deleted the data-picker, re-created it without the data-binding - and now my code worked without modification. How strange. And really intuitive and easy to fix for noobs.
When I tried to set the to-date value, I discovered that I could not use the property-name "ToDate". I got no errors or warning - just a different value than I have saved in the user properties. When I changed the property-name to "TimespanToDate" it worked.
This is another example that this is not RAD product. I spent almost an hour before I could get a start-value in a date-picker from the users settings. I could not use the data-binding in VS, because it was broken, and had to resort to traditional coding.
Shocked and horrified
The first thing that actually shocked and horrified me, was when I discovered the total lack of support for even a simple tasks like double-clicking in one of the most common user-interface controls, the Windows.Forms.ListView. You can trap the DoubleClick event, but there is no support in .NET to track the row or column where the user actually double-clicked. You have to write your own code to do this. I don't really know what to say. Even retarded GUI toolkit designers on drugs would have added support for very common and essential tasks like this. I don't know why Microsoft keeps torturing it's customers - but I can say for a fact that marketing Visual Studio 2005 as a "RAD" toolkit i Norway, would be a serious violation of Norwegian law.
In order to handle this, I wrote the following code:
private void MouseDoubleClick(object sender,
int sel_row = -1;
if (reportListView.SelectedIndices.Count == 1)
sel_row = reportListView.SelectedIndices;
if (-1 != sel_row)
int left = 0, right = 0;
for (int idx = 0; idx < reportListView.Columns.Count; idx++)
right += reportListView.Columns[idx].Width;
if ((e.X >= left) && (e.X <= right))
left = right;
// Called from MouseDoubleClick
private void OnDoubleClick(int row, int col)
So as you can see, it's not really complicated. It's just annoying to have to deal with these details, in stead of the things my application is supposed to do.
I believe that Microsoft has a long way to go before they can call Visual Studio for a "professional" or "RAD" development environment. It does not match free alternatives like Eclipse, and for C++ GUI applications development, even small projects like DialogBlocks is way better in many areas. Maybe Microsoft should split the development environment in three parts; one for Visual Basic, one for professional (educated) developers with C# and C++, and one for simple web development. The "mental model" for a development environment will never be the same for an amateur with Visual Basic (who hides what's going on behind the scenes) and professional developers. The "point and click" development must be extended to be able to handle all core functions and the most common tasks, such as using several connected data-lists and filters in one view. All but the simplest "hello world" applications require a lot more complexity than Visual Studio's "point and click" functionality can deliver. I also miss more Windows controls. Hi - it's been 12 years since Windows 95 was introduced! Tree-views and list-views are not that impressive anymore. Now I at least expect multicolumn tree-views (like in most email applications), and appealing new controls that can enrich the user experience. The IDE should as a minimum provide all the controls it uses itself. A RAD tool is supposed to let the developer (me) focus on the problem the program is supposed to handle - not on writing primitive user interface controls!
Also, in .NET I expect all the user interface components to be native .NET components. Mixing native Windows controls, ActiveX controls and .NET components makes the code inconsistent and takes focus away from the problem the program is supposed to solve. It complicates the code and makes it error-prone on mixed 32/64 bits environments.
And why don't Visual Studio 2005 offer the same level of auto-complete for C++ as it does for C#?