Changing code accessibility modifiers quickly

Tuesday, October 12th, 2010

I have two hints today both of them involving changing accessibility modifiers. The first is a feature of CodeRush that I accidentally discovered while testing out the Visual Studio 2010 Productivity Power Tools the second is a great new feature of Visual Studio 2010.

For those who don’t know what I mean by accessibility modifiers, those are the keywords you put before blocks of code that define how that code can be accessed, this is all enforced by the compiler giving you nice compiler error messages if you violate these rules. To provide an example the following auto-properties are all have the accessibility modifier “public”:

[Column] public string Name { get; set; }
[Column] public string Description { get; set; }
[Column] public decimal Price { get; set; }
[Column] public string Category { get; set; }

CodeRush gives you a handy way to change the User interface by clicking the icon to the left of the code block, you then get a set of actions you can perform upon the that block of code.

Code Rush Code Context Menu

As with most everything in CodeRush you can access this functionality from the keyboard anywhere within the scope of that code block by pressing Alt + Up or Alt + Down to cycle through the five possibilities:

  • public
  • internal
  • protected internal
  • protected
  • private

This means that if you need to change access modifiers, either to tighten up or relax the access points into your code you can do it by pressing a hand full of keys (between two and six to be exact), much faster than navigating to the top of the method highlighting and replacing the keyword.

My second hint is something that I have been using quite regularly, lets take the above example again:

[Column] public string Name { get; set; }
[Column] public string Description { get; set; }
[Column] public decimal Price { get; set; }
[Column] public string Category { get; set; }

I want to change all four fields to “be internal”, I could go in and change each one manually or better still use the above keyboard shortcuts (Alt + Down, Down, Alt + Down, etc.) the faster alternative would be to hold down the Alt key then select from the first character of the first “public” to the last character of the last “public” keyword.

While holding down Alt traditional selection behaviour is not followed and only the “public” keywords are selected on all four lines:

VS2010 Line Select

You can then type your new visibility modifier overwriting the selected components of all four lines in one fell swoop:

[Column] internal string Name { get; set; }
[Column] internal string Description { get; set; }
[Column] internal decimal Price { get; set; }
[Column] internal string Category { get; set; }

I think that is neat!

Finding Code Issues

Friday, October 1st, 2010

As programmers we are well known for writing bug free perfectly formed code first time round, as such I don’t really understand why DevExpress implemented the code issues feature… no wait… that should be the other way round.

CodeRush has several ways to access the Code Issues user interface, first off there is the thin file overview down the right hand side of the viewport. In the code itself there are handy contextual hints too.

Code Rush Issue In Context

In this example, “this.” is redundant and has been greyed out, if you hover over it it will tell you more about the issue and how to resolve it. Different issues have different notation so code that is to be transformed will have a coloured underline.

In the process of going though a file created by someone else the code style was a bit off – I was able to quickly bring it in line with the project preferences by using the shortcut keys Alt + PageDown to skip between the issues then Ctrl + ‘ to fix the issues quickly.

Great feature for spotting mistakes as you code, and also for learning new language features as they are introduced into the specification.

Using EVEMon Data with LINQPad

Saturday, July 31st, 2010

LINQPad is an awesome aide to .NET Developers. Written by Joseph Albahari of LinqBridge and the C# In a Nutshell series fame. LINQPad allows the developer to write, compile and run C# or VB.NET Expressions, Statements of Programs outside of Visual Studio.

Everything I am going to show you in this post can be done with Visual Studio simply by wrapping the text in a new console application, and adding references to the DLLs. However I strongly encourage you to download LINQPad and give it a go.

In the event you are using 64-bit windows and are still using LINQPad 2 you will need to download the x86 version of LINQPad 2, as all of the EVEMon assemblies are compiled for x86. If you have LINQPad 4 you don’t need to worry about.

Assuming you have EVEMon installed, the first step is to load the EVEMon.Common.dll assembly into LINQPad:

  1. Go ahead and fire up LINQPad ensure you have a new query window open
  2. Press F4 (Query -> Query Properties).
  3. Click the “Browse…” button at the bottom of the properties window.
  4. Navigate to the EVEMon install directory.
  5. Select “EVEMon.Common.dll”

While you have “Query Properties” open go to the “Additional Namespace Import” tab and add the following two lines:

EVEMon.Common.Data
EVEMon.Common

EVEMon.Common was designed to work as part of a long running process, namely the EVEMon application sitting in your system tray from when you turn your computer on until you turn it off, as such we need load the static data from the data files.

EveClient.Initialize();

Now we get to do some LINQ,

var allItems = from item in StaticItems.AllItems
	       where item.Family == ItemFamily.Ship
	       select new
	       {
	           item.Name,
	           item.Race,
	           CPU = item.Properties[DBConstants.CPUOutputPropertyID].Value.Value,
	           PG = item.Properties[DBConstants.PGOutputPropertyID].Value.Value,
	           item.Description
	       };

I could start to explain the above line by line, but there are lots of really good LINQ articles on the Internet, including one by Joseph Albahari. We will just say that the above pulls all of the ships out of EVEMon’s Items data file and selects the Name, Race, CPU, PowerGrid and Description property for each one.

Now we see my favorite aspect of LINQPad, the .Dump() extension method, simply running the following command:

allItems.Dump();

Will output the data we have just queried as a nice HTML Table:

That is all I have for you for now, I am working on a project that uses this data outside of EVEMon, keep an eye on Twitter where I will hopefully be providing a link for testing in the not too far distant future.

ASP.net 3.5 GridView RowCommand event fired twice

Thursday, April 1st, 2010

I am writing this up to hopefully save someone else time in the future, this particular problem took up six hours of my day yesterday causing quite a bit of frustration for me, as the developer, and the users of the application.

If you are searching for the solution scroll down to the bottom of the page where I will outline the solution I used to resolve the problem. It is also worth pointing out that this does appear to be fixed in .NET 4. Certainly I was able to consistently reproduce the problem with VS2008/.NET 3.5 on multiple different computers. However after converting the project to VS2010/.NET 5 I haven’t seen the issue.

Explanation of the problem

I wrote and maintain an application that publishes a list of courses and allows users to book onto these courses, what I have listed below is a simplified version of this application.

The administration console contains two lists:

  • Published Courses – courses visible to all employees.
  • Unpublished Courses - courses waiting to be published, only visible from the administration console.

Courses can be freely published (i.e. moved from Unpublished to Published) by clicking green tick. Courses that have not had any bookings made can be unpublished by clicking the red cross.

The cross and the tick are implemented as GridView ButtonFields:


<asp:ButtonField ButtonType="Image" CommandName="UnpublishCourse" 
    ImageUrl="~/images/unpublish.png" InsertVisible="False" Text="Unpublish" />

This application has been running for six months, the issue had not been observed up until yesterday. The user explained to me that when they were publishing courses they were always published in pairs, equally when unpublishing courses it was being done in pairs, concealingly unpublishing a course with bookings.

Investigating the problem

Initially I tried to reproduce this on my local machine, backed up and subsequently restored the database locally made sure I was running the same revision as the server and fired it up. Couldn’t reproduce the problem, no matter how fast I clicked it wouldn’t happen. Tried various permutations of code and database but could only reproduce on the server.

Refreshed the binaries on the server with the HEAD from subversion, problem was still happening most of the time. I confirmed that it wasn’t an issue with the stored procedures by running them manually through LinqPad.

I started putting debug statements at the entry points to the critical parts of the code, this yielded an interesting output on my development machine, each time the cross or the tick was clicked UnpublishedGridView_RowCommand was fired twice. This gave me something to search for, seems I am not the only one to have this problem, Microsoft tried to reproduce it in 2006 but couldn’t.

Solving the problem

As it turns out there are several ways of fixing the problem, several people have used timers to “debounce” the RowCommand event, assuming that the event is always going to be fired twice a session variable can be used to filter out the second event.

Because the event is only fired twice when ButtonType=”Image” not when ButtonType=”Link” you can set the text property to the HTML to render your image. This resulted in the code above becomming:


<asp:ButtonField ButtonType="Link" CommandName="UnpublishCourse" 
    InsertVisible="False" Text="<img src=images/unpublish.png />" />

This proved to be the simplest possible solution, Visual Studio 2008 throws a warning about ASP.net validation, but I can live with that as long as the application works. In addition to the simplicity of the solution it also continues to work in ASP.net 4 (which doesn’t exhibit the double event behaviour).

Lack of AutoEllipsis support in ToolStripSystemRenderer

Sunday, March 7th, 2010

AutoEllipsis is a property introduced to System.Windows.Forms.Label with .NET 3.0, which in the event of the text overflowing the rendering rectangle of the Label will trim the end and add a Ellipsis (“…”), if this does occur the ToolTip for the label will also be set to the full (untrimmed text).

Unfortunately this functionality is not available for ToolStripStatusLabel. To make things worse in the event the text overflows it disappears completely. This bug, oversight, feature or whatever you want to call it cause some confusion after the release of EVEMon 1.3.0.1912. Several people assumed the new more verbose status bar was broken, being empty and all.

We put together a kludge fix, which would set the text and if it overflowed try to guess the length with Graphics.MeasureString. This worked fairly well, it cause some flickering when resizing the window and would leave a small gap on the right hand side of the StatusStrip.

I knew there must be a better way, and seeing an article about the StringFormat class reminded me of the need to find it. Searching about a bit found me a post on Joel on Software, I refined the code a little and came up with this (which is basically identical to Tom’s solution):

public class AutoEllipsisToolStripRenderer : ToolStripSystemRenderer
{
  protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
  {
    ToolStripStatusLabel label = e.Item as ToolStripStatusLabel;
 
    if (label == null)
    {
      base.OnRenderItemText(e);
      return;
    }
 
    TextRenderer.DrawText(e.Graphics,
      label.Text,
      label.Font,
      e.TextRectangle,
      label.ForeColor,
      TextFormatFlags.EndEllipsis);
  }
}

You need to wire this code into your StatusStrip:

this.MainStatusStrip.Renderer = new AutoEllipsisToolStripRenderer();

To the ToolStripStatusLabel will also need it’s Spring property set to true, and if you want the text left aligned the TextAlign Property will need to be set to MiddleLeft.

If you want the ToolTip to work correctly the StatusStrip will need to have ShowItemToolTips set to work, and the ToolStripStatusLabel AutoToolTip set to true. It isn’t perfect as the ToolTip is displayed when the text is not truncated, but it is close enough for my purposes.

I am exploring WPF at the moment, I was glad to see the default behaviour of a StatusBar was to just stop rendering the text at the bounds of control, an ellipsis could be added with the TextTrimming and TextWraping properties:

            Some Text Goes Here, this text may be very long as demonstrated here. In the event we run out of space an ellipsis is used.

Preventing the PictureBox control from locking files

Sunday, February 28th, 2010

One of our more regular contributors to EVEMon posted on our forums showing that the application was incapable of updating cached files (specifically images), after a bit testing I discovered the following Exception was being thrown when trying to overwrite the file in question:

System.IO.IOException: The process cannot access the file 'path\filename' because it is being used by another process.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite)
   at System.IO.File.Copy(String sourceFileName, String destFileName, Boolean overwrite)
   at EVEMon.Common.FileHelper.OverwriteOrWarnTheUser(String srcFileName, String destFileName) in EVEMon.Common\FileHelper.cs:line 108
   at EVEMon.Common.FileHelper.OverwriteOrWarnTheUser(String destFileName, Func`2 writeContentFunc) in EVEMon.Common\FileHelper.cs:line 82
   at EVEMon.Common.Controls.CharacterPortrait.SavePortraitToCache(Image newImage) in EVEMon.Common\Controls\CharacterPortrait.cs:line 248

After a bit of searching around I discovered a post on StackOverflow identifying that System.Drawing.Bitmap(string filename) would lock the filename until the Bitmap was disposed of. The post presented a solution but no code, A bit of further searching confirmed my expectation that Image.FromFile(string filename) was subject to the same locking behaviour:

The file remains locked until the Image is disposed.

A bit more searching identified another post on StackOverflow which gave me the basic syntax and structure for the code I was going to need to implement this in EVEMon. The final code looks like this:

MemoryStream stream = new MemoryStream();
 
byte[] imageBytes = File.ReadAllBytes(cacheFileName);
stream.Write(imageBytes, 0, imageBytes.Length);
stream.Position = 0;
 
var image = Image.FromStream(stream);
return image;

It appears that GDI+ will lock any image that is loaded into a control in WinForms and WPF, several comments on StackOverflow and byte.com suggested that even disposing of the control and the FileStream was not a reliable way of being able to write to the file so the above method is seems to be be the best solution all round.