Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a shadow drop effect around a wpf button like the google button

I am trying to create a google button in wpf. I have found the following link that specifies the google's button css style

Google button css style

Right now I have also searched the net and found out this style that resembles google's button

<Style x:Key="GoogleGreyButton" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="#FFF5F5F5"/>
    <Setter Property="BorderBrush" Value="#FFDCDCDC"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="#FF666666"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="FontSize" Value="11"/>
    <Setter Property="FontFamily" Value="Arial"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="8,7"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Name="border" 
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}" 
                    BorderBrush="{TemplateBinding BorderBrush}" 
                    CornerRadius="1" 
                    Background="{TemplateBinding Background}">
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>

                </Border>

                <ControlTemplate.Triggers>
                    <!--TODO: Set the right colors-->
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="border" Property="BorderBrush" Value="#FFC6C6C4" />
                        <Setter Property="Foreground" Value="#FF020202" />
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                       ` <!--Some setters here--> `

                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="#ADADAD"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Trigger Property="IsPressed" Value="True"> part i need to produce some shadow drop effect as in the above Google button css style, may I know how can i achieve that?

like image 708
tesla1060 Avatar asked Sep 28 '12 07:09

tesla1060


2 Answers

You can produce a shadow drop ish effect by changing the BorderThickness some. Try something like this:

<Trigger Property="IsMouseOver" Value="True">
    <Setter TargetName="border" Property="BorderBrush" Value="DarkGray" />
    <Setter Property="Foreground" Value="Black" />
    <Setter Property="BorderThickness" Value="1,1,2,2" />
</Trigger>

Note that doing it this way can mess up your layout a bit, since it changes the total width and height of your button, so other controls around it may "bump around" just a tad when hovering the button.

If you want to play around with proper drop shadow, you can add drop shadow to your button like this:

<Button>
    <Button.BitmapEffect>
        <DropShadowBitmapEffect Color="Black" Direction="320" Softness="1" ShadowDepth="10" Opacity="0.5" />
    </Button.BitmapEffect>
</Button>

EDIT:

As MrDosu commented, BitMapEffect is deprecated so you should probably use Effect instead.

Here's a sample using Effect:

<Trigger Property="IsMouseOver" Value="True">
    <Setter TargetName="border" Property="BorderBrush" Value="DarkGray" />
    <Setter Property="Foreground" Value="Black" />
    <Setter Property="Button.Effect">
        <Setter.Value>
            <DropShadowEffect Color="Black" Direction="320" ShadowDepth="3" BlurRadius="5" Opacity="0.5" />
        </Setter.Value>
    </Setter>
</Trigger>
like image 85
Eirik Avatar answered Oct 11 '22 13:10

Eirik


In the past, I implemented material elevation like this:

public static class UI
{
    private static readonly DropShadowEffect[] sShadows = new[]
    {
        new DropShadowEffect()
        {
            BlurRadius = 5,
            ShadowDepth = 1
        },
        new DropShadowEffect()
        {
            BlurRadius = 8,
            ShadowDepth = 1.5
        },
        new DropShadowEffect()
        {
            BlurRadius = 14,
            ShadowDepth = 4.5
        },
        new DropShadowEffect()
        {
            BlurRadius = 25,
            ShadowDepth = 8
        },
        new DropShadowEffect()
        {
            BlurRadius = 35,
            ShadowDepth = 13
        }
    };

    public static readonly DependencyProperty ElevationProperty = DependencyProperty.RegisterAttached("Elevation", typeof(double), typeof(UI), new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender, null, OnElevationChanged));

    public static double GetElevation(this UIElement element) => element.GetValue(ElevationProperty) as double? ?? default;

    public static void SetElevation(this UIElement element, double elevation) => element.SetValue(ElevationProperty, elevation);

    private static object OnElevationChanged(DependencyObject dependencyObject, object value)
    {
        if (dependencyObject is UIElement element && value is double elevation)
        {
            if (elevation == 0)
            {
                element.Effect = null;
            }
            else
            {
                var effect = CreateElevation(elevation, element.Effect);

                if (effect != null)
                    element.Effect = effect;
            }
        }

        return value;
    }

    private static void MixShadows(DropShadowEffect target, DropShadowEffect other, double balance)
    {
        target.BlurRadius = target.BlurRadius * (1 - balance) + other.BlurRadius * balance;
        target.ShadowDepth = target.ShadowDepth * (1 - balance) + other.ShadowDepth * balance;
    }

    private static Effect CreateElevation(double elevation, Effect source)
    {
        if (elevation < 0 || elevation > 12)
            throw new ArgumentOutOfRangeException("Elevation must be between 0 and 12.", nameof(elevation));

        elevation = Math.Max(0, elevation / 12 * shadows.Length - 1);

        var shadows = sShadows;
        var prevIndex = (int)Math.Floor(elevation);
        var index = (int)elevation;
        var nextIndex = (int)Math.Ceiling(elevation);
        var approx = elevation - index;
        var shadow = shadows[index];
        var modify = false;

        if (approx != 0)
            MixShadows(shadow, approx < 0 ? shadows[prevIndex] : shadows[nextIndex], Math.Abs(approx));

        if (source is DropShadowEffect sourceShadow)
        {
            sourceShadow.BlurRadius = shadow.BlurRadius;
            sourceShadow.ShadowDepth = shadow.ShadowDepth;
            shadow = sourceShadow;
            modify = true;
        }

        shadow.Direction = 270;
        shadow.Color = Color.FromArgb(0xAA, 0, 0, 0);
        shadow.Opacity = .42;
        shadow.RenderingBias = RenderingBias.Performance;

        return modify ? null : shadow;
    }
}

Then,

<Button local:Elevation="2">Elevated button</Button>

Any value between 2 and 12 can be set as the elevation of any UIElement.

like image 42
Davide Cannizzo Avatar answered Oct 11 '22 13:10

Davide Cannizzo