Jose Fajardo
Silverlight and WPF
Friday March 14, 2008
Skinning a button - 4 different ways and counting!
First up let me apologize for the long gaps between my posts, the honest truth is it's taking longer than I thought to master the new features in Silverlight 2.0 beta. It's not that it's hard or anything, well actually some things are, it's more that there's so much to learn! Also I'm taking my time to truly understand why they did it one way versus another way, really cement in my mind the reasoning behind the decisions they made with the architecture.
When I do post I will be sharing the sum total of my learning minus the pain of getting there. The first task I set myself was to investigate how to skin a button or rather turn my existing blend assets into a button.
This is what I found out ...
DESIGNER CREATES THE LOOK AND FEEL OF THE BUTTON
If you stretch you mind back to a previous blog post titled "glowing glass buttons"
That post was purely a walk through of how to create a blend xAml asset that could be used in a xAml friendly application. Wearing my designer hat I used Blend to create a nice glass button. I had a layer that represented the "glow effect" and I named the other layers purely from a cosmetic aesthetic perspective.
Question: Who should be naming things, the designer or the developer??? This could be a problem when a designer and developer need to exchange assets back and forth. As a designer I like to keep my assets ordered and neat. I like to group my layers and have them nicely laid out and named. I don't think this is going to work well when developers are involved.
I will leave the designer/developer workflow debate for another post, the purpose of this post is skinning buttons.
Below is the xAml of the designer created asset :
So we have a graphic representation of a glass button that has a layer called "glowEffect" that defines the glow of the button. At the moment this asset is purely static that does nothing and has no behavior. Still with my designer hat on I give it a couple of animations for situations the button will likely be in:
1. Hover
2. Normal
3. Selected
Here is the marked up xAml of the animations. It is important to note that this is still the designer playing with the graphic, the developer has not touched it yet. Basically the designer does everything they need to do to make it look and behave the way they want it to. Also notice that the designer named the storyboard animations using terms he/she felt comfortable with.
So now we have the xAml asset with some animations. The asset now has the look the designer wants and the behavior the designer wants. The next step is to turn this xAml asset into a real button that can be used in an application.
DEVELOPER MAKES IT INTO A REAL BUTTON
Now with my developer hat on I take this asset with it's designer flavored naming convention and I turn it into a real button, how do I do this in Silverlight 2.0 beta?
Silverlight 2.0 Beta ships with
1. Standard set of controls including a button control
2. Control Framework to build your own controls on top of - more specifically it's called the "part's model" for controls which is new to Silverlight & WPF, to be ported back into WPF at a later date.
The options available to us are
1. Use the new button control and skin it with our asset, assuming it meets our needs, that is does the standard button behave in the way we want it to E.g. hover, click etc.
2. Create our own button control using the new controls "parts" framework
3. leave it as a simple xAml asset and wire up events on them in code all inline to the page or into it's own separate usercontrol xAml.
Options 1 & 2 are arguably the best approaches to take, option 3 is more a hack then anything. Mind you option 3 does have it's merits especially when dealing with prototyping UI's.
Why would I want to use the standard button? Because it already has heaps of logic built in such as mouse-over/selected events, enabled/disabled functionality, a heap of logic that I would need to re-code if I were to build my own button. Let's reuse it and if it doesn't have a feature I need then I can just extend it using inheritance.
MY UNDERSTANDING OF SKINNING IN THE 2.0 BETA WORLD
Because my glowing button is very simple I am just going to use the existing standard button and skin it with my designers skin. In my investigations I found four ways to do this and the terms I used to define these four ways are purely my own names. Let me know if there are proper terms for these and I will update my post accordingly.
1. Inline Template
2. Local Style
3. Global Template
4. External Control
SKINNING : INLINE TEMPLATE
This is the simplest form of skinning. Wherever you have the button just replace it's current skin with your own one using it's internal "ControlTemplate". The green highlighted section is just a "copy and paste" of the asset from the designer (some minor tweaks which I'll mention later) .
SKINNING : LOCAL STYLE
This is very simple, define a style template "LiveButtonLocal" in a resources collection somewhere on the page. If that resource is available to a control then that control can use it. In the sample above the style template is defined in the topmost Grid.Resources which means that all controls within the grids children collection should be able to get access to it, that's my understanding.
It's important to note that the green highlight is just a "copy and paste" of the asset from the designer (some minor tweaks which I'll mention later) .
SKINNING : GLOBAL TEMPLATE
This is very similar to style templates but the template is defined within the Application.Resources collection thus is available to ALL controls in the Silverlight application.
Again the green highlight is just a "copy and paste" of the asset from the designer (some minor tweaks which I'll mention later) .
SKINNING : EXTERNAL CONTROL
Ultimately you can define the skin in an external library so that you can reuse this across all your Silverlight projects. With the first three approaches above if you wanted to reuse the skin on other projects you would need to copy the skin into the new project which is not very good from a reuse perspective.
The actual demo doesn't have this external button fully wired up so the button doesn't glow when mouse hovers over it. A future post will have this working and will walk through this process in more detail as it is an important concept to get right and this blog post will not do justice to it.
For now I'll skim through the bits showing areas that make sense in context of this blog post.
Again the green highlight is just a "copy and paste" of the asset from the designer (some minor tweaks which I'll mention later) .
TURNING THE DESIGNER ASSET INTO SOMETHING THE BUTTON CONTROL CAN UNDERSTAND
In the above 4 ways of skinning I pointed out the green-highlighted areas. Basically that is where the designers assets are suppose to go. If we just cut and paste the xAml asset from the designer into those green areas then the button will render with the new look BUT it will not be wired up to any of the standard buttons events like the mouse over or mouse click. So the button will not have any animations.
What we need to do is to massage the designers assets so that the standard button can understand it. Long story short, the standard button expects to find a couple of specifically named storyboard's, all we need to do is work out what storyboard's it expects and rename the designers ones to them.
Because the source-code for Silverlight is readily accessible we can look at the button class and see what storyboard's it expects. I use a tool called reflector to interrogate the .NET source-code, it's free and it's simple to use.
Basically find the button control and look at it's signature using Reflector this is what I found
What this is telling me is that there are four Storyboard's that the button control expects, if it doesn't find them then it won't do anything for that state. So if we change the designers xAml to reflect these names then technically the button control should be able to find them and call them.
Here's the Storyboard xAml from the designer before any changes:
Here's the xAml after the changes:
So now my skinned buttons are wired up to the standard buttons events. So if you mouse over the skinned button it will now glow and if you click it it will now run the pressed state storyboard. So simple!
CONCLUSION
So there are currently four ways that I can skin a standard Silverlight button, and the 4th way (external control) in my opinion is the most reusable but requires a lot of effort. A future post will delve into this process in more detail .
Skining controls is dead simple, once you know the signature of the standard control you want to skin that is. To truly understand the skining architecture you need to look deep into the source code, do this and you won't regret it believe me. I'm infinitely wiser since I embarked on learning via interrogating MS source code, I plan on re-writing my "A Beautiful web-site" controls in the next couple of weeks with this new found knowledge.
The demo can be seen below, the buttons for each skinning method are on the top right, every button is skinned differently just to prove that they each work. Click on the image to go to the actual Silverlight 2.0 beta sample site.
Source code can be downloaded HERE: GlowingBoard2.zip
It took me a while to get my head around styles, skinning and templates. Hopefully this was useful to you guys.
Equipped with this new found knowledge I can now continue on with my "Windows Live Messenger Project", I was stuck with the whole skinning controls side of things, now I'm not :)
Off to do my next post and remember keep sharing what you can!








