Messing With The New PathListBox

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 :

shapes[1]

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.

Path1[1]

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.

Path2[1]

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

Path3[1]

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

Path4[1]

Using Path as a Path

Path5[1]

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

Advertisements

2 thoughts on “Messing With The New PathListBox

  1. Serge says:

    Hello,

    I have seen your sample using PathListBox which is great. Actually we are building application for Microsoft Surface and lot of customers request most of time Carousell like to display items. PathListbox was my choice at first but the problem I have with it now ( I am not a designer and do not know how to solve it ) is that I need to manipulate the PathListBox item in similarway as a SurfaceListBox but could not reach my goal. It seem the control is not implementing Touch event and scrollviewer.

    Any idea and help would be appreciate in order to be able to scroll my items like a carousell behaviour with touch

    Thnaks for help
    Serge

    • sachabarber says:

      To be honest all I know is what is shown in that PathlistBox article. Any more than that, I can’t really say to be honest.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: