AndrewVos.Com .NET, C#, jQuery etc.

28Jul/100

Better compile times in Visual Studio

EDIT: Tried some of these today. Results are in blue.

Where I'm working now, we have a huge Visual Studio solution with hundreds of project files. The problem with this being that compile times are drastically reduced, causing great irritation and generally just hampering production.

Having a look around the web other people are definitely having this problem. Some suggestions are:

  • Merge all the projects into one, or at very least merge any projects that can logically be merged. For example, unit test projects could really benefit from being merged.
  • Have all projects output their bits to one directory.
  • Disable anti-virus (only for the solution directory): Not much of a change. Maybe lost a few seconds build time, though results may vary. Would recommend doing this always just in case your virus checker is slowing things down.
  • Combine the project files (this is generally not a great approach because the projects are split up like this so that our concerns are kept seperated).
  • Creating new solutions which only contain smaller parts of the code base, and linking them to compiled dlls from the other projects (DLL hell).
  • Parallel builds (Tools/Options./Projects and Solutions/Build and Run/Maximum Number of Parallel Project Builds): No noticeable change. The default setting was 4 by the way.
  • Stop using TFS (purely unwarranted, but who knows? Thought I'd just throw that in there).
  • Disable indexing on your source folders (windows search). No noticeable change. Didn't really expect anything to change here, because windows search has a way of delaying indexing as far as I know.

I'm going to have a look at these items tomorrow during lunch, and will update if I find anything good!

28May/100

jQuery.shrinkTo

A cool little plugin that shrinks and fades any element to a position on the page.

View demo

Get the script here

20Apr/100

jquery.watermark

A simple jQuery plugin that allows you to watermark text inputs. Watermarking is when you show some text in a text input, then hide the text when the user focuses on the textbox.

Check the example here

Download the code here

Peace!

21Jan/100

CodeAnywhere 1.0.0.17

Version 1.0.0.17

  • Now compiles to .NET 3.5 instead of 2.0
  • Added support for updating from the context menu
  • You can now return an object instead of a string, and CodeAnywhere will do a ToString on it before writing it back

Sorry – haven’t been around in a while. Thought I’d stop by and release an awesome piece of software, CodeAnywhere.

Let’s say you have this:

CodeAnywhere1

And then you press CAPS LOCK:

CodeAnywhere2

CodeDOM compiled the code and executed it. (It’s C# code, by the way)

BAM.

I wrote this on the train travelling to work everyday.

Install it here

Things to note:

  • It uses UI Automation to grab the text, so some apps won’t work. Notepad and Wordpad definitely do though.
  • It’s meant to set CAPS LOCK state to off when it starts. Some people have reported that it doesn’t though. Comment below if this is you (state your OS please)
15Jan/090

HtmlBuilder 0.1.33

HtmlBuilder is simple web design software, and this is it’s first release.

HtmlBuilder uses a simple template system, and includes some example templates under Help/Example Projects.

The HtmlBuilder Main Window

On the left we have the Site browser, which lists all files in the site.

HtmlBuilder Main Window

The Color Chooser Window

Favorite colors can be stored on the right hand side.

HtmlBuilder Color Chooser

Requirements

.NET Framework 3.5

Downloads

Version 0.1.33

Changes

Version 0.1.33 (January 15th 2009)

Added some DTD’s to the Insert/DTD Menu.

Version 0.1.3 (January 14th 2009)

First Release.

9Jan/090

Getting music from iTunes to your G1

I wanted to export all my music from iTunes to my G1, but I wanted to maintain the folder structure like this:

Artist\Album\TrackName.mp3

Couldn’t find anything on Google so here’s some C# code to get it done. Remember to add a reference to iTunesLib (Add Reference / COM).

   1: private static class ITunesExporter{
   2:   public static void Export(string playlistName, string path) {
   3:     iTunesAppClass iTunes = new iTunesAppClass();
   4:  
   5:     foreach (IITPlaylist playlist in iTunes.LibrarySource.Playlists) {
   6:       if (playlist.Name == playlistName) {
   7:         foreach (IITTrack track in playlist.Tracks) {
   8:           if (track.Kind == ITTrackKind.ITTrackKindFile) {
   9:             IITFileOrCDTrack file = (IITFileOrCDTrack)track;
  10:             string extension = Path.GetExtension(file.Location);
  11:             string newPath = ITunesExporter.createValidFileName(path, file.Artist, file.Album, file.Name, extension);
  12:             string newDirectoryName = Path.GetDirectoryName(newPath);
  13:             Directory.CreateDirectory(newDirectoryName);
  14:             
  15:             if (File.Exists(newPath) == false) {
  16:               File.Copy(file.Location, newPath);
  17:             }
  18:           }
  19:         }
  20:       }
  21:     }
  22:   }
  23:   private static string createValidFileName(string exportPath, string artist, string album, string track, string extension) {
  24:     artist = ITunesExporter.removeInvalidFileNameCharacters(artist);
  25:     album = ITunesExporter.removeInvalidFileNameCharacters(album);
  26:     track = ITunesExporter.removeInvalidFileNameCharacters(track);
  27:  
  28:     string filePath = exportPath;
  29:     filePath = Path.Combine(filePath, artist);
  30:     filePath = Path.Combine(filePath, album);
  31:     filePath = Path.Combine(filePath, track);
  32:     filePath = Path.ChangeExtension(filePath, extension);
  33:     return filePath;
  34:   }
  35:   private static string removeInvalidFileNameCharacters(string str) {
  36:     char[] chars = Path.GetInvalidFileNameChars();
  37:     foreach (char c in chars) {
  38:       str = str.Replace(c.ToString(), null);
  39:     }
  40:     return str;
  41:   }
  42: }

You can use the code like this:

   1: ITunesExporter.Export("Phone", @"D:\Music");

”Phone” is the playlist name and “D:\Music” is the path that the files will be exported to.

If anyone want’s to recode it to use the iTunes XML file please post the code! (I am to lazy).

7Jan/092

object.Format Extension

EDIT: I've added the string extension found here

I was reading an article on haacked today, called Fun With Named Formats, String Parsing, and Edge Cases and I started thinking what if I made a format extension method for an object which used reflection to get the properties.

The following example:

private static void test() {
  CultureInfo southAfrican = CultureInfo.CreateSpecificCulture("en-ZA");

  var human = new {
    FirstName = "Andrew",
    LastName = "Vos",
    BirthDate = new DateTime(1983, 10, 23),
    MoneyInPocket = 123.34
  };

  string formatted = human.Format(southAfrican,
    "Hello my name is {FirstName}, and my last name is {LastName}.\n" +
    "My birth date is {BirthDate:D}\n" +
    "I have {{MoneyInPocket:C}} in my pocket right now.\n" +
    "Here are some random chars... { { } }{ {} {}{} }{ {} " +
    "\nThis last value fails because there's no corresponding property: {TheLastValue}."
    );
  Console.WriteLine(formatted);
}

 

Would result in the following output:

Hello my name is Andrew, and my last name is Vos.
My birth date is 23 October 1983
I have {R 123.34} in my pocket right now.
Here are some random chars... { { } }{ {} {}{} }{ {}
This last value fails because there's no corresponding property: {TheLastValue}.

 

Here's the code:

internal static class ObjectFormatter {
  /// <summary>Formats the string by replacing format items with the objects properties.</summary>
  /// <param name="obj">The <see cref="T:System.Object"></see> to format.</param>
  /// <param name="format">A <see cref="T:System.String"></see> containing the format items.</param>
  /// <returns>A copy of format where the format items have been replace by the corresponding properties.</returns>
  /// <exception cref="T:System.ArgumentNullException">format or obj is null.</exception>
  internal static string Format(this object obj, string format) {
    return ObjectFormatter.Format(obj, null, format);
  }

  /// <summary>Formats the string by replacing format items with the objects properties.</summary>
  /// <param name="obj">The <see cref="T:System.Object"></see> to format.</param>
  /// <param name="provider">An <see cref="T:System.IFormatProvider"></see> that supplies culture-specific formatting information.</param>
  /// <param name="format">A <see cref="T:System.String"></see> containing the format items.</param>
  /// <returns>A copy of format where the format items have been replace by the corresponding properties.</returns>
  /// <exception cref="T:System.ArgumentNullException">format or obj is null.</exception>
  internal static string Format(this object obj, IFormatProvider provider, string format) {
    if (format == null) throw new ArgumentNullException("format");
    if (obj == null) throw new ArgumentNullException("obj");

    const string propertyPattern = @"\{(?<PropertyName>[a-z,0-9,_]+)\:?(?<PropertyFormat>[^}]+)?\}";
    MatchCollection matches = Regex.Matches(format, propertyPattern,
      RegexOptions.Compiled |
      RegexOptions.CultureInvariant |
      RegexOptions.IgnoreCase);

    foreach (Match match in matches) {
      string propertyName = match.Groups["PropertyName"].Value;
      string propertyFormat = match.Groups["PropertyFormat"].Value;
      PropertyInfo propertyInfo = obj.GetType().GetProperty(propertyName);

      if (propertyInfo != null) {
        object propertyValue = propertyInfo.GetValue(obj, null);
        string propertyString = null;

        if (propertyValue != null) {
          propertyString = string.Format(provider, "{0:" + propertyFormat + "}", propertyValue);
        }
        format = format.Replace(match.Value, propertyString);
      }
    }

    return format;
  }
}
internal static class StringObjectInjector {
  /// <summary>Formats the string by replacing format items with the objects properties.</summary>
  /// <param name="format">A <see cref="T:System.String"></see> containing the format items.</param>
  /// <param name="obj">The <see cref="T:System.Object"></see> to format.</param>
  /// <returns>A copy of format where the format items have been replace by the corresponding properties.</returns>
  /// <exception cref="T:System.ArgumentNullException">format or obj is null.</exception>
  internal static string Inject(this string format, object obj) {
    return obj.Format(format);
  }

  /// <summary>Formats the string by replacing format items with the objects properties.</summary>
  /// <param name="format">A <see cref="T:System.String"></see> containing the format items.</param>
  /// <param name="provider">An <see cref="T:System.IFormatProvider"></see> that supplies culture-specific formatting information.</param>
  /// <param name="obj">The <see cref="T:System.Object"></see> to format.</param>
  /// <returns>A copy of format where the format items have been replace by the corresponding properties.</returns>
  /// <exception cref="T:System.ArgumentNullException">format or obj is null.</exception>
  internal static string Inject(this string format, IFormatProvider provider, object obj) {
    return obj.Format(provider, format);
  }
}
6Jan/0913

ShellContextMenu2

Here's a refactored version of the ShellContextMenu code I released a while back. It has been converted to C# and the code is much better.

A shell context menu is the shortcut menu you see when right clicking on a file in Explorer.

Shell Context Menu

Download the code here

30Dec/080

PasswordMaker

Check out PasswordMaker, a simple little script that codes simple passwords into slightly more complex passwords.

PasswordMaker

The encoder uses the simple Caesar Shift Cypher.

24Sep/080

SettingsManager 0.1

SettingsManager is a library that dynamically generates a form to allow the client to edit settings.

Take for example a class that contains the following property:

private bool someBoolean1 = true;
public bool SomeBoolean1 { get { return this.someBoolean1; } set { this.someBoolean1 = value; } }
 

To allow the client to edit this property we would typically create a Form and put some checkboxes, labels etc. on it.

With SettingsManager, we just inherit from the SettingsBase class, and apply a SettingAttribute to the property:

public class MySettings : SettingsBase {
  private bool someBoolean1 = true;
  [Setting("Demo Category", "Booleans", "Please check this box.", typeof(BooleanEditor))]
  public bool SomeBoolean1 { get { return this.someBoolean1; } set { this.someBoolean1 = value; } }
}

And show a Settings form:

MySettings settings = SettingsBase.Load<MySettings>("C:\\settings.xml");
TabbedSettingsForm settingsForm = new TabbedSettingsForm(settings);
settingsForm.ShowDialog();


And we get this:

SettingsManager

Creating custom editors

You may have noticed that the SettingAttribute constructor takes a Type. This we can use to make custom editors for types. Let's take a look at the source for the DateEditor type.

public class DateEditor : SettingEditorBase {

  DateTimePicker datePicker;

  public DateEditor(string text, object settingValue)
    : base(text, settingValue) {

    this.AddLabel(text);

    this.datePicker = new DateTimePicker();
    this.datePicker.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;

    this.datePicker.Value = (DateTime)settingValue;
    this.datePicker.ValueChanged += new EventHandler(datePicker_ValueChanged);
    this.Controls.Add(datePicker);
  }

  private void datePicker_ValueChanged(object sender, EventArgs e) {
    this.OnSettingChanged(this.datePicker.Value);
  }
}

Notice that we inherit from SettingEditorBase, which is an abstract class. Basically all that is important in this code is that we call OnSettingChanged when the value is changed. This allows the Settings form to enable the Apply button.

Creating custom Settings forms

Creating custom Settings forms is fairly easy. We inherit from SettingsFormBase, and override the InitializeEditors method. All our controls are placed on the contentPanel that is passed in as a parameter.

In InitializeEditors, we loop though this.Categories, and in turn loop through each categories' group. We then add each editor to the form.

The Ok, Cancel and Apply buttons are all taken care of in SettingsFormBase.

public class TabbedSettingsForm : SettingsFormBase {
  TabControl tabControl;
  public TabbedSettingsForm(SettingsBase settings)
    : base(settings) {
    this.Padding = new Padding(10);
  }

  public override void InitializeEditors(Panel contentPanel) {
    this.tabControl = new TabControl();
    this.tabControl.Dock = DockStyle.Fill;
    contentPanel.Controls.Add(this.tabControl);

    foreach (SettingCategory category in this.Categories) {
      TabPage tabPage = new TabPage(category.Name);
      tabPage.AutoSize = true;
      this.tabControl.TabPages.Add(tabPage);

      TableLayoutPanel content = new TableLayoutPanel();
      content.Dock = DockStyle.Fill;
      content.AutoScroll = true;
      tabPage.Controls.Add(content);

      foreach (SettingGroup group in category.Groups) {
        content.Controls.Add(new GroupTitle(group.Name));
        foreach (SettingEditorBase editor in group.Editors) {
          content.Controls.Add(editor);
        }
      }
    }
  }
}
 
Source and a Demo project is available here.