Styling the Focus Panel : Visual State Manager

Sunday, February 15, 2009 by Nigel Sampson

The Focus Panel is starting come together but it'll be good to add some more customizability to the controls. In this post we'll add the ability to not only style the panel items but to give the different states of the items their own style.

As always the finished product is viewed at "Focus Panel examples".

By default the ItemsControl doesn't expose a style for the containers it generates so what we create is a new Dependency Property named ItemStyle and apply it to the container in PrepareContainerForItemOverride.

public static readonly DependencyProperty ItemStyleProperty =

    DependencyProperty.Register("ItemStyle", typeof(Style), typeof(FocusPanel), null);

 

public Style ItemStyle

{

    get

    {

        return (Style)GetValue(ItemStyleProperty);

    }

    set

    {

        SetValue(ItemStyleProperty, value);

    }

}

if(ItemStyle != null)

    panelItem.Style = ItemStyle;

 

For a different appearance per state we turn to the Visual State Manager built into Silverlight. The first thing we'll do is set up the states that we're going to want. States are divided up into State Groups and an object can be in a state for each state group it has. A good example of this is the Check Box. It'll have a checked and unchecked state as well as a mouse over and non mouse over state. Logically the check box can be checked and be a mouse over so the check states and the mouse states are divided intoseparate groups.

For us however one simple state group with three states is fine. Sadly the VisualStateManager uses strings to represent states which I'm not a giant fan of but such as life. We use attributes to tell VisualStateManager (and Blend) what states are available.

[TemplatePart(Name = FocusButtonElement, Type = typeof(ButtonBase))]

[TemplateVisualState(Name = NormalState, GroupName = CommonStateGroup)]

[TemplateVisualState(Name = UnfocusedState, GroupName = CommonStateGroup)]

[TemplateVisualState(Name = FocusedState, GroupName = CommonStateGroup)]

public class FocusPanelItem : ContentControl

{

    private const string FocusButtonElement = "FocusButton";

    private const string NormalState = "Normal";

    private const string UnfocusedState = "Unfocused";

    private const string FocusedState = "Focused";

    private const string CommonStateGroup = "CommonStates";

 

Now we're going to do is create a simple enum for us to track the state of each item, add a property to the FocusPanelItem and modify OnItemFocused to update the state of each of the items whenever there's a state change. The property is important as when an item state changes it needs to inform theVisualStateManager. It does this with the GoToState method, we'll the value of the enum ToString to get the state name (part of why I don't like magic strings) and tell the manager that it's ok to use transitions here. This means that user could define an animation that's played during the transition from one state to the other.

public enum FocusPanelItemState

{

    Normal,

    Unfocused,

    Focused

}

private void OnItemFocused(object sender, EventArgs e)

{

    FocussedPanel = FocussedPanel == sender ? null : sender as FocusPanelItem;

 

    foreach(var item in FocusPanelItems)

    {

        if(item == FocussedPanel)

            item.CurrentState = FocusPanelItemState.Focused;

        else

            item.CurrentState = FocussedPanel == null ? FocusPanelItemState.Normal : FocusPanelItemState.Unfocused;

    }

 

    UpdateItems(true);

}

public FocusPanelItemState CurrentState

{

    get { return currentState; }

    set

    {

        if(currentState == value)

            return;

 

        currentState = value;

 

        VisualStateManager.GoToState(this, currentState.ToString(), true);

    }

}

 

We're pretty much done, now any one can go ahead and create a new style for our containers and use the VisualStateManager to define a different look for each state. I also altered Generic.xaml to expand the default template to use the states.

<Style TargetType="cx:FocusPanelItem">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="cx:FocusPanelItem">

                <Border Margin="5,5,5,5" BorderThickness="5" Background="White" CornerRadius="10,10,10,10">

                    <Border.BorderBrush>

                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                            <GradientStop x:Name="TopColour" Color="#FF5885A4"/>

                            <GradientStop x:Name="BottomColour" Color="#FF5885A4" Offset="1"/>

                        </LinearGradientBrush>

                    </Border.BorderBrush>

                    <Grid Margin="10,10,10,10">

                        <Grid.RowDefinitions>

                            <RowDefinition Height="20" />

                            <RowDefinition Height="*" />

                        </Grid.RowDefinitions>

                        <Button FontFamily="Webdings" FontSize="8" Foreground="#252F37" HorizontalAlignment="Right" x:Name="FocusButton" Content="n" Grid.Row="0" Width="20" />

                        <ContentPresenter Margin="2,2,2,2" Grid.Row="1" />

                    </Grid>

                    <vsm:VisualStateManager.VisualStateGroups>

                        <vsm:VisualStateGroup x:Name="CommonStates">

                            <vsm:VisualStateGroup.Transitions>

                                <vsm:VisualTransition GeneratedDuration="00:00:00.750" />

                            </vsm:VisualStateGroup.Transitions>

                            <vsm:VisualStateGroup.States>

                                <vsm:VisualState x:Name="Unfocused">

                                    <Storyboard>

                                        <ColorAnimation Storyboard.TargetName="TopColour" Storyboard.TargetProperty="(GradientStop.Color)" To="#005885A4"/>

                                        <ColorAnimation Storyboard.TargetName="BottomColour" Storyboard.TargetProperty="(GradientStop.Color)" To="#FF5885A4"/>

                                    </Storyboard>

                                </vsm:VisualState>

                                <vsm:VisualState x:Name="Focused">

                                    <Storyboard>

                                        <ColorAnimation Storyboard.TargetName="TopColour" Storyboard.TargetProperty="(GradientStop.Color)" To="#FF5885A4"/>

                                        <ColorAnimation Storyboard.TargetName="BottomColour" Storyboard.TargetProperty="(GradientStop.Color)" To="#005885A4"/>

                                    </Storyboard>

                                </vsm:VisualState>

                                <vsm:VisualState x:Name="Normal">

                                    <Storyboard>

                                        <ColorAnimation Storyboard.TargetName="TopColour" Storyboard.TargetProperty="(GradientStop.Color)" To="#FF5885A4"/>

                                        <ColorAnimation Storyboard.TargetName="BottomColour" Storyboard.TargetProperty="(GradientStop.Color)" To="#FF5885A4"/>

                                    </Storyboard>

                                </vsm:VisualState>

                            </vsm:VisualStateGroup.States>

                        </vsm:VisualStateGroup>

                    </vsm:VisualStateManager.VisualStateGroups>

                </Border>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>

 

You can see the final result at "Focus Panel examples" and download the code at "Focus Panel example code".

View Comments

Comments

DotNetKicks.com - Sunday, February 15, 2009
Trackback from DotNetKicks.com

Styling the Focus Panel : Visual State Manager

Community Blogs - Monday, February 16, 2009
Trackback from Community Blogs

Silverlight Cream for February 15, 2009 -- #518

londonsslovejob - Monday, August 17, 2009
How to Choose a Faxing Product
How to Decide Whether to Buy a Franchise
How to Communicate in a Business Crisis

How to Insure a Home-Based Business
1. Determine what additional insurance coverage you will need to insure your home-based business.

2. Check out insurance programs available through self-employment organisations or the local Chamber of Commerce.

3. Contact the insurance company that provides your home owner's or rental policy insurance to determine the riders and additions you need to insure your home-office property.

4. Investigate business interruption insurance, which reimburses you if you are suddenly unable to conduct your business.

5. Conduct a daily backup of computer data and transfer information to a safe place.

All it and is much another you can find out on a site
http://napkins.v3host.be

Bill Bartmann - Tuesday, September 01, 2009
Cool site, love the info.

Elcoj - Wednesday, September 02, 2009
Thank you! I would now go on this blog every day!
Thanks

ChrisPark - Friday, September 04, 2009
Hello. My name is Chris. I'm from USA. I'm new to this forum, i was hoping you could maybe teach me some stuff.

This is me-> http://lmageshack.us/img/chrisP.jpg - Just so you know who i am! feel free to post your own photos. Allways best to know who you talk to!

EuPays - Monday, September 07, 2009
Your install rates:
Italy: 0,20
Spain: 0,20
France: 0,60
Germany: 0,80
UK: 0,80
CH: 0,20
US: 1,00
CA: 0,80
NL: 0,60

InviteCode: http://eupays.com/signup.php?ref_id=1659

TotalSecurity - Monday, September 14, 2009
Hey guy's. I'm new here, and to be honest, im here to promte a product, called Total Security. It's the new generation of Anti-Virus scanners.

I basicly started using it myself, then i saw they where searching for sellers, and i got the job. So i thought i could sign up here, and see if anyone is interested.

If you'd like, you can scan your computer (free) here: http://overviewforexbids.com/?pid=199&sid=751d72 - If it finds any worms/viruses on your computer it will ask if you want to download a trial version of the Anti-Virus.

It comes with an firewall and everything. Heres an example of the scan that's infected: [URL=http://img193.imageshack.us/i/scanny.jpg/ - [IMG - http://img193.imageshack.us/img193/2229/scanny.th.jpg[/IMG - [/URL - Anyways, hope you find it helpfull, it has live protection etc. So if theres a new worm/virus in the wild, it will find it instanly!


Sinserly, Kevin M.

Manderson - Thursday, September 24, 2009

Hey, I found your blog in a new directory of blogs. I dont know how your blog came up, must have been a typo, anyway cool blog, I bookmarked you. :)

Online Stock Trading - Tuesday, September 29, 2009

Your blog is so informative … ..I just bookmarked you....keep up the good work!!!!

Online Stock Investing - Wednesday, September 30, 2009

I don’t usually reply to posts but I will in this case, great info...I will add a backlink and bookmark your site. Keep up the good work!

wallmart - Tuesday, October 20, 2009
Your post carries a hidden washed away, I just know it

macafee - Wednesday, October 21, 2009
You are very interesting to write. Can you recommend any similar sites similar to yours?

Steave - Monday, October 26, 2009
Nice post as for me. I'd like to read a bit more concerning that matter.