Tuesday, November 02, 2010

Timeline – or restyling controls

One nice thing with WPF that is slightly different is that the controls are lookless. This means that you can re-style or apply a different template altogether if the behavior of a standard control is what you want, but the looks are not.

A real world example: At work we recently needed to show a list of items with associated timestamps, in a way so that the time differences between them are easily determined at a glance.

Thanks to the lookless controls of WPF I was able to solve this simply by using a ListBox with re-templated ListBoxItems giving the following result:

image

The style is defined as follows:

        <Style TargetType="ListBoxItem" x:Key="TimelineStyle">
            <
Setter Property="SnapsToDevicePixels" Value="true"/>
            <
Setter Property="OverridesDefaultStyle" Value="true"/>
            <
Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <
Setter Property="Template">
                <
Setter.Value>
                    <
ControlTemplate TargetType="ListBoxItem">
                        <
StackPanel Orientation="Vertical"> <Border
                           
Name="Border"
                           
Padding="2"
                           
CornerRadius="2"
                           
BorderThickness="2"
                           
SnapsToDevicePixels="true">
                                <
ContentPresenter />
                            </
Border>
                            <
Grid>
                                <
Rectangle Width="2" Stroke="LightBlue"
                                          
Height="{Binding TimeToNext, Converter={StaticResource HeightConverter}}"
                                          
VerticalAlignment="Center"
                                          
HorizontalAlignment="Center"/>
                                <
TextBlock Text="{Binding TimeToNext, Converter={StaticResource DurationConverter}}"
                                          
Background="White"
                                          
VerticalAlignment="Center"
                                          
HorizontalAlignment="Center"
                                          
FontSize="8"
                                          
Foreground="Gray"/>
                            </
Grid>
                        </
StackPanel>
                        <
ControlTemplate.Triggers>
                            <
Trigger Property="IsSelected"
                                    
Value="true">
                                <
Setter TargetName="Border"
                                       
Property="BorderBrush"
                                       
Value="Blue"/>
                            </
Trigger>
                        </
ControlTemplate.Triggers>
                    </
ControlTemplate>
                </
Setter.Value>
            </
Setter>
        </
Style>

and and the listbox uses the style like this:

<ListBox ItemsSource="{Binding DataItems}" ItemContainerStyle="{StaticResource TimelineStyle}" />



The style uses two converters, but those should be fairly trivial.



Setting FocusVisualStyle to {x:Null} is done to hide the indication of keyboard focus, as unless it is fixed properly, will be more confusing than helpful. Fixing it properly is left as an exercise for the reader.

Saturday, February 06, 2010

MCTS

Today I passed the second certification exam 70-502. So now I’m officially a Microsoft Certified Technology Specialist: .NET Framework 3.5, Windows Presentation Foundation Applications.

Monday, February 01, 2010

Nullable<T> and IFormattable

If you ever tried to format a nullable type you would soon realize that you cannot directly as Nullable<T> does not implement IFormattable and thus you only have object.ToString() available.

This is easily fixed using an extension method:

public static class NullableExtensions
{
public static string ToString<T>(
this Nullable<T> nullable,
string format,
IFormatProvider formatProvider)
where T : struct, IFormattable
{
if (!nullable.HasValue) return string.Empty;
T notNull = nullable.Value;
return notNull.ToString(format, formatProvider);
}
}


and you can use it e.g. like so:



            DateTime? foo = null;
...
foo.ToString("t", CultureInfo.CurrentCulture);

Thursday, January 21, 2010

WPF project building inside of Visual Studio but not with MSBuild/TFSBuild

At work, I recently run into a strange build error when building from MSBuild and TFSBuild while the same solution built inside of Visual Studio 2008 just fine.

The error message was:

error MC3015: The attached property '?' is not defined on '?' or one of its base classes.

(obviously with real names instead of the questionmarks)

Feeding the above into google provided the following solution to the issue:

One of the differences between building in VS and command line is that a WPF build in VS defaults to

<AlwaysCompileMarkupFilesInSeparateDomain>true</AlwaysCompileMarkupFilesInSeparateDomain>.
Outside of VS, the default is false.

(Answer by Rob Relyea)

Adding that to the relevant .csproj made the project build successfully.