SilverLight 2.0: Setting the Background of a Button

buttons

I know, this hardly seems a topic worthy of a blog post.  To create a Button in SilverLight like the first in the picture is just:

<Button Content="Stock Button"/>

To set the Background to a dark green, you might assume works (I know I did):

<Button Content="Green Stock Button" Background="DarkGreen" />

In the land of WPF, that would do exactly what you expect, but in SilverLight (2.0, I haven’t tested 3.0) you would get the second button in the image.  It’s a nice “touch of green” to the button, but hardly noticeable to most and impossible to see on some LCD monitors.  Even if you set the background to Black, it will only darken the gradient a bit.

So what’s the problem?  Digging into the SilverLight 2.0 source, the default style for a button is:

<ControlTemplate TargetType="controls:Button">
    <Grid>
        <!-- snipped the 36 lines of VisualStatManager here -->
        <Border x:Name="Background" CornerRadius="3" Background="White" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
            <Grid Background="{TemplateBinding Background}"  Margin="1">
                <Border Opacity="0"  x:Name="BackgroundAnimation" Background="#FF448DCA" />
                <Rectangle x:Name="BackgroundGradient" >
                    <Rectangle.Fill>
                        <LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
                            <GradientStop Color="#FFFFFFFF" Offset="0" />
                            <GradientStop Color="#F9FFFFFF" Offset="0.375" />
                            <GradientStop Color="#E5FFFFFF" Offset="0.625" />
                            <GradientStop Color="#C6FFFFFF" Offset="1" />
                        </LinearGradientBrush>
                    </Rectangle.Fill>
                </Rectangle>
            </Grid>
        </Border>
        <ContentPresenter
            x:Name="contentPresenter" 
            Content="{TemplateBinding Content}" 
            ContentTemplate="{TemplateBinding ContentTemplate}"
            VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
            Margin="{TemplateBinding Padding}"/>
        <Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
        <Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
    </Grid>
</ControlTemplate>

The issue is the Rectangle with it's own Background is on top of the Grid which has the Background from our button. Also, the Border is hard-coded to White, so even if we handle the rectangle we’ll have a white box padding the content . We can fix this using our own ContentTemplate, but that means also adding all the VisualStatManager stuff to get all the animations that go along with the Button.  That’s more effort than I want to put into fixing a Button.

A second method is to subclass Button, and modify the template in the OnApplyTemplate override.  I don’t want to remove any of the controls in the template, since that will break the animations, so my fix is to lower the opacity of the rectangle and border so the background shows through:

public class BKButton : Button {

    public override void OnApplyTemplate() {
        base.OnApplyTemplate();

        Border border = GetTemplateChild("Background") as Border;
        Rectangle rect = GetTemplateChild("BackgroundGradient") as Rectangle;

        if (border != null) {
            border.Background = this.Background;
            border.Opacity = .6;
        }
        if (rect != null) {
            LinearGradientBrush lbrush = rect.Fill as LinearGradientBrush;
            if (lbrush != null) {
                lbrush.Opacity = .6;
            }
        }
    }
}

When I use this, it looks like the third button in the image.  From XAML you’ll need to add xmlns:local="clr-namespace:MyProjectNameSpace" to the UserControl, and then call this button:

<local:BKButton Content="Green BKButton Button" Background="DarkGreen" />

Posted By Mike On Tuesday, June 09, 2009
Filed under silverlight wpf button | Comments (8)

Submit this story to DotNetKicks   

jake - Friday, June 12, 2009 11:43:22 PM

great post, was wondering how to do this myself lately

Perry - Thursday, January 28, 2010 6:31:12 PM

Thanks for the info, was confused digging through blend and you saved me from trying to implement my own button :P

Gomathy - Monday, April 12, 2010 8:39:38 AM

Hai,
I had included the BKbutton class function in my page.xaml. Still If i try to include BKbutton in my xaml code, it is throughing the error "BKButton not found". I need your guidance.

Thanks in Advance

Mike - Monday, April 12, 2010 11:29:07 AM

@Gomathy check that you added the namespace properly for the button

Jessy - Wednesday, April 14, 2010 6:57:52 AM

Hi Mike,

Where I need to include the BKButton class. Is it in page.xaml?

Dg - Wednesday, April 14, 2010 7:18:34 AM

I'm new to silverlight.

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SilverlightApplication1.Page"
xmlns:local="clr-namespace:SilverlightApplication1.Page"
Width="640" Height="480" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">

<Grid x:Name="LayoutRoot" Background="White">
<local:BKButton Content="Green BKButton Button" Background="DarkGreen" />
</Grid>
</UserControl>

If I buid , it throws the following error:

'The name "BKButton does not exist in the namespace"clr-namespace:SilverlightApplication1.Page".

Help me to solve this simple issue.

Gomathy - Wednesday, April 14, 2010 7:36:13 AM

Mike,

Thanks a lot.Now i was able to set the background as I wish.

Can you guide me regarding silverlight for windows embedded? i need to know how to swiitch between different pages.

Please guide me.

Thanks in Advance

Mikhail - Friday, March 04, 2011 3:56:47 AM

Thank you, Mike!!!

Leave a comment



Your name:
 

Your email (not shown):
 
Will display your Gravatar image.

Your website (optional):



About Michael

Michael C. Neel, born 1976 in Houston, TX and now live in Knoxvile, TN. Software developer, currently .Net focused. Board member of ETNUG and organizes CodeStock, East Tennessee's annual developers conference. .Net speaker, a Microsoft ASP.NET MVP and ASPInsider. Co-Founder of FuncWorks, LLC and GameMarx.

Proud father of two amazing girls, Rachel and Hannah, and loving husband to Cicelie who inflates and pops his ego as necessary.

 Subscribe to ViNull.com |  Comments

Follow me on Twitter | Contact Me

Related Posts

Ada Lovelace Day: Mary Everest Boole and Beautiful Math

October 16th, 2012 is technically Ada Lovelace Day, a day for celebrating women in science, technology, engineering, and math (STEM), but as long as it's ... Read more

Code Camp Room Planner

I just finished creating a project on CodePlex for the Code Camp Room Planner, a little app I wrote to help me plan the schedule at CodeStock 2009.  ... Read more

SilverLight Interop with Flash/Flex (flashlight?)

While the marketers and academics focus on the battle between silverlight and flash/flex, here in Mike's Mad Scientist Labs we've been focused on making ... Read more

WPF: Using Viewbox and Canvas to create a virtual resolution workspace

First, for you SilverLight 2.0 junkies, you can skip over this.  SilverLight 2.0 doesn't (yet?) support the WPF ViewBox. The problem: when you start ... Read more

SilverLight: Using Web Services with SilverLight 1.0

After posting my first SilverLight example, Dave Campbell asked if this approach could work for getting SQL data into a SilverLight 1.0 app (remember, ... Read more

XNA 3D Primer by Michael C. Neel

XNA 3D Primer by Michael C. Neel
Buy Now: [ Amazon ] [ Wrox ]

GameMarx

CodeStock

ASPInsiders Member

ETNUG Member