VS2010 Intellisense and refactoring

I’ve been spending a little more time recently with Visual Studio 2010 Beta 1. In particular building a solution from the ground up (including TFS integration) and doing a fair bit of prototyping. Some of the new editor improvements in VS2010 are really pretty neat.

One of the first changes that you notice in the editor of course is the changes to intellisense. It now includes auto-filtering, but not just by a “starts-with” search but using more of a “contains” approach. This includes the ability to search for multi-word names using abbreviations, e.g. “AQN” to match “AssemblyQualifiedName.“ Personally I think the filtering works particularly well. Having used Resharper’s intellisense filtering I wasn’t to keen on the idea, I find that implementation to be slow and it somehow feels invasive. The VS2010 implementation IMHO is much better.

VS2010 Filtered Intellisense

I’ve started using the “consume-first” toggle, which is a great way to prevent Visual Studio from being over-zealous with auto-completion. This is useful when you’re building code against a set of yet-to-be-written APIs (i.e. consuming the API first).

VS2010 Consume First Mode

Just press the Ctrl+Alt+Space combination and auto-completion is suspended.

VS2010 Consume First Not Yet Created Class

The code generation options have also had a tweak with the “Generate other…” dialog.

VS2010 Generate Class

Lots of good options here – particularly being able to specify in which project to create the new file.

VS2010 Generate Other

(Refer here for more VS2010 code-focused changes).

{sigh} It’s getting harder and harder to go back to Visual Studio 2008.

Circular Layout Panel v2

On the flight to Remix09 last week I had fun putting together a simple WPF Circular Layout Panel. Today I decided that a nice “extra” feature would be to have the child elements optionally rotated so that they are normalised with the centre of the layout panel.


So after adding a new attached dependency property, IsNormalised I updated my sample clock and fan menu. The following XAML…

<Window x:Class=”PanelTest.Window1″
xmlns
=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x
=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Circular Panel Examples” Height=”405″ Width
=”383″
xmlns:local
=”clr-namespace: PanelTest”
xmlns:panels=”clr-namespace:Spencen.Panels;assembly=Spencen.Panels”
>
<
DockPanel
>
<
DockPanel.Resources
>
<!– Stuff to make buttons pretty –>
</DockPanel.Resources
>
<Ellipse Fill=”LightYellow” Stroke=”LightGray” StrokeThickness=”1″ StrokeDashArray
=”0,1,1,0″ />
<panels:CircularPanel StartAngle=”-90″ EndAngle=”630″
TextBlock.FontSize=”24pt”>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>XII</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>I</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>II</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>III</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>IV</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>V</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>VI</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>VII</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>VIII</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>IX</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>X</TextBlock
>
<
TextBlock panels:CircularPanel.IsNormalised=”True”>XI</TextBlock
>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>
<
Ellipse Width=”5″ Height=”5″ Fill=”Black”
panels:CircularPanel.RadiusScaleX=”0.9″ panels:CircularPanel.RadiusScaleY
=”0.9″/>




<
Line x:Name=”secondHand” Fill=”Black” X1=”0″ X2=”0″ Y1=”0″ Y2=”100″
Stroke=”Red” StrokeThickness=”1″ StrokeStartLineCap=”Triangle” StrokeEndLineCap
=”Round”
panels:CircularPanel.FixedAngle
=”-90″
panels:CircularPanel.RadiusScaleX
=”0.4″
panels:CircularPanel.RadiusScaleY
=”0.4″
panels:CircularPanel.IsNormalised
=”True”/>
<
Line x:Name=”minuteHand” Fill=”Black” X1=”2″ X2=”2″ Y1=”0″ Y2=”70″
Stroke=”Black” StrokeThickness=”5″ StrokeStartLineCap=”Triangle” StrokeEndLineCap
=”Round”
panels:CircularPanel.FixedAngle
=”-60″
panels:CircularPanel.RadiusScaleX
=”0.3″
panels:CircularPanel.RadiusScaleY
=”0.3″
panels:CircularPanel.IsNormalised
=”True”/>
<
Line x:Name=”hourHand” Fill=”Black” X1=”5″ X2=”5″ Y1=”0″ Y2=”50″
Stroke=”Black” StrokeThickness=”10″ StrokeStartLineCap=”Triangle” StrokeEndLineCap
=”Round”
panels:CircularPanel.FixedAngle
=”-180″
panels:CircularPanel.RadiusScaleX
=”0.2″
panels:CircularPanel.RadiusScaleY
=”0.2″
panels:CircularPanel.IsNormalised
=”True”/>
<
Ellipse Fill
=”Black”
panels:CircularPanel.FixedAngle
=”0″
panels:CircularPanel.RadiusScaleX
=”0″
panels:CircularPanel.RadiusScaleY=”0″ Width=”30″ Height
=”30″ />
<
panels:CircularPanel.Triggers
>
<
EventTrigger RoutedEvent
=”Loaded”>
<
BeginStoryboard
>
<
Storyboard
>
<
DoubleAnimation Duration=”0:1:0″ By=”360″ RepeatBehavior=”Forever”
Storyboard.TargetName=”secondHand”
Storyboard.TargetProperty
=”(panels:CircularPanel.FixedAngle)”/>
<
DoubleAnimation Duration=”1:0:0″ By=”360″ RepeatBehavior=”Forever”
Storyboard.TargetName=”minuteHand”
Storyboard.TargetProperty
=”(panels:CircularPanel.FixedAngle)”/>
<
DoubleAnimation Duration=”12:0:0″ By=”360″ RepeatBehavior=”Forever”
Storyboard.TargetName=”hourHand”
Storyboard.TargetProperty
=”(panels:CircularPanel.FixedAngle)”/>
</
Storyboard
>
</
BeginStoryboard
>
</
EventTrigger
>
</
panels:CircularPanel.Triggers
>
</
panels:CircularPanel
>
<
panels:CircularPanel Padding=”45″ StartAngle=”-90″ EndAngle=”-90″
>
<
Button panels:CircularPanel.IsNormalised=”true”>1</Button
>
<
Button panels:CircularPanel.IsNormalised=”true”>2</Button
>
<
Button panels:CircularPanel.IsNormalised=”true”>3</Button
>
<
Button panels:CircularPanel.IsNormalised=”true”>4</Button
>
<
Button Panel.ZIndex=”1″ Background=”Gray”>Menu</Button
>
<
Button panels:CircularPanel.IsNormalised=”true”>5</Button
>
<
Button panels:CircularPanel.IsNormalised=”true”>6</Button
>
<
Button panels:CircularPanel.IsNormalised=”true”>7</Button
>
<
Button panels:CircularPanel.IsNormalised=”true”>8</Button
>
<
panels:CircularPanel.Triggers
>
<
EventTrigger RoutedEvent
=”MouseEnter”>
<
BeginStoryboard
>
<
Storyboard
>
<
DoubleAnimation To=”-180″ Storyboard.TargetProperty
=”StartAngle”>
<
DoubleAnimation.EasingFunction
>
<
ElasticEase Springiness=”10″ Oscillations
=”2″/>
</
DoubleAnimation.EasingFunction
>
</
DoubleAnimation
>
<
DoubleAnimation To=”0″ Storyboard.TargetProperty
=”EndAngle”>
<
DoubleAnimation.EasingFunction
>
<
ElasticEase Springiness=”10″ Oscillations
=”2″/>
</
DoubleAnimation.EasingFunction
>
</
DoubleAnimation
>
</
Storyboard
>
</
BeginStoryboard
>
</
EventTrigger
>
<
EventTrigger RoutedEvent
=”MouseLeave”>
<
BeginStoryboard
>
<
Storyboard
>
<
DoubleAnimation To=”-90″ AccelerationRatio=”0.5″ DecelerationRatio=”0.5″
Storyboard.TargetProperty
=”StartAngle”/>
<
DoubleAnimation To=”-90″ AccelerationRatio=”0.5″ DecelerationRatio=”0.5″
Storyboard.TargetProperty
=”EndAngle”/>
</
Storyboard
>
</
BeginStoryboard
>
</
EventTrigger
>
</
panels:CircularPanel.Triggers
>
</
panels:CircularPanel
>
</DockPanel
>
</
Window>

Now produces…


 CircularPanel - Normalised


For reference this is so much easier than doing the same thing in WinForms. Custom layout panels really were quite a pain.


Updated source code for CircularPanel is here.

Remix09 Recap

Remix09 Last year I went to Remix08 in Melbourne (scaled down aussie version of Mix08). One of the main attractions was the fact they were giving away a copy of Expression Suite 2 to every attendee – not bad for the $199 entry fee!

This year I decided to go to Remix09 not for software bargains, but because of the quality of last year’s event. Presumably the GFC meant that the event was only held in Sydney this year. Here’s my take on the conference this year.

GoodWindows Mobile 6.5 Development

  • Keynote was packed with lots of good Aussie demos.
  • Matt Morphett on design prototyping and Sketchflow – for me he was the outstanding presenter of the day. [Make sure you check out the video when it comes online late next week.]
  • Silverlight 3 and Expression 3 demos – behaviours, blend visual state manager support, animation easing, 2.5D, shaders etc.
  • Windows Mobile 6.5 was demoed along with plans for the Australian launch and overview of the “Marketplace” to compete with “fruit phone”. Check out the Australian dev centre.
  • Virtual Earth Live Bing Maps for Silverlight. Some nice demos – I liked the GIS integration.

Bad

  • Internet connections. Its a shame that every time I attend a Microsoft conference in Australia the available internet connection sucks. It’s bad enough that the delegates get WiFi that drops out and 3G/NextG saturation, but when the presenters can’t get a reliable/performant connection if really affects demos.
  • Seating was a bit quishy in Ballroom 3. OK – if that’s all I’ve got to complain about I’m thinking this must have been a pretty good day .

Remix10?

There seems to be a question mark around having a Remix conference at all next year. I for one would be disappointed not to see the event return.

Circular Layout Panel

I’ve been given an opportunity to write a custom WPF layout panel. This is something that I’ve been wanting to try for ages but have never really had the need. Rather than jumping straight in to some potentially complex layout algorithms, I figured that I’d start with something trivial just to get the hang of things. Hence the CircularPanel was born.

The CircularPanel is a simple Panel derivative that lays out its children in a circular arrangement. It has some useful dependency properties to allow some customization.

  • StartAngle – Angle in degrees at which the first child element will be positioned.
  • EndAngle – Angle in degrees at which the last child element will be positioned. If the EndAngle forms a complete circle, e.g. Math.Abs(StartAngle-EndAngle) > 360 then rather than positioning the last element on top of the first the element an angle will be included between first and last elements.
  • Padding – As per standard – reduces the space within the panel used to layout the child elements.

When adding these properties I originally missed the AffectsArrange flag on the property registration’s FrameworkElementMetaData. Without this flag changing the property (for instance in the designer) would not cause the control to re-render.

I also added some attached dependency properties. These properties can be used by the child UI elements to dictate an override to the default behaviour.

  • FixedAngle – Overrides the default automatic assignment of angle based on child index. Instead the child element is placed at the fixed angle specified in degrees.
  • RadiusScaleX – Allows the radius to be scaled in the X direction for this child element – defaults to 1.
  • RadiusScaleY – Allows the radius to be scaled in the Y direction for this child element – defaults to 1.

When adding these attached properties I made sure I included the AffectsArrange flag. Of course this wasn’t right – changing the attached property requires the parent to re-calculate the arrangement, it doesn’t affect the applied elements arrangement. I updated the flag to AffectsParentArrange and all was good.

Now I’m not sure how much real-world value this panel has – but I did get the combination of these properties to produce some interesting affects. For example:

Set StartAngle = 0, EndAngle = 1080 and then have each element decrease the RadiusScaleX/Y via binding. This produces a nice sprial.

CircularPanel - Spiral

Add 12 auto-placed elements, then three more using FixedAngle combined with an animation to produce a clock with hour, minute and second hands.

CircularPanel - Clock

Use an animation over StartAngle and EndAngle to produce an effect similar to opening a fan.

CircularPanel - Fan

Here’s the interesting code from the ArrangeOverride method on CircularPanel.

protected override Size ArrangeOverride(Size finalSize)
{
int numberOfVisibleChildren = InternalChildren
.OfType<UIElement>()
.Count(u => u.Visibility != Visibility.Collapsed
&& !GetFixedAngle(u).HasValue); if (numberOfVisibleChildren == 0) return finalSize;
// Short circuit if there are no children int currentChildPosition = 0; double startArcAngle = StartAngle / 180 * Math.PI; double endArcAngle = EndAngle / 180 * Math.PI; double arcDelta; if ( Math.Abs(startArcAngle-endArcAngle) >= Math.PI * 2 ) // If we have a full circle then don't end the last element on the
// EndAngle because that would overlay the StartAngle.
arcDelta = (endArcAngle - startArcAngle ) / (double) numberOfVisibleChildren;
else // If we have less than a full circle then make sure we spread the
// elements with first and last on the start and end angles.
arcDelta = (endArcAngle - startArcAngle) / ((double)numberOfVisibleChildren - 1); double maxChildWidth = InternalChildren
.OfType<UIElement>()
.Max( u => u.DesiredSize.Width ); double maxChildHeight = InternalChildren
.OfType<UIElement>()
.Max( u => u.DesiredSize.Height ); double radiusX = ( finalSize.Width - Padding.Left - Padding.Right - maxChildWidth ) / 2; double radiusY = ( finalSize.Height - Padding.Top - Padding.Bottom - maxChildHeight ) / 2; Point midPoint = new Point( radiusX + Padding.Left + maxChildWidth / 2,
radiusY + Padding.Top + maxChildHeight / 2); foreach (UIElement child in InternalChildren) { var childAngle = startArcAngle + arcDelta * currentChildPosition; double? fixedAngle = GetFixedAngle(child); if (fixedAngle.HasValue) childAngle = fixedAngle.Value / 180 * Math.PI; double x = Math.Cos( childAngle ) * radiusX * GetRadiusScaleX(child) +
midPoint.X - child.DesiredSize.Width / 2; double y = Math.Sin( childAngle ) * radiusY * GetRadiusScaleY(child) +
midPoint.Y - child.DesiredSize.Height / 2; child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
// Ignore collapsed children and FixedAngle children. if ( child.Visibility != Visibility.Collapsed && !fixedAngle.HasValue ) currentChildPosition++; } return finalSize; }

Source code with simple sample application here. It’s a VS2010 solution/project but should be easy to converted to VS2008 – just remove the EasingFunctions in the sample app XAML.

Windows 7 RC and Visual Studio 2010 Beta – Hands on

A while back I posted that I had installed the Windows 7 64bit Beta on my main development machine as a dual boot with Vista and that all looked good. A couple of weeks after that post my machine inexplicably stopped booting into Vista despite my attempts to perform a repair. So I’ve been running Windows 7 now for quite a while.

This week, along with everyone else I re-paved the machine with Windows 7 RC. On top of that I installed Visual Studio 2010 Beta and also jumped through the numerous hoops to install VS2010 Team Foundation Server on a virtual Windows 2008 Server instance running on my WHS box.

So far:

  • The Windows 7 taskbar is improved by the additional key/mouse combos, e.g. Ctrl-LeftClick to quickly cycle through instances of an application.
  • Windows 7 install is still the best Windows installation ever – which is good because for a while there Windows was getting consistently worse.
  • Team Foundation Server is still a long installation process, but mainly now due just to the pre-requisites, e.g. Windows Server, IIS, SharePoint, SQL Server/Reporting Services. The install documentation is good – but it would pay to read through most of it before you install – which of course no-one (myself included) will ever do.
  • Visual Studio 2010 is looking pretty good. If the new WPF text editor is anything to go by then the new font improvements in WPF 4/DirectWrite have worked well.
  • There are typical Beta quirks in VS 2010 – it crashes occasionally, when you zoom in the editor the scroll bars also zoom (which looks most odd).
  • Visual Studio start page is so easy to customize now. This article shows how you simple toggle an option and then build whatever XAML you like for the startpage. Either just extending what’s already there or completely re-writing or re-skinning. Very cool!
  • A number of Visual Studio extensions are beginning to popup. Including editor extensions for creating Regex’s with intellisense, adding images inline with source code as well as some project templates, e.g. WPF application with tray icon.

Xceed WPF DataGrid – Part 1

Vendor Choice

Having met a number of obstacles in getting Microsoft’s WPF DataGrid control to function as I required I decided it may be prudent to look at some of the other offerings. In the past I’ve been a big fan of the DevExpress suite of WinForms controls.

However, DevExpress have been a little slow to get on the WPF bandwagon. In fact even now (April 2009) their grid control is still only in Beta (expecting release in mid 2009). That’s a two full years behind the offerings from Xceed and Infragistics – what were they thinking!? Even if they did release now I’m really not sure I want to be working with a v1 DataGrid control when other vendors have more mature products available.

I remember taking a look at the Xceed WPF DataGrid when it first appeared – back in early 2007. At the time I found the demo app to be quite off-putting. All orange glow and black gloss with ridiculously rounded corners.

However, whilst searching the internet for clues on using Microsoft’s WPF DataGrid I had stumbled across a number of posts/articles related to the Xceed grid. In fact many more so than any other WPF grid control. So from this I figured it must have an active community, which got me to thinking that maybe it was time to see how far the Xceed offering has come in the last two years?

Comparison against Microsoft’s WPF DataGrid

So how does the Xceed DataGrid stack up against Microsoft’s? Here are some of the benefits that I’ve found so far:

  • Binding to SelectedItem works just fine.
  • ReadOnly properties support at Grid, Column and Row level.
  • CheckBox column allows simple styling whilst preserving ReadOnly value.
  • Automatically supports current selection and edit indicators in the row header.
  • The grid theme matches the OS theme out of the box. This is how it should be. Sure the grid can be custom styled to suit but it only makes sense that by default the grid should match the look and feel of the standard themed controls.
  • When auto-generating column headers it correctly uses any System.ComponentModel.DisplayName attributes that have been applied to the underlying class.
  • There are lots of options at grid and column level that determine how a cell should enter edit mode. This is very useful for columns such as CheckBox columns where requiring a click to enter edit mode can be highly annoying (since the user would expect the click to toggle the checkbox).

In short – most of the stumbling blocks that I’ve hit getting the Microsoft WPF DataGrid to do something pretty trivial “just work” with the Xceed grid. That’s not to say there was no learning curve at all – I had to wrap my head around setting the ItemsSource to a DataGridCollectionView rather than direct to a ObservableCollection<T> to get anything to display for a start. But this was glaringly obvious as soon as I looked at any of the samples and “how to” guides. The supplied documentation is OK, but what impressed me most was the feedback provided on Xceeds community forums. Some really good answers provided by the Xceed team in an ultra timely fashion.

So what could be improved with Xceed’s DataGrid? Well, its a little early for me to provide a comprehensive list here – but off the cuff I’d make the following suggestions:

  • An easier mechanism for custom sorting. Rather than having to specific custom IComparer implemenations often it is easier to refer to an unbound property that contains the raw data. Like Microsoft’s SortMemberPath property. Hmm… I wonder if you could use a generic SortComparer to provide the same functionality?
  • Smaller assembly size. I know these days 2.08Mb shouldn’t be an issue but for my current contract it is. We have a ClickOnce application that is deployed to machines in remote country areas. Many of these machines are still using dial-up! Adding another another 2Mb to our current 4.5Mb total is a decision not to be made too lightly. [We’ve already been burned with a ridiculously bloated NHibernate assembly (1.6Mb)]

As much as I’ve had fun with the Microsoft DataGrid I’m now considering making the Xceed’s my DataGrid of choice – certainly for my own projects. Expect to see a few more posts on the Xceed DataGrid coming up soon.

References

Microsoft WPF DataGrid – www.codeplex.com/wpf

Xceed WPF DataGrid – www.xceed.com

Hard Drive Performance

Today I spent an hour or so reconfiguring the hard disks in a few of my home machines. The idea was to boost the Windows Home Server machine  to 2Tb and also replace the aging 120Gb ATA drive in my main dev box (the oldest of four drives in that box and my last remaining ATA drive in service).

Once I was done swapping physical drives I wanted to check that the drive I was going to use to install the Windows 7 64bit RC build was sufficiently speedy. I decided to run a simple drive benchmark across my widely varying collection of disks. The results are as follows:

            120Gb                          200Gb                              400Gb                           640Gb                         1500Gb

HDD Benchmark 120Gb HDD Benchmark 200Gb HDD Benchmark 400Gb HDD Benchmark 640Gb HDD Benchmark 1500Gb

So the 120Gb drive that cost me AUD$413 in July 2002 has about one third the read speed of the latest 1.5Tb drive that cost me AUD$199.

From a cost perspective the 7 year old drive cost me $3.44 per gigabyte, compared to the new drive at just $0.13 per gigabyte. Still this pales in comparison to my first 20Mb hard drive that I bought 20 years ago for $950. That works out to $45000 per gigabyte!

Problems binding to SelectedValue with Microsoft’s WPF DataGrid

I had been seeing some odd exceptions being thrown by the WPF DataGrid code when interacting with the “new row” place holder.

GridEditing - SelectedItem FormatException

I could identify that the error was occurring because I had data-bound to the SelectedItem property on the DataGrid like so:

<toolkit:DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False"
                  SelectedItem="{Binding SelectedPerson}"
IsSynchronizedWithCurrentItem="True">

Both the Persons collection and SelectedPerson are properties on my ViewModel (VM). Its possible to use CollectionViewSource.GetDefaultView(Persons).CurrentItem – but I find it useful to expose and bind a simple read/write property. I’ve used this previously for ListView and ListBox without a problem.

I spent some time debugging this right down through BindingExpression and DependencyObject.SetValue. As far as I can tell the exception is thrown because a ConvertBack method (on the default converter) fails when dealing with the MS.Internal.NamedObject that represents the NewItemPlaceholder. This instance is used to represent the blank “new row” if CanUserAddRows is set to True (and the collection supports it). In fact it appears as if the FormatException is actually being thrown within an exception handler whilst attempting to Trace the binding failure. Whoops!

Initially I tried simply putting an try/catch block around the DataGrid code shown above. However, the exception occurred under various conditions – focus on new row, begin edit on a new row and rollback on a new row. Not all of these could be easily caught because they would leave the grid in an invalid state. Eventually the answer (HACK) became obvious – to use a converter on the binding.

using System;
using System.Windows;
using System.Windows.Data;
namespace GridEditing.Converters
{
public class IgnoreNewItemPlaceHolderConverter : IValueConverter
{
private const string NewItemPlaceholderName = "{NewItemPlaceholder}";
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
return value;
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
if ( value != null && value.ToString() == NewItemPlaceholderName )
return DependencyProperty.UnsetValue;
return value;
}
}
}

All we are doing here is not binding when we encounter the “new row” instance. Notice the curly braces in the NewItemPlaceholder ToString() representation? This, I believe, is why it causes the FormatException since the ToString() is used to construct a formatString which is then passed to the TraceEvent method. However, because the curly braces aren’t escaped it expects a string token number, e.g. {0} as per string.Format().

Anyhow, using the converter above means that binding to DataGrid.SelectedValue works as expected with the “new row” place holder.

<Window.Resources>
<converters:IgnoreNewItemPlaceHolderConverter x:Key="ignoreNewItemPlaceHolderConverter"/>
</Window.Resources>
<toolkit:DataGrid ItemsSource="{Binding Persons}" AutoGenerateColumns="False"
SelectedItem="{Binding SelectedPerson,Converter={StaticResource ignoreNewItemPlaceHolderConverter
}}" IsSynchronizedWithCurrentItem="True">

WPF Charting

Yesterday, I received an e-mail from a developer who has been working on a set of WPF charting controls called amCharts for WPF. I was intrigued so I went over to the website to have a look around. Suffice to say I was easily impressed enough by the demos on the website to download myself a copy of the free (link ware) version.

The download, if anything, was even more impressive. The class library is concise, consistent and obviously well thought through (or evolved). Also, unlike other “bloatware” libraries this one weighs in at only just over 200Kb!

amCharts Torus

If you like what you see over at amCharts and are considering purchasing the Pro version then you may want to take advantage of a 50% discount code “spencen” when placing your order. Thanks go to Alan from amCharts for making me aware of his product and providing the discount which should be good till the end of May 2009.