jump to navigation

February 13, 2012

Posted by codinglifestyle in Uncategorized.
add a comment

I like waffles too!

Making the Complex Simple

I’ve noticed a rather interesting thing about best practices and trends in software development, they tend to oscillate from one extreme to another over time.

So many of the things that are currently trendy or considered “good” are things that a few years back were considered “bad” and even further back were “good.”

This cycle and rule seems to repeat over and over again and is prevalent in almost all areas of software development.

It has three dimensions

Don’t misunderstand my point though, we are advancing.  We really have to look at this from a 3 dimensional perspective.

Have you ever seen one of those toys where you rock side to side in order to go forward?

snakeboard

Software development is doing this same thing in many areas.  We keep going back and forth, yet we are going forward.

Let’s look at some examples and then I’ll tell you why this…

View original post 749 more words

Advertisements

Late binding DataGridView data with BackgroundWorker threads October 18, 2010

Posted by codinglifestyle in C#, Parallelism, Uncategorized, Winform.
Tags: , , ,
1 comment so far

In an increasingly multicore world you may notice your WinForm app never pushes your machine to 100%.  Great, right?  Erm, no.  Winforms are traditionally single threaded applications meaning we typically only tap into 1/2, 1/4, or even 1/8th of our processor’s potential.

I’ve recently been working on a utility containing a DataGridView for displaying work item data from TFS. Some of the column data had to be calculated so when displaying 500+ records the whole app was slowing down considerably. What I wanted was a delayed binding such that the cell would be initially blank, launch a thread, and update itself when the thread returned with the value. It turned out this was pretty easy.

First, use a data entity. You probably don’t have to, but I find having this layer offers an obvious place to add the changes I’ll cover below. The ideal place is in the bound property’s getter. Here you can see that the value is not yet calculated, launch a thread, and return blank or another default value in the meantime.

private int _nWeight = -1;

public int Weight

{

get

{

if (_nWeight < 0)

{

Tfs.GetWeight(Tag, GetWeightComplete);

_nWeight = 0;

}

return _nWeight;

}

}

private void GetWeightComplete(object sender, RunWorkerCompletedEventArgs e)

{

_nWeight = (int)e.Result;

if (Row < FormMain.Instance.Grid.Rows.Count)

FormMain.Instance.Grid.InvalidateRow(Row);

}

The property above represents the weight of the entity to be used in sorting or graphing by importance. Calculating the weight is a time intensive operation and is a great candidate for calculating in a worker thread. Notice a backing store, _nWeight, is used to check if the value has been calculated and also to cache the value. If _nWeight is uncached (-1) we launch the thread and return a default weight of 0 while the thread calculates the actual value. Notice when we call Tfs.GetWeight we pass the delegate, GetWeightComplete, as an argument. This function will ultimately be called when the thread returns.

public static void GetWeight(WorkItem wi, RunWorkerCompletedEventHandler onCompleteEvent)

{

BackgroundWorker worker    = new BackgroundWorker();

worker.DoWork             += new DoWorkEventHandler(GetWeightDoWork);

worker.RunWorkerCompleted += onCompleteEvent;

worker.RunWorkerAsync(wi);

}

private static void GetWeightDoWork(object sender, DoWorkEventArgs e)

{

WorkItem wi = (WorkItem)e.Argument;

int result = 0;

foreach (Revision rev in wi.Revisions)

{

if (rev.Fields[CoreField.ChangedBy].Value.ToString() == wi.Store.TeamFoundationServer.AuthenticatedUserDisplayName)

result += 1;

}

result = Math.Min(result, 10);

e.Result = result;

}

When a call is made to GetWeight you can see it uses the standard System.CompnentModel.BackgroundWorker class to manage the work. This has two main advantages: 1) an easy to use asynchronous event based pattern and 2) uses the thread pool for optimal thread management. Notice the two events, DoWork and RunWorkerCompleted are set before the thread is launched and that we can pass an arguement via RunWorkerAsync. GetWeightDoWork is called when the thread is launched and sets the result to the event arguments.  When we leave this function the RunWorkerCompleted event is called.

Finally, back in the data entity, GetWeightComplete is called when the thread has calculated the value.  The result is taken from the RunWorkercompletedEventArgs and set to the backing store. The form uses the singleton pattern and exposes the grid as a property (see here). This allows the data entity to easily invalidate the row which redraws the row taking the Weight value into account (in my case the weight determined the intensity of a yellow highlight drawn over the row indicating how often the authenticated user appeared in the work item’s revision history).

The user experience when using the above method is truely fantastic.  You get a responsive UI which immediately displays information with calculated information quickly coming in a few seconds later.  The standard binding method of the DataGridView further enhances this experience by only binding the data currently shown to the user.  So if only the first 25 rows are displayed, only those values will be calculated.  As we scroll down to show more rows the DataGridView will calculate only the newly bound rows (saving loads of time for potentially 1000’s of rows never shown).  Good luck unlocking your other cores for a better UI experience.

Welcome Microsoft Delegate! Lambda expressions right this way… July 3, 2010

Posted by codinglifestyle in C#, CodeProject, linq, Uncategorized.
Tags: , , , , ,
add a comment

Delegates are deceptively great.  Without them something as simple as the OnClick event of a button would cease to work.  In a nutshell, they offer a simple way to pass a function as a parameter which in turn can be invoked anywhere, anytime.  Pointers for functions, very useful!

In .NET v2.0 the anonymous delegate was quietly introduced, well at least it slipped my notice.  I read about them at the same time I read about Lambda functions.  I saw them laid bare without the syntactic sugar in all they’re simple glory.  As I was stuck on a .NET v2.0 project I found sugar-free anonymous delegates useful to, say, recursively find all controls of a given Type and execute a function on the matching controls.

More recently, I was working on a robust Windows service responsible for various IO operations.  It was vitally important each file operation (heretofore fileop) had its own comprehensive try/catch block.  As the number of fileops increased the code looked like one huge catch block.

It was clear it would be nice to have just one try/catch block in a static utility class which could catch every IO exception conceivable.  Then I could replace each try/catch block with one-line:

bool isBackedUp = FileUtil.FileOp(_logger, () => File.Copy(latestFilename, backupFilename, true));

Notice the file copy on the other side of the lambda function syntax, () =>, is what is executed in the try block below:

public delegate void FileOperation();

internal static bool FileOp(ILogger logger, FileOperation fileOp)

{

bool success = false;

try

{

fileOp.DynamicInvoke();

success = true;

}

catch (ArgumentException argEx)

{

logger.Error(argEx, “Bad arguement(s) passed”);

}

catch (DirectoryNotFoundException dirEx)

{

logger.Error(dirEx, “The specified path is invalid”);

}

catch (FileNotFoundException fileEx)

{

logger.Error(fileEx, “The specified file was not found”);

}

catch (PathTooLongException pathEx)

{

logger.Error(pathEx, “The specified path, file name, or both exceed the system-defined maximum length”);

}

catch (IOException ioEx)

{

logger.Error(ioEx, “An I/O error has occurred”);

}

catch (NotSupportedException supportEx)

{

logger.Error(supportEx, “The requested operation was not supported”);

}

catch (SecurityException secEx)

{

logger.Error(secEx, “The caller does not have the required permission.”);

}

catch (UnauthorizedAccessException accessEx)

{

logger.Error(accessEx, “The caller does not have the required permission”);

}

catch (Exception ex)

{

logger.Error(ex, “General fileop exception”);

}

return success;

}

Not only was this an elegant way to catch a comprehensive set of exceptions, but the resulting code was much more readable.

Of course we could pass bigger hunks of code and this is fine in moderation.  But the flip-side can mean less readable code when lambda functions (and especially lambda expressions) are used without restraint.  Readability for the whole team is paramount.  After all, too much syntactic sugar will rot your teeth!

The brilliant thing about C# is the mind set of “I’m sure there’s a way to do this” is often rewarded with a little research.

PlaySound: A Better Way to Play Wav Files in C# April 30, 2010

Posted by codinglifestyle in C#, CodeProject, Uncategorized.
Tags: , , , , ,
1 comment so far

The other day I was whipping up a fun utility which played some wav files.  I was giving this to people who’s desktop us Windows Server 2008 so using the Windows Media Player COM object wasn’t an option and SoundPlayer didn’t seem to work with any of the wav files I had for some reason.

Back in my C++ days I used to do this all the time with winmm.dll’s PlaySound (and have a piece of freeware which uses this to a great extent).

Well, once again as a C# programmer I am saved by pinvoke!

public static class Wav

{

[DllImport(“winmm.dll”, SetLastError = true)]

static extern bool PlaySound(string pszSound, UIntPtr hmod, uint fdwSound);

[Flags]

public enum SoundFlags

{

/// <summary>play synchronously (default)</summary>

SND_SYNC = 0x0000,

/// <summary>play asynchronously</summary>

SND_ASYNC = 0x0001,

/// <summary>silence (!default) if sound not found</summary>

SND_NODEFAULT = 0x0002,

/// <summary>pszSound points to a memory file</summary>

SND_MEMORY = 0x0004,

/// <summary>loop the sound until next sndPlaySound</summary>

SND_LOOP = 0x0008,

/// <summary>don’t stop any currently playing sound</summary>

SND_NOSTOP = 0x0010,

/// <summary>Stop Playing Wave</summary>

SND_PURGE = 0x40,

/// <summary>don’t wait if the driver is busy</summary>

SND_NOWAIT = 0x00002000,

/// <summary>name is a registry alias</summary>

SND_ALIAS = 0x00010000,

/// <summary>alias is a predefined id</summary>

SND_ALIAS_ID = 0x00110000,

/// <summary>name is file name</summary>

SND_FILENAME = 0x00020000,

/// <summary>name is resource name or atom</summary>

SND_RESOURCE = 0x00040004

}

public static void Play(string strFileName)

{

PlaySound(strFileName, UIntPtr.Zero, (uint)(SoundFlags.SND_FILENAME | SoundFlags.SND_ASYNC));

}

}

Example:

FileInfo fi = new FileInfo(sFile);

Wav.Play(fi.FullName);

CustomValidator and the ValidationSummary Control April 26, 2010

Posted by codinglifestyle in ASP.NET, jQuery, Uncategorized.
Tags: ,
3 comments

ASP.NET validators can be tricky at times.  What they actually do isn’t particularly hard, but we have all had issues with them or quickly find their limits when they don’t meet our requirements.  The CustomValidator control is very useful for validating outside the constraints of the pre-defined validators: required fields, regular expressions, and the like which all boil down to canned javascript validation.  CustomValidators are brilliant as you can write your own client-side functions and work within the ASP.NET validation framework.  They are also unique in that they allow for server-side validation via an event.

However, there is a common pitfall when used in combination with the ValidationSummary control.  Normally, I would avoid using ShowMessageBox option as I believe pop-ups are evil.  However, where I work this is the norm and the problem is the CustomValidator’s error isn’t represented in the summary popup. 

When the ASP.NET validators don’t live up to our requirements we really must not be afraid to poke around Microsoft’s validation javascript.  It contains most of the answers to the questions you read about on the net (to do with ASP.NET validation… it isn’t the new Bible/42).  Quickly we identify the function responsible for showing the pop-up.  ValidationSummaryOnSubmit sounds good, but as the name implies it occurs only on submit.  However my validator failed after submit and now I need the popup to show what errors occurred.  I could see from the script window that this function could be called but programmatically registering the startup script wasn’t working.  So I used a jQuery trick to call the function after the DOM had loaded.

So drumroll please, there is the information you want to copy and paste in to your CustomValidator event:

if (!args.IsValid)
{
ScriptManager.RegisterStartupScript(this, this.GetType(), “key”, “$(function() { ValidationSummaryOnSubmit(‘MyOptionalValidationGroup’)});”, true);
}

Now my server-side validation will bring up the ValidationSummary messagebox.

Gong! v2.0 Press Release May 5, 2006

Posted by codinglifestyle in Uncategorized.
Tags: , , , , ,
add a comment

Well, this is as close as I’m ever going to get to a press release. 

A small piece of freeware I’ve been working on for some time has recently been officially released.  This is really a Frankenstein of utilities I personally find handy to have in the system tray.  A lot of it has been a programming exercise, like the auto-upgrade feature.  The code is written in VC++ w/ MFC.  Yes old school, but does offer maximum compatibility.  There are probably a lot of classes I will eventually release to CodeProject over the following months.  Here is the blurb:

 

Gong! offers fast, flexible control over your system volume. Use the Win key to mute, raise, or lower volume. Pin the volume to the screen for total control even in Remote Desktops or Virtual Machines. Set additional sound events like an hourly chime. Make your computer sound like a grandfather clock! Set a sleep time to keep your computer quiet at night. Set graphical and/or auditory reminders in 2-clicks. See a countdown on your screen when its time to leave work. Keep your system time accurate with the atomic clock. Quickly access a calendar in 2-clicks. Make decisions with the Hainted 8-Ball!

 Take a look and download at http://www.loungeware.net