Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

CP Vanity

4.93/5 (80 votes)
8 Jun 2011CPOL8 min read 1   1.8K  
A viewer for CodeProject's recently introduced reputation information; futile, but fun

Introduction

This article presents a viewer for CodeProject's recently introduced reputation information. Completely futile, but fun to create, and fun to have available.

Overall Functionality

The first view presents information on a single account; it shows the user name (HTML rendered in a little WebBrowser), the reputation graph, and a list of articles (real ones and Tip&Trick ones).

CPVanity One Account

The second view presents a list of "highest achievers", i.e. the people that show up on the Who's Who pages when querying by reputation, by article count or by message count. Values for all reputation categories are listed here.

CPVanity Highest Achievers

The third view offers counter values for the same members.

CPVanity Highest Achievers

Some Functional Details

Some effort has been spent to offer functionality together with user comfort:

  • The User ID, when changed, gets stored in the registry; a single registry key is used under CurrentUser\Software\CPVanity\MemberID, so the utility will start by showing the last account it has presented in a previous session; unless it gets launched while holding the control key (no account shown), or a userID is passed on the command line (Yes, you could make desktop shortcuts for a number of accounts).
  • To honor CodeProject conventions, hitting CTRL/F5 will refresh the current view.
  • The "Highest Achievers" view applies the CodeProject coloring scheme (white, bronze, silver, gold, and platinum).
  • The champion for each reputation category gets a blinking red background, and the one account (if any) gets a blinking green background when present amongst the highest achievers. This blinking effect is conditional on a checkbox and gets persisted in another registry key CurrentUser\Software\CPVanity\Blinking.
  • The "Highest Achievers" page offers hyperlinks to the profile page of all the listed accounts; when clicked with control key down, CP Vanity loads the "One Account" view with the selected account. Since version 2.3 the "shift" button (as well as the "shift" key!) scroll the DataGridView horizontally and reveal several new values, the total counts for articles, tips, blogs, messages, questions, answers, and comments.

Limitations

There are a lot of limitations to CP Vanity, some by design, some by the principles that had to be used in order to collect the necessary information. Here is a list:

  1. The window width is fixed at 1024; that is the width the DataGridViews need to display all their information; since I don't like horizontal scrolling, I decided to settle for a fixed width that should be no problem except for the smallest displays.
  2. CP Vanity shows a snapshot; it does not provide a live image or an automatic refresh.
  3. The information is gathered by fetching a couple of CodeProject web pages and scraping their HTML content; there is an ever increasing risk that something will change (the URLs used, the page content, the HTML tags used, whatever) to such an extent that CP Vanity no longer functions as intended. If so, I may or may not provide an update.
  4. The Highest Achievers list is aggregated from the Who's Who pages, which basically offers the top members ordered by total reputation, by article count, or by message count. For some of the reputation categories, many points could be earned without creating lots of articles or messages (e.g. Organiser points are earned by voting), so it is conceivable, but not very likely, that some highly ranked people will not show up on the "Highest Achievers" page.

Some Technical Details

All the CodeProject specific things are isolated in the CPSite class, which offers methods to get URL strings, to fetch web page content, and to extract the required information. If anything changes at CodeProject, CPSite is where the changes may have to be reflected.

All web page fetching and scraping is performed by a BackgroundWorker, and of course the GUI updating is handled in the ProgressChanged and RunWorkerCompleted event handlers.

The TabControl Tabs

The configurability of the WinForms TabControl is very limited; all the tabs are rendered identically, using the TabControl's Font, ForeColor and BackColor values. So a different look-and-feel (multiple colors, hovering effects, ...) are not supported at all. This often is the subject of a question in the programming forums.

As I wanted a menu bar rather than the typical tabs, my dilemma was to either use a TabControl and somehow fake a tab strip, or use superimposed Panels rather than TabPages and control their visibility myself. The one advantage of the TabControl is that one can design the TabPages in site, within the Form itself; no separate Forms or UserControls are needed. So I decided to go for the former, and take on the fight with TabControl. This is what I came up with:

  • Inside Visual Designer, I added a Panel and a TabControl to the Form. The Right and Width properties match, the Panel.Height is sufficient to hold the new tab strip and to hide the unwanted tabs (once the Panel and TabControl get moved over one another); however the TabControl's position is under the Panel, so the TabControl initially is a bit lower, allowing both of them to be designed with ease.
  • At run-time (i.e. in the Form constructor, right after calling InitializeComponents), the TabControl's Top gets reduced and its Height gets increased by the height of the Panel, effectively sliding the native tabs under the artificial tab strip. Et voila, the ugly tabs are gone, and the look-and-feel is what was hoped for. In reality, the tab strip isn't as tall as the old tabs, however a second panel above them hides whatever protrudes.
CPVanity Designer Detail CPVanity RunTime Detail

The left image shows the Designer view: the new tab strip (green panel) will be used to hide the original (gray) tabs, which have Appearance=FlatButtons. The right image shows the run-time view, the original tabs are hidden by sliding the TabControl up and under the other panel(s).

DataGridView Problems

I've had some trouble getting the DataGridView controls to correctly render empty cells! Everything works fine when background coloring is not required; however, when a cell changes from non-empty with background color into empty (always without background), then the cell does not get erased.

The one workaround that solved (most of) the unwanted mispaints, consisted of three special measures:

  1. When the TabControl switches to another page, the newly visible DataGridView is made invisible for a while with a simple Thread.Sleep(100). That is sufficient to get a clean background before the control gets rendered as required.
  2. When the application returns from the background, the same repaint is forced.
  3. When the DataGridView gets sorted, the background coloring is suspended for a while; i.e. a boolean flag controlling background colors is set false, and a timer is launched to set it true again some 100 milliseconds later. Without this trick, toggling the sort order in some columns creates a mirrored image, where the cells from the top and those from the bottom look identical (whereas one set of them should be empty).

The above did not solve the problems about repainting (or lack thereof) that should occur when the DataGridView gets scrolled, so I kept looking for a real solution. And I finally discovered what seems to be the real problem: empty cells only work properly when no background color gets set (not even White or Transparent), so the CellFormatting event handler has to check the reputation points before setting the BackColor, and skip all of it for a zero value. I fixed the code accordingly in version V1.3 and removed the code related to the earlier workarounds. All is well now.

Regex Performance

While I'm no Regex expert, I wanted to come up with patterns that would be somewhat tolerant to changes in the HTML code used. Initially that resulted in some complex patterns containing multiple wildcards, some greedy, some lazy. The net result was scraping tended to use several seconds per page.

In a second iteration, I simplified the Regex patterns, used fewer wildcards, and fewer groups; and I used some simple string searches too. As an example, the user names and the reputation numbers are extracted with regex patterns, whereas the colors are determined by searching separately for the color names. The speed up was spectacular, scraping time now is irrelevant.

Networking

To support situations where the PC is located behind a firewall, the configuration file got adapted to this:

XML
<?xml version="1.0"?>

<configuration>
<system.net>
  <defaultProxy enabled="true" useDefaultCredentials="true" />
</system.net>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>

When a proxy server uses password-based authentication, a NetworkCredential must be issued; look into file CPSite.cs and adapt method CreateWebRequest() as required.

Conclusion

CP Vanity offers two pages of highly-condensed information at your finger tips, most of it presented in DataGridViews that can be sorted in many ways. One remarkable outcome is that the seven reputation categories currently have six different champions.

Acknowledgements

Thanks to:

  • Sacha Barber, whose Really Vain Web Spider article provided a lot of inspiration, and from whom I borrowed an icon
  • Pete O'Hanlon and Don Kackman, for providing the firewall/proxy suggestions
  • All early users for reporting their findings and offering suggestions and comments

History

  • Version 1.0 (22-Mar-2010): Original version
  • Version 1.1 (23-Mar-2010): Regional settings bug fixed; tooltips added to DataGridViews; article titles listed; minor improvements
  • Version 1.2 (23-Mar-2010): Duplicate titles bug fixed
  • Version 1.3 (28-Mar-2010): DataGridView background fixed; Bronze bug fixed; minor improvements
  • Version 1.4 (29-Mar-2010): Total reputation points and color calculated when not present at their original position
  • Version 1.5 (06-Apr-2010): Linklabel bug fixed; blink checkbox added; MVP column added
  • Version 1.7 (03-Aug-2010): accepting the latest CP styles; individual member type icons added
  • Version 1.8 (09-Oct-2010): added bookmarks column to articles table; several minor GUI improvements
  • Version 2.0 (06-Dec-2010): added support for Who's Who queried by Reputation, and cbFetchJob ComboBox; added PlatinumCount column; several minor GUI improvements
  • Version 2.1 (25-Dec-2010): updated to cope with the latest web site changes
  • Version 2.2 (27-Mar-2011): added downloads column to articles table
  • Version 2.3 (24-May-2011): added several counters to the top achievers tab, see "shift" button; updated and added some screen shots; added an executable-only download; fixed a scraping bug (the "One Account" tab failed to deal with the thousand separator in article votes, bookmarks, and downloads)
  • Version 2.4 (09-Jun-2011): added rep graph zooming

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)