Adding Skin Support to Sudoku

With the source code for Microsoft Sudoku released on MSDN at, you can take the code and modify it to your liking, adding features, putting a new UI on the game for different environments, whatever cool projects you come up with. I provided a few project suggestions at the end of the article, but I thought I'd spend a few blog posts detailing other ways the game could be extended.

One of the neat features that many apps have these days (both Web and smart client applications) is the ability to be skinned or themed, allowing users to tweak the UI to their liking. Modifying Sudoku to support basic skinning is a piece of cake, requiring only around 20 lines of code.

At present, Sudoku uses approximately 35 bitmap images for various parts of the UI. This includes some background images, images for the various buttons and icons in the UI, images that serve as suggested-cell or selected-cell highlights, etc. The easiest way to modify Sudoku to provide a skinning feature is to allow a user to easily replace these images with their own set.

Sudoku contains a file ResourceHelper.cs that provides static Bitmap properties for each of these images. The images are all stored as embedded resources in the assembly, and the static constructor for ResourceHelper loads the images from manifest resource streams through an internal method GetResourceImage:

    internal static Bitmap GetResourceImage(string resourceName)
return new Bitmap(_resourceAssembly.GetManifestResourceStream(resourceName));

The resource names supplied to GetResourceImage are strings like "Microsoft.Sudoku.Images.Background.png", "Microsoft.Sudoku.Images.CellHintUpperLeft.png", and "Microsoft.Sudoku.Images.ButtonChecked.png". Thus, the easiest way to modify Sudoku to providing skinning capabilities is to modify GetResourceImage to pull these resources from somewhere besides the assembly's embedded resources. To begin, I'll add the following code to ResourceHelper.cs:

    private static string _skinDirectoryPath;

private static string SkinDirectoryPath
if (_skinDirectoryPath == null)
_skinDirectoryPath = System.Configuration.ConfigurationSettings.AppSettings["SkinDirectoryPath"];
if (!Directory.Exists(_skinDirectoryPath)) _skinDirectoryPath = string.Empty;
else if (!_skinDirectoryPath.EndsWith("\\")) _skinDirectoryPath += "\\";
return _skinDirectoryPath;

This code adds a SkinDirectoryPath property that will return the string path to a folder containing the skin's replacement images. It pulls this path from the AppSettings section of the application's configuration file:

    <?xml version="1.0" encoding="utf-8" ?>
<add key="SkinDirectoryPath" value="C:\Sudoku\BlueSkin\" />

Now, all that remains is to modify GetResourceImage to pull an image from the skin directory if that image can be found there (if it can't be found, it will fall back to the original behavior, pulling the images from the embedded resource):

    internal static Bitmap GetResourceImage(string resourceName)
string filepath = SkinDirectoryPath;
if (filepath.Length > 0)
filepath += resourceName;
if (File.Exists(filepath)) return new Bitmap(filepath);
return new Bitmap(_resourceAssembly.GetManifestResourceStream(resourceName));

That's the total extent of the modifications to the application necessary to support basic skinning. I could of course add more code to support layout modifications, ink color changes, and so forth, but by allowing the images to be replaced with any of the user's choosing, some really nice skins can be created. For example, here are two skins I created simply by changing the background images and the color hues of the rest of the images:

You can download the image files for these skins from here and here. Simply extract the images into a directory, and then point the SkinDirectoryPath appSetting at this directory. When you launch Sudoku, GetResourceImage will discover the new images and use those instead of the ones embedded in the assembly.

Note that I pulled the background images from the Origami Project Gallery.  These images are meant be used with the Program Launcher application that ships on Ultra-Mobile PCs (UMPC) as part of the Microsoft Touch Pack, but they work equally well with Sudoku.

Comments (11)

  1. Phil says:

    Hey there, this Version of Sudoku not only looks verry appealing to the eye it also is… well, addictive… However, having downloaded the programm I foud that it won’t run on my XP Pro SP2… Darn, not knowing anything about programming really is no good… Does anybody know where I can get a version which will run? Or maybe somebody knows how to make it run? Guess it is not much more than setting a different parameter somewhere in the code. But as I said, I have no clue about those things. Your help is appreciated!

  2. If you download and install the Tablet PC SDK 1.7 and the Tablet PC 2005 Recognizer Pack, both of which should install fine onto XP Pro SP2, Sudoku should run fine.  You can get them at and (only the US English recognizer is necessary).  The former contains the Tablet APIs that Sudoku relies on, and the latter contains the handwriting recognizers.  With these installed on a non-Tablet, you’ll even be able to use the mouse as a pseudo-pen, writing in numbers and having them recognized.

  3. Phil says:

    Thanks alot! Hope I got time to try it out this weekend!

  4. Rijk says:

    I am addicted to Sudoku! I made an inventory of methods for solving even the most difficult Sudoku. Start with looking for duo’s, it’s an eye opener!

    Check for details.

    Good luck!

  5. Oisin Grehan says:

    Hey Stephen, great work. Here’s a productivity hint though — instead of checking for trailing slashes in order to combine two paths correctly, check out the automagic System.IO.Path.Combine method.

    – Oisin

  6. Yes, I could, thanks.  I would remove the ‘else’ line from the SkinDirectoryPath property and change the filepath+=resourceName line to instead use Path.Combine.  And if I was doing the retrieval of the directory path and combining it with the name in the same method, I probably would have done what you suggest.  However, assuming a directory was specified in the config file, I wanted the result of SkinDirectoryPath to always end in a ” (I think it’s a bit cleaner that way), so I’d still be doing that check and append operation in the get accessor, which limits the usefulness of Path.Combine in this particular scenario.  It’s certainly useful in general, though.

  7. bob jarns says:

    could someone post a download link to the completed sudoku program with skin support?

Skip to main content