Blend 4 is really cool, the best version yet (well duh, of course it is Sacha).
Anyway one of the things that caught my eye is that Blend 4 now comes with some pre-canned shapes, such as Arrow etc etc, this is good news for me, as I have all the graphics skills of a dead anteater.
See here :
So that is cool, the other thing that caught my eye is the PathListBox, which is a new control which is for SL and WPF. Finally WPF gets some love.
You may have actually seen this PathListBox control as Mix, or as I did at a SL launch party, where there was a very fancy ListBox that displayed text around a circle. It looked way cool, so I decided to have a play with the new boy on the block and see what I could do with it in 1-2 hours.
It is a great control actually. So how do you use it.
Well to start with I did this I dragged a PathListBox from the controls tab in the Blend assets onto the stage.
Then I simple created a Ellipse on the stage. I put the PathListBox in the upper left corner out of the way, and the Ellipse in the middle. I then went about setting the Ellipse as the LayoutPath for the PathListBox, which you can do by using the drag and drop target to pick a element on the stage in Blend.
To add items to the PathListBox I am using a bit of code behind, but the PathListBox does allow any UI element to be an item so if you were to drag Buttons to the PathListBox after you had picked the Ellipse as its LayoutPath, you would see the Buttons arranged in an Ellipse.
Ok so like I say I have some items added via code behind, so then it was onto how I wanted the items laid out, which again is all done inside Blend using the LayoutPaths applet. This has various settings I urge you to play with these, you can control orient to path, padding, start/span percentage etc etc
This is all pretty cool, but what I wanted to try and create was as close as I could to a circle with some text around it. To do this I needed a DataTemplate and a ItemContainerStyle, both of which I created in Blend.
Here is what I came up with
Using Ellipse as a Path
Using Path as a Path
The full code listing for this is available is as follows, the things of note are the DataTemplate and the PathListBoxItem Style. Unfortunately I do not know of any way in Blend to do a RelativeSource binding, so I had to slip into a bit of code to do the Trigger on the DataTemplate.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ec="http://schemas.microsoft.com/expression/2010/controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="WpfApplication1.MainWindow"
x:Name="Window"
Title="MainWindow"
Background="Black"
UseLayoutRounding="True"
Width="800" Height="800">
<Window.Resources>
<DataTemplate x:Key="listBoxItemTemplate">
<StackPanel HorizontalAlignment="Right" Width="150"
RenderTransformOrigin="0.5,0.5" Background="Transparent">
<StackPanel.RenderTransform>
<RotateTransform Angle="-90" CenterX="0.5" CenterY="0.5"/>
</StackPanel.RenderTransform>
<Label x:Name="lbl" Content="{Binding}" Padding="0,2,13,2"
HorizontalAlignment="Left"
HorizontalContentAlignment="Left"
Foreground="White" FontSize="10" Width="150">
</Label>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource=
{RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}, AncestorLevel=1},
Path=IsSelected}"
Value="True">
<Setter TargetName="lbl" Property="Foreground" Value="Orange"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<Style x:Key="PathListBoxItemStyle1" TargetType="{x:Type ec:PathListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ec:PathListBoxItem}">
<Grid Background="{TemplateBinding Background}"
RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="{Binding OrientationAngle,
RelativeSource={RelativeSource TemplatedParent}}"/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="0.6"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0"
To="0.35" Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="fillColor"/>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Opacity)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.X)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" To="0.55"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="contentPresenter"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<DoubleAnimation Duration="0" To="0.75"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="fillColor2"/>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.X)"
Storyboard.TargetName="contentPresenter">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0"
Storyboard.TargetProperty="Visibility"
Storyboard.TargetName="FocusVisualElement">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="fillColor" Fill="{x:Null}"
IsHitTestVisible="False"
Opacity="0" RadiusY="1" RadiusX="1"/>
<Rectangle x:Name="fillColor2" Fill="{x:Null}"
IsHitTestVisible="False"
Opacity="0" RadiusY="1" RadiusX="1"/>
<ContentPresenter x:Name="contentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RenderTransformOrigin="0.5,0.5" OpacityMask="{x:Null}">
<ContentPresenter.RenderTransform>
<TransformGroup>
<ScaleTransform CenterX="0" CenterY="0.5"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</ContentPresenter.RenderTransform>
</ContentPresenter>
<Rectangle x:Name="FocusVisualElement" RadiusY="1"
RadiusX="1" Stroke="{x:Null}" StrokeThickness="1"
Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot" Width="800" Height="800">
<ec:PathListBox x:Name="lstBox" Margin="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
ItemTemplate="{StaticResource listBoxItemTemplate}"
Width="100" Height="100"
d:LayoutOverrides="Width, Height, Margin"
ItemContainerStyle="{DynamicResource PathListBoxItemStyle1}">
<ec:PathListBox.LayoutPaths>
<ec:LayoutPath SourceElement="{Binding ElementName=path}"
Padding="2" Distribution="Even" Orientation="OrientToPath"/>
</ec:PathListBox.LayoutPaths>
</ec:PathListBox>
<Ellipse x:Name="ellipse"
Margin="247,157,253,343" Width="300" Height="300"
d:LayoutOverrides="VerticalAlignment"/>
<Path x:Name="path" Data="M439,268 C519,374 439,476.5 439,476.5 L368.25091,547.25"
Margin="368.25,268,324.444,251.75"
StrokeStartLineCap="Flat" Stretch="Fill" StrokeEndLineCap="Flat"
StrokeThickness="1" StrokeMiterLimit="10" StrokeLineJoin="Miter"
UseLayoutRounding="False"/>
<Button x:Name="btnUseEllipse" Content="Use Ellipse"
HorizontalAlignment="Right" Height="28" Margin="0,22,253,0"
VerticalAlignment="Top" Width="98"/>
<Button x:Name="btnUsePath" Content="Use Path"
HorizontalAlignment="Right" Height="28" Margin="0,22,139,0"
VerticalAlignment="Top" Width="98"/>
</Grid>
</Window>
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }And as always here is a small demo application for you:
Blend4 RC PathListBox Demo.zip