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 06-09-2009 11:16 AM by Michael C. Neel
Filed under:

[Advertisement]

Comments

Jack wrote re: SilverLight 2.0: Setting the Background of a Button
on 06-11-2009 9:15 PM

I've tried, some do not work well in silverlight 3.0

Michael C. Neel wrote re: SilverLight 2.0: Setting the Background of a Button
on 06-12-2009 9:47 AM

I sent in a bug report and Microsoft replied and closed it with "By Design" - so shame on use for thinking it's easy to change the background color of a button (without Blend).

rgd wrote re: SilverLight 2.0: Setting the Background of a Button
on 12-03-2009 2:20 PM

thanks...this worked very nicely

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)