The Ramblings of a Geek

A place for writing about how different little programming problems were solved, in particular relating to C++ using .NET.

The idea behind this particular blog is to document solutions to particular problems I have come across while programming. I feel that by documenting these here, it is serving two purposes. First it is an easy place for me to check and find out what I did, without having to keep searching through old files in my code trying to remember exactly where I'd written the code, sometimes over several functions, or even different files. Second, it is a place for others to find solutions, and hopefully help them to reach a solution much sooner than I achieved; sometimes hours or even days have spent trying to find out how to fix a problem.

Thursday 24 December 2009

ListView Flicker in Virtual Mode with OwnerDraw

The Problem

Within a ListView if you have set the Virtual Mode, and also have OwnerDraw selected, the result is very unpleasant. It appears that due to the number of times that the virtual items are retrieved and asked to redraw, the control starts to flicker badly. This is apparent when doing something as simple as moving the mouse over the ListView. As soon as you start to scroll the listview, it is hideous and does not look at all professional.

The solution to this problem is actually very simple, but took a lot of tracking down, dismissing one solution that required overriding the WndProc function.

The Solution

The solution is unbelievably simple, and makes you wonder why Microsoft have not made it a setting you can change in the ListView properties. It all revolves around the following simple function call.
SetStyle( ControlStyles::OptimizedDoubleBuffer, true );
What this does is pretty self explanatory, and just about removes all the flicker and actually improves the performance of the ListView itself. Here lies another issue, in that this function can't be called from within your own code, as it's an inaccessible method of an ancestor.

There is a way around this, where instead of putting a ListView on your dialog, you create your own class, inherited from the ListView, as in the following example.
public class MyOptimisedListView : ListView
 {
     public MyOptimisedListView()
         : ListView()
     {
         SetStyle( ControlStyles.OptimizedDoubleBuffer, true );
     }
 }
There is a bad issue with doing this though, because this means you will not longer have the ListView control showing within the View Designer. This means any changes you make would be largely blind, and only really useful if you have one very simple case you're working with.

A better solution is to create a Custom Control of your own, which needs to be added to a Managed DLL. This is actually very simple to do within Visual Studio 2008. Go to the Project menu and click the "Add New Item" option, which brings up a dialog for adding the new item. Select "User control" from within the UI category, giving it a name, such as MyListView. This will bring up the View Designer showing a dialog box, which is of little importance to us. What you want to do is look at the View Code window, and scrolling down you should find the following code:
public ref class MyListView : public System::Windows::Forms::Form
 {
 public:
     MyListView(void)
     {
         InitializeComponent();
         //
         //TODO: Add the constructor code here
         //
     }
To complete the job, you want to change that bit of code so that it is as follows:
public ref class MyListView : public System::Windows::Forms::ListView
 {
 public:
     MyListView(void)
     {
         InitializeComponent();
         //
         //TODO: Add the constructor code here
         //

         SetStyle( ControlStyles::OptimizedDoubleBuffer, true );
     }
This now gives us a control that we will be able to add a dialog box, but in order to do that we need to get it into the ToolBox. This is achieved by right clicking within the ToolBox window, and selecting the "Choose Items ...." option. This brings up a new dialog, which may take a while to appear. Click the browse button and navigate to the compiled version of the DLL in which you've added this custom control. Once you click okay, this custom control will be added to the list of selectable controls. Make sure the CheckBox is selected for the control, and then click the OK button. The control is then added to the bottom of the "All Windows Forms" section of the ToolBox. You can then place this control on any dialog you create, and interact with it the same way you can with the standard ListView control.

The flicker in your ListView will then stop, making your application more professional. In the end I'm not actually using this custom control due to a different limitation on the number of items that the VirtualListSize allows. In the particular dialog I sometimes had datasets that required more than 100 million items. If you set the VirtualListSize to be larger than that value, the control will display nothing, with none of the relevant events being called.

Blog Introduction

A Little About Me

I am largely self taught in terms of programming, having received little in the way of lessons or lectures on programming. I've received lectures in a few areas, such as grapics, and how to draw a shape in 3D, and the matrix transformations required to change its position and orientation, and small introductions to Pascal and C++. Other than that I've learnt as I've gone along, sometimes with help from other people, but mostly through looking at examples and reading the documentation that goes with the functions available.

I originally learnt Sinclair Basic, back in the early 1980's using a ZX81, which was immensely limited, proceeding later to using a ZX Spectrum a few years later. It was during this time I taught myself to do a bit of programming using Z80 assembly, which gave me an insight into just how slow the Basic interpreter was. Later I was to do some more Basic on a BBC Master Computer, for which my father managed to get a Pascal compiler, which I used during the time I was it as part of my degree course. The following year on the degree course we used Z80, which I was already good at, so did not actually learn anything new then.

It was during a year working in industry where I learnt Fortran while using a VAX/VMS system. I was given no formal training, and just picked things up as I went along, and of course fell into many of the major pitfalls that Fortran can land you in. I learnt a lot from that year, which I was to use during the final year of my degree. It was during that final year that I learnt about 3D graphics, and was shown C++ for the first time. I have to say I did not understand Object Orientation properly at that time. We also learnt a bit about concurrent programming using a version of Pascal developed for the purpose, which was my first step to understanding the concepts required for programming with threads.

After completing my degree in 1991, which was a bad time in England to looking for work, especially after completing a degree at a then Polytechnic, I accepted the offer of doing a PhD. During the PhD I used Fortran to produce some of the data I required, which was then further used with Matlab. This did little to advance my programming skills over the following 3 years, but it was during that time we gained access to the internet, initially using the Mosaic browser, which seems like ancient history now. Back in about 1993 the internet was very fast, due to how little traffic there was. Largely due to the almost complete absence at the point of several things. The adult industry was not ready at that point to take advantage of the technology being a major factor. Piracy of software etc, using the internet was next nonexistent, and streaming media was largely a dream.

I completed my PhD in late 1994, and was employed early 1995 as on a 2 year contract as a research fellow at Brunel University. In respect of how little real work was required in order to keep my boss happy was minimal. This gave me plenty of time to pursue other avenues of interest, which included chatting to people using telnet Bulletin Board Systems, largely being run on PC's running Linux. It was on these that I built friendships with a number of people in different places around the world, bumping into a group of like minded geeks that were running one of these boards, written in C. Although I had a very limited knowledge of the language at the time, when I was asked if I'd like to be part of the programming team, I jumped at the chance, feeling sure that I would have no problem learning what I needed to be able to make modifications to the code. This I did, and without even really understanding pointers properly, made some quite astonishing changes without breaking anything. With the two years of my contract nearly up, my confidence in C programming was good enough for me to consider trying for a full time programming job.

After a lot of interviews during the space of two weeks, I was offered a job working for a company doing data recovery, programming in C. A funny point to note, is that the project I was originally employed do, was never completed during the seven and a half years I was working for them. However most of what I'd been doing was not wasted, and went into other projects. In fact the client server technology I'd been developing found use within one of the telnet bulletin boards, so from my point of view nothing was wasted. During my time at the company I started to teach myself how to program in C++, and once I understood the Object Oriented concept was able to quickly advance my skill in the language. The use of templates was briefly another sticking point, but once mastered there was a temptation to make almost everything as templated code.

When I left the data recovery company, I took a break from the IT industry for 5 years, but dabbling with a few of my own projects and forays into creating websites using PHP and Cascading Style Sheets. After 5 years out of the industry I was ready to start programming again, and was offered some contract work, which I do from home, using .NET and the C++ language. I'm not able to reveal anything about the work I'm undertaking, but certain examples of stuff I will be able to post about, which I hope will help other people find the answers to problems more efficiently.

The Reason For Creating This Blog

There are few things more frustrating than those occasions when you're trying to find the solution to a programming problem, and your search keeps finding the following types of example:
  1. Simple examples, that doesn't tell you anything you didn't already know.
  2. The overly complicated solution. These sometimes use all sorts of weird and wonderful techniques.
  3. The solution where it is assumed you already know a huge amount about certain functions or structures that are being used.
  4. Once in a while you find the Holy Grail of examples, where you find exactly what you need.
I will explore each type in turn, and why type 1 is the most common to find, with each getting rarer as you head towards type 4.

1. Simple Examples

The simplistic solution that you find to problems are often due to people just copying the examples supplied with the compiler documentation. This reveals just how hit and miss the documentation can actually be. In particular some of the MSDN documentation is almost no help whatsoever, and other times it is brilliant.

Unfortunately some people seem to think it's a great idea to proliferate some of these simple examples to such an extent, it can make it very hard to find any hits that are actually helpful.

2. Overly Complicated Examples

These are immensely frustrating to come across. What I've noticed with this type of example are people using windows messages to get access to certain things, quite often requiring you to create a class that is inherited from a particular control. In itself to inherit from a particular is not a big issue, but far too often this is not necessary. I've examples where they create a new class inherited from a control, override lots of different methods, and send lots of windows messages. I know there are short comings with some of the .NET controls, but level of intervention seems way over the top. So far I've never resorted to the use of windows messages, which is something I quite honestly hated with MFC.

I always remember reading different examples for using MFC controls, where it say that you need to set up your own message pump. Noone seemed to however, show how you did that, with no links to tell you either, or if there was a link, it would be a dead page. In the end it was a friend who told me the actual code I needed to achieve this.

3. Example with too many assumptions

This can also be immensely frustrating, as you think you've found what you need, but it turns out there's lots more you need to know to make use of it. This would be okay if the person who wrote the example explained where and how you got the rest of the information you require. It then becomes a bit like putting a puzzle together, where you have to search for the next piece, hoping that it will complete the puzzle.

One particuarly nasty example of this was trying to put together all the information required to find all the devices attached to a machine, which requires several different functions to be used to get everything. Turns out it will only tell you the devices which have a driver loaded. The MSDN help explains each individual function very well, but it required a lot of searching on the internet to find out what functions people were using to get the information. Once I found that, the documentation was all I needed, but until I'd found that information, I didn't know what I needed to be looking at. This happened to be one of the rare cases where the MSDN help was able to make up for the fact that the information I found, mostly from forum posts was incomplete.

It is in answer to poorly phrased questions on a forum or newsgroup, where this type of issue can occur. Where someone just says, you need to use this class or whatever, with no explanation to go with it. Sometimes they might put a link, but over a period of time, those links become invalid, which leads to much the same problem as someone just assuming you know about about the particular things they've mentioned using.

4. Complete Explanation

This is of course what everyone wants to find, when they search for an answer to the particular problem they have encountered. To be useful such an example doesn't have to document everything in precise details, but be complete enough that you are not left wondering if and how this actually helps.

The most common places to find such examples are in blog posts, but sadly even these have a tendency to get removed over time, but generally persist for much longer.

The most critical thing is, that these examples need if applicable to relate to something that you really would program, rather than some contrived example, which misses out something that is relevant. It is important to make the example fit a real world scenario, otherwise it could just end up fitting into one of the first 3 categories, and not providing as much help as it should.

This is the category I want to try and have all my examples fit into, and will look at any feedback to try and improve the examples, if there is anything that is lacking from them. I never pretend to know all the answers, but by posting examples of how I've done something, it first of all gives me a central place to find my solution, while giving other people the chance to also find out how to do something. It also means that if there is a better way of achieving the solution, I'm open for people to tell me about it. It's only through discussing problems and ideas that the best solutions can be arrived at.