Saturday, 28 April 2012
Project X
Yet another new blog, this time it's a personal blog about...well everything and anything really.
You can find it here: Project X
Why not come by and say hello?
Friday, 22 April 2011
In-Traction
My head has been hurting of late. As well as continuing to plug away at WPF, doing fun stuff like creating optimised vector graphics editors and custom controls, I am having to develop in XNA and Silverlight for Windows Phone 7, Objective-C and Cocoa for iPhone and somehow find room to at least keep abreast of Android and Java. Ouch!
It strikes me there are just too many devices, platforms and API's out there. Luckily I have some great people working with me and I can at least leave HTML5 and Android alone...for now.
In other news, DiceBox RPG has been doing really well. Its just a shame we can't make it's counterpart (DiceBox) free on the app store. If Microsoft would only get its act in gear and let its developers in the UK ad support their apps... Oh well, sure we wont have to wait too much longer.
Anyhow. I now find myself well and truly in the mobile arena and I'm not sure how much longer this blog has left in it. I guess you never know, I may well end up doing some GIS stuff again at some point but, outside of mobile, that is looking increasingly unlikely.
Having said that, a new and interesting blogging effort is underway. If you are at all interested in smartphones, tablets and the future of computing then why not pop in on the new site at www.in-traction.com
See you there.
Saturday, 22 January 2011
An Expression Blend TabControl Style
After spending some time trawling the web and failing to find the style I was after, I decided to sit down and put one together myself.
A couple of hours later, and with a bit of help from Snoop, this is what I came up with; It’s a style for a tab control and, in-particular, a tab item, that goes some way to looking and feeling like the one used by Expression Blend.
The tabs are prevented from rearranging themselves into multiple lines by swapping out the TabPanel with a StackPanel.
To more closely resemble the style adopted by Blend the TabPanel could instead be replaced with the SqueezeTabPanel, which can be found on CodeProject. For the time being, this has been left as an exercise for the reader ;)
XAML:
<Style TargetType="{x:Type TabControl}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel
Orientation="Horizontal"
Name="HeaderPanel"
Grid.Row="0"
Panel.ZIndex="1"
Margin="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
<Border
Name="Border"
Grid.Row="1"
Background="LightGray"
CornerRadius="2"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2" >
<ContentPresenter
Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="#888888" />
<Setter TargetName="Border" Property="BorderBrush" Value="#AAAAAA" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Path
x:Name="Cross"
Data="M0,0L6,6 M6,0L0,6z"
Stroke="LightGray"
StrokeThickness="1.7"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Cross" Property="Stroke" Value="White"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Cross" Property="Stroke" Value="LightGray"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Margin="0,0,-12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="24"/>
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.Column="0"
Grid.ColumnSpan="2"
CornerRadius="3,0,0,0"
Background="#FF333333" />
<Path
x:Name="RoundedCorner"
Grid.Column="2"
Stretch="Fill"
Data="M6.5,2.6C4.767,0.973 2.509,0 0,0 0,0 0,19 0,19L23,19z"
Fill="#FF333333" />
<Button
x:Name="CloseButton"
Grid.Column="1"
Visibility="Collapsed"
Margin="0,0,0,0"
Width="6"
Height="6"/>
<ContentPresenter
x:Name="ContentSite"
TextElement.Foreground="White"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="Background" Value="Gray" />
<Setter TargetName="RoundedCorner" Property="Fill" Value="Gray" />
<Setter TargetName="CloseButton" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="#EEEEEE" />
<Setter TargetName="RoundedCorner" Property="Fill" Value="#EEEEEE" />
<Setter Property="Foreground" Value="#888888" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Friday, 31 December 2010
Bonehead
DiceBox seems to be doing pretty well, at least according to the stats coming in from AppHub.
So, as well as the DiceBox 1.1 update, work is underway for an RPG version that is already looking pretty awesome. Unfortunately, its still to early to release any details but a video preview should be available soon. To provide a home on the web for this exciting new endeavour, may I present to you...
The site should be slowly evolving over the following weeks and months, so be sure to keep an eye out.
Thursday, 23 December 2010
And now for something completely different: DiceBox
This is bit of a shameless plug really...
Recently a couple of friends and myself have been playing around with the Windows Phone 7 developer tools.
The first fruits of this is DiceBox, a simple dice app, now available on the windows marketplace. If you don't have the Zune software installed you can see the blurb here
We are planning a series of updates which will introduce a number of additional features, such as backgrounds, shadows and a dice tray for playing poker dice/yahtzee etc
If you have a Windows Phone 7, why not give it a try :)
Monday, 8 February 2010
SpatiaLite data provider now in SharpMap trunk
It was nice to see that sussing out how to use those spatial indexes in SpatiaLite was not in vein. A post on bill dollins site prompted me to take a look at the recent changes to the SharpMap trunk, which now includes bills excellent SpatiaLite data provider complete with spatial index support.
Thursday, 21 January 2010
WPF Header/Multi-Column ListBox Control
The WPF ListBox control can be used to create a wide variety of user interface elements thanks to templates and styling. However, recently it left me out in the cold...for a while at least.
We had an existing control, based on a heavily styled ListBox, that contained a bunch or items that could be considered as rows in a table. It all worked fine until some bright spark had the idea of adding column headers.
Now, at this point you may be thinking that ListBox is not the ideal candidate here. ListView, with its GridView layout, is the control to use if you want to layout column based data with column headers. Right?
Well, not always. GridView is fine if you want to apply styles to individual cells or columns. The problem with our particular style was that each conceptual row could be expanded in various ways, making the GridView unsuitable. There were two options as far as i could see:
- Write a custom View (based on ViewBase) for ListView
- Add a header to the ListBox control
We went with option two. The pain began.
The basic problem is that the header needs to be part of the ListBox so that when the ListBox is scrolled horizontally, the header scrolls too. However, when you scroll it Vertically you want the header to remain visible and not scroll with the rest of the list.
I started by looking at the style of the ListView control which does something similar to what i wanted to achieve. This gave me a big clue. The ListView uses a custom ScrollViewer that has a child scrollviewer nested inside. This child ScrollViewer contains the header; The scrollbars on the child ScrollViewer are always hidden. Magic.
I also had a look at this very helpful article: Building a Multi-Column ListBox in Avalon
This came close to what i wanted to achieve, but there were a number of problems:
- It was written before the first release of WPF and would no longer compile
- Having updated it so that it did compile, there were several problems with the scrolling resulting in unsatisfactory placement of the vertical scrollbar (not consistent with ListView) and errors causing the content to slide past the header at the extreme right.
Nevertheless, it gave me a lot of ideas, In-fact the example is based on a lot of the same XAML.
Next, I need to work out how to make the header scroll horizontally when the list box is scrolled horizontally. Unfortunately there is no easy way to do this. Ideally you would bind the HorizontalOffset of the header ScrollViewer to that of the main one. However, this is not possible thanks to its read only nature. To overcome this I used an attached behaviour to achieve the same goal by making use of the ScrollToHorizontalOffset method.
The resulting XAML for the ScrollViewer looks like this:
<Style x:Key="HeaderedScrollViewer" TargetType="{x:Type ScrollViewer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Margin="{TemplateBinding Padding}">
<ScrollViewer DockPanel.Dock="Top"
local:SetHorizontalOffset.Offset="{Binding
RelativeSource={RelativeSource TemplatedParent},
Path=HorizontalOffset}"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Focusable="false"
Content="{StaticResource ListHeader}">
</ScrollViewer>
<ScrollContentPresenter Name="PART_ScrollContentPresenter"
KeyboardNavigation.DirectionalNavigation="Local"/>
</DockPanel>
<ScrollBar Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{TemplateBinding HorizontalOffset}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
<ScrollBar Name="PART_VerticalScrollBar"
Grid.Column="1"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{TemplateBinding VerticalOffset}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And it is applied to the ListBox with this style:
<Style x:Key="{x:Type ListBox}" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ScrollViewer Style="{StaticResource HeaderedScrollViewer}"
Grid.IsSharedSizeScope="True">
<StackPanel IsItemsHost="true"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can download the full source here: MultiColumnList.zip
Subscribe to:
Posts (Atom)