Wednesday, March 17, 2010

Sample application for Windows Phone

I wrote this simple game a while ago for my kids using WPF. When I heard that Silverlight was going to be on Windows Phone I just couldn't resist porting it to Silverlight.

The game is fairly simple, four times a second a little ball appears on the screen in random places and flys accross the screen. The idea is to try and touch the balls with your finger causing them to explode.

You can download the full source to game here.

To build and run the app you'll need the Windows Phone Developer Tools CTP

Monday, March 15, 2010

How to select a row in the WPF DataGrid using a CheckBox

This is fairly simple to achieve in the WPF DataGrid, all you need to do is add a DataGridCheckBoxColumn to the Columns collection of the data grid, and then bind it to the IsSelected property of the DataGridRow that is hosting it.
<Grid.Resources>
    <local:PersonCollection x:Key="people">
        <local:Person ID="1" FirstName="Joe" LastName="Blow" />
        <local:Person ID="2" FirstName="Sam" LastName="Blam" />
        <local:Person ID="3" FirstName="Jack" LastName="Black" />
        <local:Person ID="4" FirstName="Hugo" LastName="Blue" />
    </local:PersonCollection>
</Grid.Resources>

<DataGrid
    x:Name="dataGrid"
    ItemsSource="{Binding Source={StaticResource people}}"
    IsSynchronizedWithCurrentItem="True"
    >
    <DataGrid.Columns>
        <DataGridCheckBoxColumn 
            Binding="{Binding IsSelected, 
                RelativeSource={RelativeSource AncestorType=DataGridRow}}" 
            />
    </DataGrid.Columns>
</DataGrid>  

Friday, March 12, 2010

How to move to the first item in a WPF DataGrid after sorting

Although the WPF DataGrid exposed a Sorting event, this only tells you a sort is about occur. Unfortunately there is not a corresponding Sorted event. However with just a little help from the Dispatcher we can utilise the Sorting event to move to the first item in the grid.

I solved this using an attached behaviour, if your not familiar with this term think of it as an attached property that uses PropertyChanged event to add a feature to an existing control. Conceptually it's quite similar to an attached method in C#.

In the data grid we simply set the attached property to true. We also need to set the IsSynchronizedWithCurrentItem property to true as well, this is required to keep the current item in sync with the default CollectionView that the data grid will bind to.

<DataGrid
x:Name="dataGrid"
ItemsSource="{Binding Path=People}"
local:MoveFirstSortBehaviour.MoveFirstOnSort="True"
IsSynchronizedWithCurrentItem="True"
/>

The attached behaviour is really quite simple. All it does is subscribe to the Sorting event on the data grid. When the Sorting event occurs it uses the Dispatcher to move to the first item in the CollectionView the data grid is bound to. BeginInvoke is required because the sort hasn't occured yet, by the time our code is invoke the grid will be sorted.


public class MoveFirstSortBehaviour
{
public static bool GetMoveFirstOnSort(DependencyObject obj)
{
return (bool)obj.GetValue(MoveFirstOnSortProperty);
}

public static void SetMoveFirstOnSort(DependencyObject obj, bool value)
{
obj.SetValue(MoveFirstOnSortProperty, value);
}

public static readonly DependencyProperty MoveFirstOnSortProperty =
DependencyProperty.RegisterAttached("MoveFirstOnSort", typeof(bool), typeof(MoveFirstSortBehaviour),
new UIPropertyMetadata(false, OnMoveFirstOnSortChanged));

private static void OnMoveFirstOnSortChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null !(bool)e.NewValue) return;

dataGrid.Sorting += (s, args) =>
{
dataGrid.Dispatcher.BeginInvoke((Action)delegate()
{
var view = CollectionViewSource.GetDefaultView(dataGrid.ItemsSource);
if (view == null) return;
view.MoveCurrentToFirst();
}, null);
};
}
}

Thursday, March 11, 2010

How to set the TabItem Header in a Silverlight TabControl using Prism

In this piece of XAML it's assumed that the view being placed into the TabControl region has it's DataContext bound to a view model containing a HeaderInfo property.

For the complete example see ViewInjectionComposition quick start and have a look at the EmployeeDetailsView.

The trick to displaying the header is to override the HeaderTemplate property on the TabItem using a style.


<UserControl.Resources>
<Style TargetType="controls:TabItem" x:Key="TabItemStyle">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding HeaderInfo}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>

<Grid x:Name="LayoutRoot">
<controls:TabControl
Regions:RegionManager.RegionName="MainRegion"
Regions:TabControlRegionAdapter.ItemContainerStyle="{StaticResource TabItemStyle}"
>
</controls:TabControl>
</Grid>