Visual Studio 2010’s WPF Source Editor

The last couple of days I’ve been enjoying reading/listening to the announcements coming out of PDC – as I’m sure has most of the Microsoft Developer community.

Tonight I watched the on-demand keynote. The highlights for me:

  • Windows 7 Taskbar Enhancements
  • Windows 7 Multi-touch
  • WPF demos! In fact, lots of WPF love in general!
  • Visual Studio 2010 shell and editor moved to WPF
  • “Much improved” WPF design experience (including Silverlight)
  • Programming against the Live Mesh API

And the ultimate highlight was watching Scott “Gu” show has easy it was to extend the design time source editor in Visual Studio 2010 which is rendered in WPF (around 1:30:00 in the video). As simple as implementing an interface (ITextViewService), decorating with an “Export” attribute and then dropping the assembly into the extensions folder. No other registration required. Interestingly, Visual Studio is itself using the new Managed Extensibility Framework, including its support for Add-Ins. What was even cooler (from my perspective) is that Scott’s demo “add-in” showed how easy it was to re-render XML source comments with a custom UserControl declared in XAML.

VS2010 Source Code Adorner   

Hey – I think I predicted/wished for that feature :-p. This is even better – now I can build my own and customize however I like!

Building delimited lists

As developers we often find ourselves writing the same simple bits of logic over and over again. Today at work I noticed one of my co-workers (let’s call him Benjy) writing a very simple routine to format some output for diagnostics. It went something like this:

        public static string FormatAsCommaDelimitedList(object[] args)
{
var builder = new StringBuilder();
foreach (object arg in args)
{
builder.Append( (builder.Length > 0 ? ", " : "") + arg.ToString());
}
return builder.ToString();
}

I commented that whilst his implementation was fine (and I’m sure we’ve all written something similar in the past) it annoyed me that the condition within the loop made it look so ungainly. It was then that a few things clicked. I mentioned that if it were a simple array of strings we could concatenate using String.Join(). Benjy then applied his philosophy of “thou should never write in a loop what can better be expressed as a query”. And thus was born the following:

        public static string AsCommaDelimitedList<T>(IEnumerable<T> items)
{
return String.Join( ", ", items.Select<T, string>( item => item.ToString() ).ToArray() );
}

Not satisfied with that, Benjy went on to create a neat little CSV routine expressed as an extension method so as to be available to any enumerable collection of objects.

       public static string ToCSV<T>(this IEnumerable<T> items, string delimiter, bool quoteAll)
{
string quoteChar = "\"";
return String.Join(
delimiter,
items.Select<T, string>(
item => item.ToString().Contains(quoteChar) || quoteAll
? String.Format("{0}{1}{0}", quoteChar, item)
: item.ToString()
).ToArray()
);
}

If you ignore his ghastly formatting (and the bug which I’m sure is just there to test me) then that’s pretty cute.

I figured at this point I ought to at least pretend to contribute something – so here’s a version that allows the object to be formatted. Works with IFormattable types like Int32, Decimal, Float, DateTime etc.

        public static string ToFormattedList<T>(this IEnumerable<T> items, string delimiter, string format)
where T : IFormattable
        {
return String.Join(
delimiter,
items.Select<T, string>(
item => item.ToString(format, System.Globalization.CultureInfo.CurrentCulture)
).ToArray());
}

In deference to Benjy (a strong believer in console applications and mono-spaced fonts) here’s the simple Console Main() I used to test these:

        public static void Main(string[] args)
{
Console.WriteLine(args.ToCSV(", ", true));
Console.WriteLine(args.AsCommaDelimitedList());
var amounts = new decimal[] { 2.1m, 4, 4.5m, 9, 3.333m, 4.14m };
Console.WriteLine(amounts.ToCSV(", ", true));
Console.WriteLine(amounts.AsCommaDelimitedList());
Console.WriteLine(amounts.ToFormattedList("  |  ", "$#,##0.00"));
Console.ReadLine();
}

And the corresponding output in all its dumb terminal glory.

"The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog."

The, quick, brown, fox, jumped, over, the, lazy, dog.

"2.1", "4", "4.5", "9", "3.333", "4.14"

2.1, 4, 4.5, 9, 3.333, 4.14

$2.10  |  $4.00  |  $4.50  |  $9.00  |  $3.33  |  $4.14

On the subject of formatting I enjoyed this blog post on Visual Studio Debugging Tips. Particularly the explanation of how to use conditional formatting with the DebuggerDisplay attribute. Worth a look!

Validation Template without Binding Errors

WPF guru Josh Smith has just put up a great post here about how to access the validation errors on a WPF control without getting lots of binding debug output. Most samples (including MSDN documentation) suggest you should use Validation.Errors[0] which generate debug output for a binding failure whenever there are no errors (since Errors[0] doesn’t exist).

The format of the template that I commonly use (which also avoids the Errors[0] issue in almost exactly the same way) is as follows:

        <ControlTemplate x:Key="DefaultErrorTemplate">
            <DockPanel DataContext="{Binding ElementName=adorner, 
Path
=AdornedElement.(Validation.Errors)/
ErrorContent}"> <Ellipse x:Name="Ellipse"
DockPanel.Dock
="Right"
Margin
="2,0,2,0"
Width
="14" Height="14"
VerticalAlignment
="Center" Stroke="#40000000" StrokeThickness
="2" Fill="Red"> <Ellipse.ToolTip> <Border MaxWidth="350"> <ContentControl FontSize="14" Content="{Binding}"/> </Border> </Ellipse.ToolTip> </Ellipse> <Border BorderBrush="#40FFAF00" BorderThickness="2" IsHitTestVisible="False"> <Border.Background> <SolidColorBrush Color="Red" Opacity="0.2"/> </Border.Background> <AdornedElementPlaceholder Margin="-2" Name="adorner"/> </Border> </DockPanel> </ControlTemplate>

Normally instead of hard coding the colours I would use a colour converter that maps the severity of the error (through a custom property) to the relevant colour, e.g. error=red, warning=orange etc.

My equivalent of Josh’s sample project is here.

CleanlyBindToValidationErrors

Convenience PCs

Today I took my son to the computer store to buy some parts for his new machine. We’d recently tried to upgrade his Pentium 3 to Windows Vista – but whilst the install worked the performance was terrible. The box only had 512Mb RAM and the aging 30Gb drive eventually failed after so much page swapping whilst attempting to install SP1.

Over the last few years the relative price of buying or building your own decent PC has dropped dramatically, but today when I got home to rummage through the goodies we’d bought the scale of this really hit home. Here’s a few examples:

Transcend 2GB RAM Stick – $38 – assuming 2Gb is today’s standard mid-low end spec – that’s pretty good.

Samsung 640Gb HDD – $84 – hard disk space truly is no longer a problem. I’m finally at the point where all my machines have ample hard disk space, including enough to ensure all information is stored redundantly on at least two drives/machines. Having said that based on this recent review, I’m really looking forward to getting a couple of SSD drives in my development machine. Seems the (Veloci)Raptors reign as the king of consumer priced performance drives is over.

To offset these ridiculously cheap components I bought a few “luxury” items.

Intel Core 2 Quad 8200 – for my development machine, son will get my old Core 2 Duo.

Asus EAH3650 Silent HDMI – ATi Radeon 3650 passive cooled with HDMI output (HDCP) and H.264 & VC1 hardware decoding – for the HTPC.

But then there were the two super-budget items that almost defy reason. Whilst these are definitely budget, no-frills items they come from two of my most respected hardware manufacturers – ASUS and Samsung.

Samsung DVD-RW – $27 – does anyone else remember the original Pioneer DVD burner from 2000 (A01). It cost $8000 and the RW discs were $100 each!

ASUS P5KPL-CM motherboard – $58 – that’s Core 2 Duo/Quad 45nm compatible, gigabit LAN, 4 SATA, integrated graphics, PCI Express x16,x1 & 2 x PCI, 4 (+4 int.) x USB, 8 channel audio in a micro ATX format. Take a look at it – the left is the board from above, the right is roughly a 5x4cm section from below.

DSC08570       DSC08572

Now tell me – how is this made for under $58. Surely the individual electrical componentry, the copper, the included cables and the friggen high quality full colour box must cost that much. Then think about the cost involved in designing this specific board layout, building the dies, setting up factory lines, shipping, support etc.

Now I’m really looking forward to the weekend so my son and I can put all this stuff together, scavenging and replacing bits from various machines to build his new box and then re-install Vista. I’ve been building my own PCs for many years – its great fun and pretty much idiot proof these days. Strongly recommended