web 2.0

Building a HRM system with the MVVM pattern–Creating the MVVM base classes

What will this blog post cover?

This blog post will show you the basic elements of an M-V-VM framework and setup the basic infrastructure we require to build our application. It might be that currently (this blog post) doesn’t make sense at all for you, please be patient and continue to read and try to understand as much as possible. When we actually build the application this will all become more clear.

What parts do we need?

To answer this question it’s important to first know how parts will interact with each other.

  1. The communication between the view and the view model will be handled by the use of bindings and commands. The commands feature is a default WPF feature just like bindings.
  2. Communication between view models can be archived with a communication bus, which can be seen as a channel to communicate over. (The communication bus is sometimes also called event aggregator).

Why… why do view models need to communicate with each other?

This allows them to tell each other something changed. For example:

If you have a view model to set the current culture or current project that’s open. Then you want to make all the other view models aware of that the change.

Or if you have a master detail view with 2 view models than at some point you might receive a selected item command execute on one view model and you want to notify the other view model that the selected item is changed.

The visual representation of the parts we require:

image

 

 

 

 

 

 

 

 

 

 

At the top there are styles and templates, these are default WPF features to modify the looks of controls inside your view. Next to what’s shown above, we also require some mechanism to connect the view to the view model. We will start with writing code to do that.

The view model locator

The entrance point of our application is the View. When a view is loaded it should have the data context set to the view model. This allows the communication between those 2 to start. To allow this magic to happen we use the view model locator. This class will allows us to do this without adding code in the code behind and allows use to use dependency injection for it.

How does this works:

In our App.xaml we will add a resource which points to our ViewModelLocator class:

image

Now we can reuse this resource everywhere in our application to set the data context of the view:

image

The class itself is very simple. It is a dynamic object, which will simply call the IoC container (our class that takes care of the dependency injection) to get an object by a given name.

(The code on line 22 is to support this functionality in Silverlight, I discovered that in the current version of SL it’s not allowed to bind to a dynamic object. So in Silverlight you would need to bind to [MainWindowViewModel] to archive the same)

image

With this in place, you’ve got the first part working :-) So on each view we will use, we will call the view model locator with the name of the view model that we would like to bind to and set it as the data context. This will allow you to just data bind to commands and data objects in your view model. Later on I will explain you how the dependency injection works, for now just assume that it will always give back the correct view model. (TODO: add reference to future blog post)

The view model base class

From the view, we now arrived at the view model. Let’s build a base class for this, which we can inherit for each view model to make sure we don’t repeat the default behavior each time. Our view model base class will implements the INotifyPropertyChanged interface, to notify listeners(view) when properties change so the binding can be updated to the latest values.

Below is the code:

image

The NotifyPropertyChanged method will allow you to notify on change of a property (See the sample below for an property called employee). When only implementing the default, the event should be fired with a string that contains the name of the property that changed. This is a little bit risky, because when you refactor and forget to change the string, everything will still compile, but the properties won’t be updated on the bindings. When using the method above, with the expression, you will get compile errors if the name is different and refactoring will always work as you assume.

image

The Culture Manager will be covered later on. This is used to provide the multi language user interface. For now just ignore it.

The Relay command

To communicate from the view to the view model, we will send it commands to react on. These commands will be send using the relay command, which is an implementation of the interface in .NET called ICommand.

The relay command will just execute the assigned Execute command action that is set on it. It’s just someone standing in the middle, when you scream on, he or she will turn a button on (execute the assigned command in this case). The CanExecute predicate allows you to define if the the action is active or not (if a button can be clicked).

In a later blog post, when we start to build the actual application, I will demonstrate you how to activate these commands on button click, mouse over events, etc..

image

Communication between view models

To communicate between view models we require a communication channel/ bus. I’ve didn’t placed this channel in the base view model class, because I think you can have more than 1 channel in your application and this should be handled in the class that inherits from the base class. For example: it can be that you setup a communication channel to communicate messages that are directed at the global application level and one channel that is directed to specific screen that the end user can interact with.

This class is an implementation of the mediator pattern. The mediator pattern defines an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referencing each other explicitly.

What the object basically does, it keep a register of other classes that are subscribed to a certain message. As soon as you notify the message over the communication channel it will check the register and notify everyone that is subscribed to the message.

image

Most of the code is just default .NET code, so I assume you are able to understand it (it doesn’t feel complex, let me know if I need to explain it more).  Still, there is one weird class in there called weak action.

The weak action implements the weak reference class and allows us to keep a reference to an object (the action) that might be garbage collected. If this was a normal reference and the view model was disposed, the garbage collector would not clean up the view model, because it thinks it’s still alive.. one of it’s objects (the action) is still active on the communication bus. The weak reference will allow the view model to be collected and will just remove the action out of the list to notify, when it’s not active.

The code of the weak action is very basic, it will just create the delegate it’s still alive.

image

And that's end for today, as you can see this isn’t much code. I will walk you thru some of the other basic classes and concepts in the next blog posts, after that we will arrive at the part where we will implement them in real life, so it starts to make sense :-)

Give me the code… I want to play with it.

Currently I looking for time in my schedule to setup a CodePlex project to share this code.

I assume I got this setup and working by the end of next week. I will update this text as soon as everything is setup or you can check the codeplex project site itself http://hrmsystem.codeplex.com/.

Tags:

Building a HRM system with the MVVM pattern - Introduction post

What’s this?

This blog post is the start of a series of blog posts that will give insight in building an application from scratch using cool patterns. It’s not the best way; it’s not the worst way; it’s the way I like to follow today :-) I will probably refactor this post along the way.

In this series I will build a sample application that can be used for demonstrating different ideas and allows me to show you the ideas against an actual application. This will allow me to test out the ideas, and allow you as a reader to see how they are implement for real, instead of looking at a sample and thinking, great, how will I get that I my application?

The application

The application we will build is a human resource management system, in short HRM system. In am not an expert in this domain, but I’ve figured I could at least make up something useful to build :-)

Specification

Let’s first start by defining the global domain context and write out what we will build. I’ve sat down with the customer (myself) and created a chart defining what our system will do. This is translated from Dutch, so it might contain wrongly translated words, but I assume you will get the idea.

Global overview of domain

image

So at the top we have our vision, we want to build a great HRM system green. We might have a small document somewhere defining a wonderful destination vision. The next layer down blue is the scope of this application. What will be our focus on during the amount of time we have to build this application?

It consists of the following modules or parts:

  • Employee – which comes down to CRUD on employees
  • Work leave –register and report free time of employees
  • Overtime – register and report the over time of employees
  • Work planning – management, do you have enough employees to complete your tasks
  • Absenteeism – register and manage employees that are ill (short and long term)

The next layer down orange contains the focus areas, this is where we would create use cases / user stories from.

As one of the stakeholders of the application I will throw in extra requirements I want this application to be a multi language application, because one part of the staff of my HR department is Dutch and one part is English. The management of HR is a English speaking person and the employees are Dutch. (This allows me to demo multi language). And the application should run as a windows application on the machines of the HR department employees.

We now have enough functional specification to start. Let’s move to the technical side.

Application Architecture

The application we will build, will be using 3 layers of separation. There are many different ways of separating applications in layers. We will use this one as long as it feels good and maybe later on redefine it when needed.

image

The data layer will be responsible for retrieving and persisting entities used inside the application. It will transform every incoming object to something your domain layer is aware of. In stone age (when there where no computers and only humans): This layer would exist of at least 2 people sitting behind a desk, 1 person that translates your request to an archivist, the archivist will store or lookup what you need, and the translator will translate it back to something you understand. You don’t know  how to translate anything neither know how to store or find something in the archive. They have the knowledge and responsibility to do it for you.

The domain layer contains the mayor part of your application, it knows the applications view of the world around it. For example: In real life, a person can either be male or female. If the application is not gender specific, then it doesn’t care, doesn’t want to know this detail. In stone age, this layer would be the workers that perform the actual work to produce something. They have the knowledge to build something and might talk in ways the customer of the product might have a hard time understanding.

The presentation layer contains the parts the end users will actually see. This are the windows or webpages in applications. In stone age, this can be a little bit seen as the seller of the goods (when he is trying to sell it, not the actual transaction). He promotes the products, and stands in front of the customer and shows them why the should be interested in buying this. If we have multiple sellers of goods, then they all might promote and try to sell the products in a different way, but If they sell or if they require more information they all talk to the workers in the domain layer in one way. They only know what’s been told to them by the workers and they are the experts in translating that to a great story/ experience for the customer so that they will buy the product.

MVC, MVP, M-V-VM which fancy name will we use?

There are many different patters to present your application to the world. One of the most famous ones in WPF world latterly is the M-V-VM pattern, which is the one we will use in this application. Below I will explain the others so you are aware of them. I think this gives you a better understanding of the M-V-VM pattern itself, if you know the history.

Presentation patterns are not something new, they have been around for ages. Today there are even different variations of the single patterns itself. We will not focus on that in this blog post, just be aware they are there.

MVC

The MVC (Model View Controller) pattern was first described in 1979 by Trygve Reenskaug at Xerox Parc http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html. In this pattern the model represents the actual data of the application and the logic to modify it (todays: data entities, repository, data services, etc.), the view represents the user interface with it’s logic and contains the state of the application. The controller takes care of the communication between them. The model is unaware of the controller and the view, so for example the model could be unit tested without them.

image

In short an interaction will work like this:

  • A request comes into the controller
  • The controller finds the correct view and model and combines them together
  • The view knows the current state of the application (for example: if something is modified or if a checkbox is checked)
  • The view will notify the controller synchronize it’s state with the model (for example: if you press the save button, it will fire an event to the controller saying I’ve changed please handle it.)
  • The controller will send the model the changed data and it will verify the data and store it.
  • The model will then notify the view, to let it know the data is changed

image

At first it might seems weird that the model sends out an event to let the view know it’s changed. This is because there can be more than 1 view listening to changes on the model. So if you have 2 views open and change the data in one view and let the controller update the model, both views will update and not only the one that you changed the data in (which basically is already updated, because you made your changes there).

MVP

The MVP (Model View Presenter) pattern was first described in 1996 by Mike Potel at Taligent http://www.wildcrest.com/Potel/Portfolio/mvp.pdf.  It’s a little bit like the next version of MVC or the evolution of the MVC pattern, but you could also identify it as a variant of the MVC pattern. The model represents the same as in the MVC pattern. The view is in charge of rendering the data and contains a direct reference to the presenter to delegate user interaction. The presenter will interpret the interaction and modify the view based upon it. So the presenter will control the view, instead of provide a communication channel, like the controller does in MVC. It will mostly contain a reference to the view in the form of an interface and will directly set property values on the view.

image

In short an interaction will work like this:

  • A request arrives at the view
  • The view delegates the request to the presenter
  • The presenter will load the required data from the model (can be a selection of the model)
  • The presenter will set the data on the view
  • The view will delegate the button press event to the presenter (user pressed save button)
  • The presenter will handle the event and call the model
  • The model will validate and persist the data and modify the presenter it’s updated
  • The presenter will set the new values of the model on the view

image

In this pattern the state of the application is still stored in the view.

PM & M-V-VM

The M-V-VM (Model View View Model) pattern was first described in 2005 by John Gossman at Microsoft http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx. It is identical to the PM (Presentation Model) defined by Martin Fowler in 2004 http://martinfowler.com/eaaDev/PresentationModel.html , but is more specific to the binding mechanism which is available in XAML. The main difference between the MVP pattern and this is that the state of the application is moved from the View to the Presenter (or View Model). The M-V-VM pattern is available in a variant called View first and View Model first. We will focus on View first.

image

In short the interaction will work like this:

  • A request arrives at the view
  • The view binds the data context to the view model
  • The view model will initialize itself with data from the model
  • The view is bound to the view model’s properties (will get it’s data that way)
  • The view will delegate the button press command to the view model (user pressed save button)
  • The view model will handle the command and talk to the model if required
  • The model will validate and persist the data and send the view model the updated data
  • The bindings on the view model will update the view

image

Great, so now how will we use this?

To use M-V-VM you can use one of the many frameworks available like MVVM Light http://mvvmlight.codeplex.com/or Caliburn http://caliburn.codeplex.com/. In this system we will build it as simple as possible from scratch. This might not be the best path to take, but I think this path will expose you to the ideas behind it and allow you to pick a framework that fit’s best with your own needs. For now, we will continue with the concepts. The next blog post will focus on creating the base classes (and will contain the actual code yeah!).

You should probably have a global view of the different presentation patterns by now. Since our application contains more than only presentation logic, I will continue to shortly explain the other patterns we will use to build out our application.

Dependency Injection (DI)

DI is a specific form of inversion of control, which is another scary term. DI is simply said a way to remove hardcoded dependencies between objects within your application and inject them dynamically at runtime. Applications with hard coded dependencies are hard to test, maintain, and change.

For example:

If you want to create an object which has 3 dependencies on other objects, that again have 16 dependencies on others, and those have x dependencies on others, etc. etc. Then you need to create them all, but what if you only want to test the functionality of the first object you’ve created and don’t really care about the rest. With DI you can just inject 3 dummy dependencies into the object you want to test, and let them return what you would expect.

In our application we will make use of Ninject (http://ninject.org/) for DI, just because it got a cool ninja logo. You can yourself pick any DI framework you want.

Repository pattern

The repository pattern abstracts away the logic to store objects to a data store. The repository has the following knowledge: how to store and retrieve objects out of the data store (for example a database). Using this pattern will allow you to later on switch the data storage easily, because the application is unaware of the underlying data store. In a later blog post we will look deeper into this. In stone age: This is the desk of the archivist, where you tell them.. I want this.. they are responsible for performing your action and retrieve or store your object.

Unit Of Work

The unit of work pattern will be used together with the repository pattern, to perform a sort of transactions. Let’s say a user adds 5 items separately, but you only want to save them if the user clicks save when closing the application. In a later blog post we will look deeper into this.

What’s next?

In the next blog post, I will show you how to build the core components (base of M-V-VM, repository, etc.) for our application, so we can later start to implement them. After we got this in place, we can go back to the global overview of the domain diagram and pick the functionality we will build first.

Tags:

Building a control template/style for the tabControl to clone the office 2010 ribbon File look

imageThis blog post is re-posted from www.eriklieben.com

Looking at the file tab of word 2010, I’ve wondered if a WPF tab control could be transformed to this layout. At first, this felt like something that could never be done, without doing a lot of magic or building it from scratch. After playing around for a while I discovered the power of WPF and it’s enormous flexibility.

The hardest part to figure out was creating the arrow on the right side of the selected item and keeping the light gray border line across the whole left bar. I’ve almost solved this (there is still a small 1px difference in my result), but it’s close enough.

The style I ended up with looks a little bit different than the actual control, but if you need to choose between rewriting a whole control or just only modifying it’s style, then I think accepting difference is more effective than going for the exact clone. And still, if you would want to use this, you would probably still transform it to your taste. You might need to optimize it for your usage, if you want to use it, because I’ve only tested it with the content below. It’s basically for you to learn how to do this, not to just copy & paste and reuse without understanding anything about it Smile

 

 

 

 

 

Let’s start, first of all we will need to get the tab control in place:

<Window x:Class="TestClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <TabControl Name="tabSteps">
        <TabItem Header="Info" IsSelected="True">
            <TextBlock>Info content</TextBlock>
        </TabItem>
        <TabItem Header="Recent">
            <TextBlock>Recent content tab</TextBlock>
        </TabItem>
        <TabItem Header="New">
            <TextBlock>New content tab</TextBlock>
        </TabItem>
        <TabItem Header="Print">
            <TextBlock>Print content tab</TextBlock>
        </TabItem>
        <TabItem Header="Save &amp; Send">
            <TextBlock>Save &amp; send content tab</TextBlock>
        </TabItem>
        <TabItem Header="Help">
            <TextBlock>Help tab</TextBlock>
        </TabItem>
    </TabControl>
</Window>

This will create a window, with a tab control like you would expect:

image

What we only want to do is modify the visual appearance of this tab control. To do this, we can make use of control template functionality of WPF. This functionality allows you to modify the rendering of all controls that make use of control templates.

We want to be able to use this control template anywhere, so we need to add a resource dictionary to our project that will contain our control template to reuse it.

Perform the following to add the Dictionary:

  • left mouse click on your project
  • click add
  • pick ‘Resource Dictionary’

Now in this resource dictionary we will add the following XAML code:

    <ControlTemplate x:Key="OfficeTabControl" TargetType="{x:Type TabControl}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="160" />
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Border Background="#FFE9ECEF" 
                    Grid.Column="0" 
                    BorderBrush="LightGray" 
                    BorderThickness="1" 
                    SnapsToDevicePixels="True" />
            <StackPanel IsItemsHost="True"
                        Grid.Column="0"
                        Margin="0,0,-1,0" 
                        SnapsToDevicePixels="True" />
            <ContentPresenter 
                Content="{TemplateBinding SelectedContent}" 
                Grid.Column="1" 
                Margin="15,0,0,0" />
        </Grid>
    </ControlTemplate>

This will create a control template with the name OfficeTabControl with a grid inside. This grid is divided in 2 columns. We want one for the tabs and one for the actual content inside the tab. The left side of the grid contains a border containing just a gray background and a light gray border line. Above(after in code) this in the same column is a StackPanel containing a property IsItemsHost set to true. This property will indicate that generated items (the tabs) will be placed in this panel. In the second column is a ContentPresenter. This is a placeholder for the content that is defined inside the tab.

Now let’s let our TabControl use our new style, set the Template property to the control template:

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="OfficeTab.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <TabControl Name="tabSteps" Template="{StaticResource OfficeTabControl}">

To do this, you will need to add the resource dictionary to your window resources. Then set the template to use our control template we’ve just created. When you run the application now, you already see a bit of the structure we want.

image

Now we need to modify the rendering of the Tab control item, this is the tab on the page, which is now on the left side. The rendering of this control can be modified by changing the control template the control. Above the Grid of the control template in the resource dictionary, we will add the following XAML:

<ControlTemplate x:Key="OfficeTabControl" TargetType="{x:Type TabControl}">
    <ControlTemplate.Resources>
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid SnapsToDevicePixels="True">
                            <ContentPresenter 
                                Name="buttonText"
                                Margin="15,0,5,0" 
                                TextBlock.FontFamily="Calibri" 
                                TextBlock.FontSize="12pt" 
                                TextBlock.Foreground="Black" 
                                Content="{TemplateBinding Header}"
                                VerticalAlignment="Center"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ControlTemplate.Resources>

When we run the application now, we see that we removed the button look from the tabs:

image

Now let’s start adding more style to it. To do this we will make use of visual states.

Visual states can be seen as a method to improve the overlap between the developer (that works in code) and the designer, which designs the layout for a given state. The developer can share certain states, for example mouse over and the designer can create a look for that.

The visual state templates can be added within the Grid. We can set the Normal state and the MouseOver state, to add the mouse over effect. To do this, we need to create a border that contains the background and the visual look of that state.

We add this style by creating 2 borders, one for the gray line on the right side and one for the background color and the light blue top and bottom borders.

<Border Name="hoverShape"
        Height="40"
        Margin="0,0,1,0" 
        SnapsToDevicePixels="True" 
        BorderThickness="0,0,1,0" 
        BorderBrush="LightGray">
    <Border BorderBrush="#FFA1B7EA"
            BorderThickness="0,1" 
            Background="#FFE5EEF9" 
            Height="40" 
            SnapsToDevicePixels="True" />
</Border>

After that we will create the storyboards for the visual states. One for the normal state, which will animate the hoverShape opacity to zero. And one for the mouse over state, which will animate the hoverShape opacity to 1.

<Grid SnapsToDevicePixels="True">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup Name="CommonStates">
            <VisualState Name="MouseOver">
                <Storyboard>
                    <DoubleAnimation 
                        Storyboard.TargetName="hoverShape" 
                        Storyboard.TargetProperty="Opacity" 
                        To="1" 
                        Duration="0:0:.1"/>
                </Storyboard>
            </VisualState>
            <VisualState Name="Normal">
                <Storyboard>
                    <DoubleAnimation 
                        Storyboard.TargetName="hoverShape" 
                        Storyboard.TargetProperty="Opacity" 
                        To="0"
                        Duration="0:0:.1"/>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>

If we start the application now, it will look like below.

image

Time to add the blue selected item bar. Below the hoverShape we will add another border called buttonShape, this allows us to add a 2 pixel darker blue border on the top and bottom of the blue shape.

(You can skip this step) Create a screenshot of the shape you want and open Expression Blend, with the pen tool, create a path that follows the shape you want, see the black line below. Go to, view, xaml, and there you will see your path, the data property contains the values that represent the shape.

image

You can for now just copy the code sample below, this also contains the correct gradient and properties, but I’ve just added the above to show how you can do it yourself.

Your XAML code should now looks like below:

<Border 
    Name="buttonShape" 
    Opacity="0" 
    BorderBrush="#FF0343A6" 
    BorderThickness="0,2" 
    Height="40"
    SnapsToDevicePixels="True">
    <Path 
        Data="M214,108 L346,108 346.125,118.125 337.75,126.125 346.375,134 346.375,143.875 214.25,144.25 z" 
        SnapsToDevicePixels="True" 
        Stretch="Fill"
        Height="40">
        <Path.Fill>
            <RadialGradientBrush GradientOrigin="0.2,0.5" RadiusX="0.8" RadiusY="0.8">
                <GradientStop Color="#FF5FA3F6" Offset="0" />
                <GradientStop Color="#FF0C55B9" Offset="1" />
            </RadialGradientBrush>
        </Path.Fill>
    </Path>
</Border>

When you run the application now, nothing is different yet. That’s because we still need to define the visual states for the selected tab.

When adding the code below, you will add the visual state group SelectionStates and add the behavior/storyboards for the selected and unselected state. As you can see we are again modifying the opacity of shapes to create the effects. To get the text color white, I’ve added the color animation. For some reason this gives an error in the designer, because it is unable to identify the TextBlock, I don’t know why this is yet. I am not a WPF expert, but maybe someone out there knows why this is or how to solve it Smile

<VisualStateGroup Name="SelectionStates">
    <VisualState Name="Selected">
        <Storyboard>
            <DoubleAnimation 
                Storyboard.TargetName="buttonShape" Storyboard.TargetProperty="Opacity" 
                To="1" Duration="0:0:.3"/>
            <DoubleAnimation 
                Storyboard.TargetName="hoverShape" Storyboard.TargetProperty="Opacity" 
                To="0" Duration="0:0:.1"/>
            <ColorAnimation 
                Storyboard.TargetName="buttonText" 
                Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" 
                To="White" Duration="0:0:.1" />
        </Storyboard>
    </VisualState>
    <VisualState Name="Unselected">
        <Storyboard>
            <DoubleAnimation 
                Storyboard.TargetName="buttonShape" 
                Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:.1"/>
            <DoubleAnimation 
                Storyboard.TargetName="hoverShape" 
                Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:.1"/>
        </Storyboard>
    </VisualState>
</VisualStateGroup>

When we are running the application now, we see it get’s closer to the end result:

image

Still there is one problem, we need to hide the background that is still visible below the arrow. We can do this by adding a white shape below it and add the opacity change to the storyboards for the selected and unselected states.

<VisualStateGroup Name="SelectionStates">
    <VisualState Name="Selected">
        <Storyboard>
            <DoubleAnimation 
                Storyboard.TargetName="buttonBackgroundShape" 
                Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
        </Storyboard>
    </VisualState>
    <VisualState Name="Unselected">
        <Storyboard>
            <DoubleAnimation 
                Storyboard.TargetName="buttonBackgroundShape" 
                Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
        </Storyboard>
    </VisualState>
</VisualStateGroup>

When we run the application now, we can see the end result:

image

Have fun. The source for the style can be found here: OfficeTab.xaml (8.37 kb)

Tags:

.NET