Editing Indicator in DataGrid Row Header

Editable grids will quite commonly show an indicator in the row header area to indicate that a row is currently being edited. This is trivial to achieve using Microsoft’s WPF DataGrid.

 GridEditing - Edit Indicator

All that is needed is a DataTemplate assigned to the RowHeaderTemplate property of the DataGrid. The template simply shows or hides the editing image based upon whether the current row is being edited.

<SolidColorBrush x:Key="gridLineBrush" Color="#FFCDEFFE"/>
<DataTemplate x:Key="rowHeaderTemplate">
<StackPanel Orientation="Horizontal">
<Image x:Name="editImage" Source="Images/Edit.png" Width="16" Margin="1,0" Visibility="Hidden"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type toolkit:DataGridRow}},Path
=Item.IsEditing}"
Value
="True"> <Setter TargetName="editImage" Property="Visibility" Value="Visible"/> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> <Style TargetType="{x:Type toolkit:DataGrid}"> <Setter Property="GridLinesVisibility" Value="All"/> <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource gridLineBrush}"/> <Setter Property="VerticalGridLinesBrush" Value="{StaticResource gridLineBrush}"/> <Setter Property="RowHeaderTemplate" Value="{StaticResource rowHeaderTemplate}"/> <Style.Resources> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black"/> <SolidColorBrush x:Key="{x:Static toolkit:DataGrid.FocusBorderBrushKey}" Color="{StaticResource gridLineBrush}"/> </Style.Resources> </Style>

There is an IsEditingRowItem property on the DataGrid but unfortunately its private. As it happens my base model class has an IsEditing property as part of its IEditableObject implementation. So I simply bind the visibility of the image to that.

#region IEditableObject Members
public void BeginEdit()
{
IsEditing = true;
}
public void CancelEdit()
{
IsEditing = false;
    // RollbackPropertyValues( _preEditValues );
}
public void EndEdit()
{
IsEditing = false;
}
#endregion

ReadOnly Rows and Cells in a DataGrid

A common requirement for a DataGrid control is to have cells, or entire rows and/or columns that are read-only, or in other words non-editable. My requirements for this are as follows:

  1. ReadOnly can be applied to the entire grid, a column, a row, or an individual cell.
  2. The cell(s) must not allow the cell value to be modified.
  3. The cell(s) must be highlighted in some manner (e.g. background colour) to indicate that they are different to the editable cells.
  4. ReadOnly columns require only single direction data-binding (i.e. Mode=OneWay to read-only properties).

GridEditing - ReadOnly Rows

The Microsoft WPF DataGrid meets these requirements via:

  • DataGrid.IsReadOnly property
<toolkit:DataGrid IsReadOnly="True"

  • DataColumn.IsReadOnly property
<toolkit:DataGridTextColumn Binding="{Binding FullName,Mode=OneWay}" IsReadOnly="True"/>

We can use a simple style targeting all DataGridCells to change the background colour.

<Style TargetType="{x:Type toolkit:DataGridCell}">
    <Style.Triggers>
        <Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
</Style>

So the only thing that’s really missing here is the ability to mark an entire row as read-only. In my experience this is a common requirement – we have a list of records displayed in the grid some of which are locked/completed/secured, whilst others can be edited.

One solution is to override the OnBeginningEdit method of the DataGrid. The following example assumes that I have an attached property ControlSupport.IsReadOnly.

protected override void OnBeginningEdit( DataGridBeginningEditEventArgs e )
{
base.OnBeginningEdit( e );
bool isReadOnlyRow = ControlSupport.GetIsReadOnly( e.Row );
if ( isReadOnlyRow )
e.Cancel = true;
}

However, since I’ve got used to “tweaking” some of the DataGrid code I decided to instead to simply add an IsReadOnly property to the DataGridRow class.

public bool IsReadOnly
{
get { return (bool) GetValue( IsReadOnlyProperty ); }
set { SetValue( IsReadOnlyProperty, value ); }
}
// Using a DependencyProperty as the backing store for IsReadOnly.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register( "IsReadOnly", typeof( bool ), typeof( DataGridRow ), 
new FrameworkPropertyMetadata( false, OnNotifyRowAndCellsPropertyChanged ) );

private static void OnNotifyRowAndCellsPropertyChanged( DependencyObject d, 
DependencyPropertyChangedEventArgs e ) { ( d as DataGridRow ).NotifyPropertyChanged( d, e, NotificationTarget.Rows | NotificationTarget.Cells ); }

Then I just needed to make sure that the read-only property DataGridCell.IsReadOnly would correctly return the right value when its row was marked as read-only.

private static object OnCoerceIsReadOnly(DependencyObject d, object baseValue)
{
var cell = d as DataGridCell;
var column = cell.Column;
var row = cell.RowOwner;
var dataGrid = cell.DataGridOwner;
return DataGridHelper.GetCoercedTransferPropertyValue(
cell,
baseValue,
IsReadOnlyProperty,
row,
DataGridRow.IsReadOnlyProperty,
column,
DataGridColumn.IsReadOnlyProperty,
dataGrid,
DataGrid.IsReadOnlyProperty);
}

There’s a fairly complex series of notification propagation calls going on within the DataGrid classes. For this solution to work it requires that the DataGridRow.IsReadOnly property changing flows down and causes the read-only DataGridCell.IsReadOnly property to be re-evaulated (via the coerce method above). I had to add another GetCoervedTransferPropertyValue method that took another pair of object/property parameters, and also tweaked the DataGridCell.NotifyPropertyChanged as follows:

else if (e.Property == DataGrid.IsReadOnlyProperty || 
e.Property == DataGridColumn.IsReadOnlyProperty ||
e.Property == DataGridRow.IsReadOnlyProperty ||
e.Property == IsReadOnlyProperty) { DataGridHelper.TransferProperty(this, IsReadOnlyProperty); }

Now in my XAML I can do the following (assuming I have an IsReadOnly property on my business objects):

<Style TargetType="{x:Type toolkit:DataGridRow}">
<Setter Property="IsReadOnly" Value="{Binding IsReadOnly}"/>
</Style>

When is a WPF DataGrid read-only CheckBox not read-only?

I found the answer to this riddle when I decided to style the DataGridCheckBoxColumn of Microsoft’s WPF DataGrid. By default the CheckBox displayed by the column template is not centered horizontally or vertically. I thought this looked at little tacky so I decided to apply a custom Style to the ElementStyle (and EditElementStyle) property.

<Style  x:Key="CheckBoxStyle" TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
    <Setter Property="HorizontalAlignment" Value="Center"/> 
<Setter Property="Margin" Value="0,2,0,0"/> </Style>
<toolkit:DataGridCheckBoxColumn Binding="{Binding IsPensioner}" 
Header
="Pensioner?"
ElementStyle="{StaticResource CheckBoxStyle}"
EditingElementStyle="{StaticResource CheckBoxStyle
}"/> <toolkit:DataGridCheckBoxColumn Binding="{Binding IsEditing,Mode=OneWay}"
Header="Is Editing"
ElementStyle="{StaticResource CheckBoxStyle}"

IsReadOnly="True"
/>

What I later discovered is that applying this style has somehow made my read-only CheckBox editable. But only via mouse clicks! Using the keyboard to focus to the cell and pressing Space didn’t cause the CheckBox to toggle, but left clicking on the CheckBox did. What’s going on?

My guess is that the default style applied to the DataGridCheckBoxColumn’s CheckBox in non-edit mode (ElementStyle) sets the IsHitTestVisible property to False to disable clicking on the cell. The keyboard events are swallowed by the DataGrid using Preview events – so no styling is required to prevent keyboard access.

The rule would therefore appear to be that if you set ElementStyle on the DataGridCheckBoxColumn you must include IsHitTestVisible=”False” to prevent it from “seeming” that the control allows edits.

<Style  x:Key="CheckBoxStyle" TargetType="{x:Type CheckBox}" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,2,0,0"/>
</Style>
<Style  x:Key="ReadOnlyCheckBoxStyle" TargetType="{x:Type CheckBox}" BasedOn="{StaticResource CheckBoxStyle}">
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
<toolkit:DataGridCheckBoxColumn Binding="{Binding IsPensioner}"
Header="Pensioner?"
ElementStyle="{StaticResource ReadOnlyCheckBoxStyle}"
EditingElementStyle="{StaticResource CheckBoxStyle}"/>
<toolkit:DataGridCheckBoxColumn Binding="{Binding IsEditing,Mode=OneWay}"
Header="Is Editing"
ElementStyle="{StaticResource ReadOnlyCheckBoxStyle}"
IsReadOnly="True"/>

Binding an Enum Property to a ComboBox using customized text

The problem

I want to data bind a property on my Model to a ComboBox that allows selection from a list of Enum values. For example, my Person class has a HighestEducationLevel property of type EducationLevel.

 GridEditing

The second part of this problem is that I want to provide an optional customized text description for each of my enumeration values. For example, the enumeration value EducationLevel.PreSchool should be displayed as “Pre-school” in the ComboBox.

GridEditing - TypeConverter ComboBox

Solution 1 – Bind to Enum.GetValues()

There are plenty of blog posts and forum answers that show the following technique that can be accomplished in XAML alone. I first saw this on a post by Karl Schifflet.

You define a static resource as an ObjectDataProvider that simply uses a method call to get an array of the enumerated values.

<ObjectDataProvider x:Key="EducationLevelList" MethodName="GetValues" ObjectType="{x:Type local:EducationLevel}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:EducationLevel"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

This can then be data bound as the ItemsSource for a ComboBox – in my case its a ComboBox column of a WPF DataGrid.

<toolkit:DataGridComboBoxColumn Header="Education Level"
SelectedValueBinding="{Binding HighestEducationLevel}"
ItemsSource="{Binding Source={StaticResource EducationLevelList}}"/>

Solution 2 – Bind to Custom Method

This technique can be taken a step further by providing your own method to be used by the ObjectDataProvider rather than relying on Enum.GetValues(Type). This then provides the opportunity to provide custom sorting, filtering and text for the list of enumeration values.

One way to achieve the custom text values is to have the method return a list of “wrapper” objects that provide access to both the underlying enumeration value and the custom text.

public class EnumMapper
{
public EnumMapper( object enumValue, string enumDescription )
{
Enum = enumValue;
Description = enumDescription;
}
public object Enum { get; private set; }
public string Description { get; private set; }
}

The enum type can then have each of its members (fields) that require a custom text decorated with a custom attribute as follows.

public enum EducationLevel
{
None,
[EnumDisplayName("Pre-school")]
PreSchool,
[EnumDisplayName( "Junior school" )]
JuniorSchool,
[EnumDisplayName( "Senior School" )]
SeniorSchool,
Graduate,
[EnumDisplayName( "Post Graduate" )]
PostGraduate,
Professor
}

The new attribute class itself is trivial…

[AttributeUsage(AttributeTargets.Field, AllowMultiple=false)]
public class EnumDisplayNameAttribute : Attribute
{
public EnumDisplayNameAttribute( string displayName )
{
DisplayName = displayName;
}
public string DisplayName { get; set; }
}

The custom method to generate the list then becomes…

public static IList<EnumMapper> GetEnumDescriptions( Type enumType )
{
if ( !enumType.IsEnum )
throw new ArgumentException( "This method can only be called for enum types." );
var list = new List<EnumMapper>();
foreach ( var enumValue in Enum.GetValues( enumType ) )
list.Add( new EnumMapper( enumValue, enumType.GetDisplayName( enumValue ) ) );
return list;
}
public static string GetDisplayName( this Type enumType, object enumValue )
{
if ( !enumType.IsEnum )
throw new ArgumentException( "This method can only be called for enum types." );
var displayNameAttribute = enumType.GetField( enumValue.ToString() )
.GetCustomAttributes( typeof( EnumDisplayNameAttribute ), false )
.FirstOrDefault() as EnumDisplayNameAttribute; if ( displayNameAttribute != null ) return displayNameAttribute.DisplayName; return Enum.GetName( enumType, enumValue ); }

The XAML has to change a little. First the ObjectDataProvider must use the new method, and secondly because the ItemsSource is now a list of EnumMapper instances we must provide DisplayMemberPath and SelectedValuePath properties for the ComboBox.

<ObjectDataProvider x:Key="EducationLevelList" MethodName="GetEnumDescriptions" ObjectType="{x:Type local:BindingSupport}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:EducationList"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

<toolkit:DataGridComboBoxColumn Header="Highest Education Level"
                                SelectedValueBinding="{Binding HighestEducationLevel}"
ItemsSource="{Binding Source={StaticResource EducationLevelList}}"
DisplayMemberPath="Description"
SelectedValuePath="Enum"/>

Solution 3 – Use a customized TypeConverter

Solution 2 provides quite a lot of flexibility but it does mean a couple of extra property setters are required in the XAML (though I guess these could go into a Style). The third approach is to use a TypeConverter to “magically” convert enum values to strings. The major benefit of this approach is that it will work not just for ComboBoxs but anywhere an enum is bound to text property, e.g. in a TextBlock or TextBox.

First we declare a new TypeConverter that has some special processing that allows its to generate the custom text. All enums by default use the EnumConverter anyway – we are just providing an extra lookup to check for a custom attribute.

public class EnumTypeConverter : EnumConverter
{
public EnumTypeConverter( Type enumType ) : base( enumType ) { }
public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType )
{
if ( destinationType == typeof(string) && value != null )
{
var enumType = value.GetType();
if ( enumType.IsEnum )
return GetDisplayName( value );
}
return base.ConvertTo( context, culture, value, destinationType );
}
    private string GetDisplayName( object enumValue )
{
var displayNameAttribute = EnumType.GetField( enumValue.ToString() )
.GetCustomAttributes( typeof( EnumDisplayNameAttribute ), false )
.FirstOrDefault() as EnumDisplayNameAttribute; if ( displayNameAttribute != null ) return displayNameAttribute.DisplayName; return Enum.GetName( EnumType, enumValue ); } }

The next step is to make sure that all our enums use the new TypeConverter. This is done by decorating the enum with a TypeConverter attribute.

[TypeConverter(typeof(EnumTypeConverter))]
public enum EducationLevel
{
None,
[EnumDisplayName("Pre-school")]
PreSchool,
[EnumDisplayName( "Junior school" )]
JuniorSchool,
[EnumDisplayName( "Senior School" )]
SeniorSchool,
Graduate,
[EnumDisplayName( "Post Graduate" )]
PostGraduate,
Professor
}

Now we can change our XAML back to its original simplified form (as per Solution 1) and yet we still get our customized text appearing.

<ObjectDataProvider x:Key="EducationLevelList" MethodName="GetValues" ObjectType="{x:Type local:EducationLevel}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:EducationLevel"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

<toolkit:DataGridComboBoxColumn Header="Education Level"

                               
SelectedValueBinding="{Binding HighestEducationLevel
}"

                               
ItemsSource="{Binding Source={StaticResource EducationLevelList}}"/>

Other Considerations

In the example here I’ve just used hard-coded strings for the EnumDisplayName attributes. However, there is no reason these couldn’t be resource IDs or the like and the GetDisplayName method changed accordingly.

Also, if we want the TypeConverter to have the ability to ConvertFrom the customized text then we need to do a little more work. This is handy in the scenarios where the user may be able to type (as opposed to select from a list) the enum values. So the EnumTypeConverter changes to the following.

public class EnumTypeConverter : EnumConverter
{
private IEnumerable<EnumMapper> _mappings;
public EnumTypeConverter( Type enumType ) : base( enumType )
{
_mappings = from object enumValue in Enum.GetValues(enumType)
select new EnumMapper( enumValue, GetDisplayName(enumValue) );
}
public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType )
{
if ( destinationType == typeof(string) && value != null )
{
var enumType = value.GetType();
if ( enumType.IsEnum )
return GetDisplayName( value );
}
return base.ConvertTo( context, culture, value, destinationType );
}
public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value )
{
if ( value is string )
{
var match = _mappings.FirstOrDefault( mapping => string.Compare( mapping.Description, (string) value, true, culture ) == 0 );
if ( match != null )
return match.Enum;
}
return base.ConvertFrom( context, culture, value );
}

private string
GetDisplayName( object enumValue )
{
var displayNameAttribute = EnumType.GetField( enumValue.ToString() )
.GetCustomAttributes( typeof( EnumDisplayNameAttribute ), false )
.FirstOrDefault() as EnumDisplayNameAttribute;

if ( displayNameAttribute != null )
return displayNameAttribute.DisplayName;

return Enum.GetName( EnumType, enumValue );
} }

WPF DataGrid Tips

I’ve been struggling at work to use Microsoft’s WPF DataGrid (from their WPF Toolkit) to fulfil a fairly basic set of requirement. The following is simply a list of lessons learned.

  1. Remember to set the SortMemberPath for all DataGridTemplateColumns. Otherwise the column header is “inactive” and doesn’t allow sorting regardless of setting CanUserSort.
  2. Remember to set the ClipboardContentBinding for all DataGridTemplateColumns. Otherwise the column data will be copied to the clipboard as an empty string.

    <toolkit:DataGridTemplateColumn Header="Date of Birth"
                                                    
    SortMemberPath="DateOfBirth"
                                                    
    ClipboardContentBinding="{Binding DateOfBirth
    }">
          <
    toolkit:DataGridTemplateColumn.CellTemplate
    >
              <
    DataTemplate
    >
                  <
    TextBlock Text="{Binding DateOfBirth,Mode=OneWay,StringFormat=d}" Margin
    ="2,0,2,2"/>
              </
    DataTemplate
    >                    
          </
    toolkit:DataGridTemplateColumn.CellTemplate
    >
          <
    toolkit:DataGridTemplateColumn.CellEditingTemplate
    >
              <
    DataTemplate
    >
                  <
    toolkit:DatePicker SelectedDate="{Binding DateOfBirth,Mode
    =TwoWay}"/>
              </
    DataTemplate
    >
          </
    toolkit:DataGridTemplateColumn.CellEditingTemplate
    >
      </
    toolkit:DataGridTemplateColumn>

  3. As with other ItemsControls you will most likely want to redefine HighlightBrush and HighlightTextBrush to avoid the high contrast (and very old fashioned) row selection colours.
  4. Use Styles embedded in the DataGrid’s style’s Resources collection to override attributes of controls that will be used for editing. For example, setting the BorderThickness=”0” and Padding=”0” on the DatePicker.
  5. Watch out for implicit Styles that effect Button. The grid is made up of lots of buttons (grid, row and column headers) so having an implicit style define MinWidth or Margins can lead to some unsightly grid layouts.
  6. DataGridCheckBoxColumn doesn’t centre vertically and its default margin doesn’t seem to match the DataGridTextColumn. Setting the Margin for DataGridCheckBoxColumns to  “2”, or at least “0,2,0,0” seems to do the trick.
  7. Setting an EditingElementStyle for a DataGridTextBoxColumn to CharacterCasing=”Upper” is not honoured if the keystroke is used to enter edit mode. Requires a simple fix to the PrepareCellForEdit method in DataGridTextBoxColumn. Refer http://www.codeplex.com/wpf/Thread/View.aspx?ThreadId=36985.

                        // If text input started the edit, then replace the text with what was typed.
                    string inputText;
                    switch (textBox.CharacterCasing)
                    {
                        case CharacterCasing.Upper:
                            inputText = textArgs.Text.ToUpper();
                            b
    reak
    ;
                        case CharacterCasing.Lower:
                            inputText = textArgs.Text.ToLower();
                            break;
                        default:
                            inputText = textArgs.Text;
                            break;
                    }
                    textBox.Text = inputText;

  8. Placing a DatePicker in a DataGridTemplateColumn doesn’t cause the DatePIcker to automatically gain focus when pressing F2 (enter edit). To get around that I overrode PrepareCellForEdit in DataGridTemplateColumn as follows:

        protected override object PrepareCellForEdit(FrameworkElement editingElement,
                                                                      RoutedEventArgs editingEventArgs)
        {
            editingElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
            return base.PrepareCellForEdit(editingElement, editingEventArgs);
        }

  9. The DatePicker uses the Enter key to highlight the date within its embedded TextBox. This is annoying when used in a DataGridTemplateColumn since the standard behaviour for the Enter key is to commit edits and move down a row. Commenting out this functionality in the DatePicker (within ProcessDatePickerKey) does the trick. 

            private bool ProcessDatePickerKey(KeyEventArgs e)
            {
                switch (e.Key)
                {
                    case Key.System:
                    {
                        switch (e.SystemKey)
                        {
                            case Key.Down: { if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
                                {
                                    TogglePopUp();
                                    return true;
                                }
                                break;
                            }
                        }
                        break;
                    }
                  
    // Removing this functionality makes the control work better in the grid – ENTER goes to next row.
                  
    //case Key.Enter:
                  
    //{
                  
    //    SetSelectedDate();
                  
    //    return true;
                  
    //}
                }
                return false;
            }

Othe
r Resources

Blog Reader Replacement

[Warning: This is largely a rant… it is by no means a serious review of any of these products.]

For the last couple of years I’ve been using FeedGhost as my RSS Reader of choice. I install it on all my machines – home, work and laptop. Up until recently I’ve been happy with the tool. I was originally drawn to it because 1) it looked fresh and new with plenty of visual polish, 2) it had a great synchronization mechanism which meant all my machines could be kept in sync.

FeedGhost

Alas, in the last couple of months things have started to fail. Running FeedGhost on my laptop has suddenly jumped from using 100Mb to using well over a 1Gb. Even more worrisome the synchronization seems to have had a few bugs introduced. Blog entries appears under the wrong category/feed and old items keep incorrectly showing as unread.

So… time for a new Blog Reader. The guys at work use Google Reader. I pity them, I try to educate them and when all else fails I just mock them.

So what serious contenders are there? I used SharpReader many years ago. Simple, quick but definitely lacking in features – I don’t think its being actively developed.

So from SharpReader I moved to RssBandit. I downloaded the latest version, loaded my feed list and took it for a spin. Initial reaction is one of disappointment. On the surface it seems much as it was a few years ago. They’ve added synchronization and a download manager. The posts glow a horrible yellow when you mouse over them – very annoying but presumably something that can be turned off.

RSSBandit

At the same time as downloading RssBandit I got the latest version of FeedDemon. I haven’t used this product before – I seem to remember a time when it wasn’t free. The Newsgator synchronization seems to work well and is quick as is loading the posts themselves. Its been severely beaten with the ugly stick which is a shame. It also doesn’t behave how I would “expect” in many cases. For instance – it doesn’t seem to let you open more than one node in the feed list tree. If you open one it closes the previous – why?!

FeedDemon

I don’t really want too much in an RSS Reader. My feature list in order of importance would go something like:

  1. Simply, effective synchronization of feeds and entry status.
  2. Well rendered post in a couple of layout formats – summary list, “river of news” flow etc.
  3. “Helpers” for adding subscriptions, e.g. Subscribe action takes clipboard URL by default, browser right click extensions etc.
  4. Clean, intuitive user interface – most are way to cluttered.

Of course what might be nice is a WPF based RSS Reader. Maybe using Live Services/Sync Framework behind the scenes to do the synchronization. Maybe Paperboy will become such a tool?

Overall – I’m a little disappointed with the available offerings. Does anyone have a (non browser based) alternative that they’d recommend?

Panoramas using Microsoft Image Composite Editor (ICE) and HD View

After having had quite a bit of fun stitching photos together using Window Live Photo Gallery I decided to see what other gems it may have on its feature list. What I found was the Extras/Download more photo tools… menu which took me to this website.

Photosynth is awesome, but it requires that all photos be public at this stage. AutoCollage I had tried out before and whilst it is kinda cute, I preferr having more custom control in the layout (hence my PhotoPlay app a few years ago).

The Image Composite Editor (apart from having a truly uninspiring name) seem to essentially be the engine that Windows Live Photo Gallery uses under the hood to perform its own “Create panoramic photo” feature. Of course the Image Composite Editor (ICE) allows you to get more involved in how the composite stitching is performed. It also has quite a few export options, including: HD View Tileset, Adobe Photoshop, Deepzoom Tileset or just plan jpg or png.

Microsoft Image Composite Editor

I did some experiments with the HD View Tileset option. What I liked about this was it allows you to view the image whilst getting a better perspective of the rotational span. Kind of like printing out a panoramic strip and then wrapping it around your head about 15cm from your eyes whist spanning the correct angle of the composite. Err… ok – that wasn’t a great explanation – try the links below.

DSC07492-5 Stitch

Dunk Island – View from Mount Kootaloo

DSC07549-53 Stitch

Dunk Island – Alone on Muggy Muggy Beach

Weekend Getaway to Kangaroo Island

I spent last weekend away with the family touring around Kangaroo Island. I managed to take a few photos of the “mandatory” tourist spots. I’ve become quite a fan of taking panoramic photos the easy way – i.e. standing in one spot and taking multiple photos at different angles with a relatively constant horizon.

Back in the “good ‘ol days” I used to spend hours stitching the individual photos together afterwards. This involved difficult colour matching, transforms to cater for perspective, manual touchups/blurs of the edges etc. These days I simply select the photos (in any order) using Windows Live Photo Gallery and then choose “Create panoramic photo…”. Hey presto – all done!

Here’s a few samples – click for larger versions. These are all taken with a 6 year old digital camera by a novice photographer (me).

EDIT: First photo now links to full size image (around 2.9Mb).

DSC09098 Stitch

Beach at Penneshaw – taken from Frenchman’s Rock. Cape Jervis on the horizon on the far right.

DSC09150 Stitch

Remarkable Rocks

 DSC09169 Stitch

Admiral’s Arch

DSC09252 Stitch Wide 

Stokes Bay – great beach for young kids.

INotifyPropertyChanged via Extension Methods

I imagine most developers that work with data-binding in WinForms or WPF have their preferred way of implementing INotifyPropertyChanged (or individual <property>Changed events). Normally I use a base class to hide the interface declaration and event and then use helper methods in the setters to take care of raising the event when applicable.

I’ve also spent some time looking at AOP alternatives using PostSharp. These look really promising, but it does require taking a dependency on PostSharp.

Another alternative is to use Extension methods. I had this realisation today and figured I’d spend a few minutes putting together a quick test. Getting the event proved a little irksome, and I’m passing around property names as strings (as opposed to perhaps using a member expression). Here’s the extension class:

public static class PropertyChangedExtension
{
public static void OnPropertyChanged(this INotifyPropertyChanged sender, string propertyName)
{
RaiseEvent(sender, propertyName,  "PropertyChanged");
}
public static void OnPropertyChanging(this INotifyPropertyChanging sender, string propertyName)
{
RaiseEvent(sender, propertyName, "PropertyChanging");
}
public static bool SetValue<T>(this INotifyPropertyChanged sender, 
ref T backingField,
T newValue,
string propertyName) { if ( Equals( backingField, newValue )) return false; var propertyChanging = sender as INotifyPropertyChanging; if (propertyChanging != null) propertyChanging.OnPropertyChanging(propertyName); backingField = newValue; OnPropertyChanged(sender, propertyName); return true; } private static void RaiseEvent(object sender, string propertyName, string eventName) { var fieldInfo = sender.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic); if (fieldInfo != null) { var eventDelegate = fieldInfo.GetValue(sender) as MulticastDelegate; if (eventDelegate != null) eventDelegate.DynamicInvoke(
new object[] { sender, new PropertyChangedEventArgs(propertyName) }); } } }

Here’s a simple test class.

public classPerson: INotifyPropertyChanging, INotifyPropertyChanged

{

    public eventPropertyChangedEventHandler PropertyChanged;

    public eventPropertyChangingEventHandler PropertyChanging;

    private string_firstName;

    private string_lastName;

    public stringFirstName

    {

        get{ return_firstName; }

       
set

      
{

            if(this.SetValue(ref _firstName, value, "FirstName"))

                this.OnPropertyChanged("FullName");

        }

    }

    public string LastName

    {

        get { return _lastName; }

       
set

       
{

            if (this.SetValue(ref _lastName, value, "FirstName"))

                this.OnPropertyChanged("FullName");

        }

    }

    public string FullName

    {

        get { return string.Format("{0} {1}", FirstName, LastName); }

    }

}

Note that I use the boolean result from SetValue to determine whether I should fire property changed events on other dependent properties (again this is something that can be done declaratively using PostSharp).

The RaiseEvent method in the Extension class is a really nasty hack (in other words it won’t always work and is slow). You can simply pass through the event handlers which makes things much simpler, but what I was aiming for was the least amount of code in the setters. I wouldn’t use this code in a production environment (a base class is much better suited). However it is well suited for adding property change notification to classes that I’m just throwing together for a demo or prototype without having to worry about PostSharp dependencies or base classes.