How to parameterize styles? - c#

I'm new in WPF. I'm trying to do same styles. The idea is to have a button style customizable. So, for example, i would like to change the background color of the button. or the image of the button.
Here is the code of the style
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
x:Class="WPFControlsApp.App"
StartupUri="MainWindow.xaml">
<Application.Resources>
<!-- Resources scoped at the Application level should be defined here. -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Simple Styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ControlTemplate x:Key="CustomButtonStyle" TargetType="{x:Type Button}">
<ControlTemplate.Resources>
<Storyboard x:Key="CuandoEstoyArribaDelBoton">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="Glow">
<EasingColorKeyFrame KeyTime="0" Value="White"/>
<EasingColorKeyFrame KeyTime="0:0:0.7" Value="#FF562020"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Grid>
<Rectangle x:Name="Background" Fill="#FF5A98EB" RadiusY="15" RadiusX="15" Stroke="#FF114FA1" StrokeThickness="2"/>
<Rectangle x:Name="Glow" Fill="White" RadiusY="15" RadiusX="15" Stroke="{x:Null}" StrokeThickness="0" Margin="0,0,0,49" Opacity="0.215"/>
<Rectangle x:Name="Glass" RadiusY="15" RadiusX="15" Stroke="#FF114FA1" StrokeThickness="2" Opacity="0.475">
<Rectangle.Fill>
<RadialGradientBrush RadiusY="0.62" RadiusX="0.62" GradientOrigin="0.506,1.063">
<GradientStop Color="#00000000" Offset="0"/>
<GradientStop Color="#FF00084B" Offset="1"/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{Binding MINOMBREBOTON, FallbackValue=MiBoton}"/>
<Image HorizontalAlignment="Left" Margin="7,24,0,25" Width="100" Source="{Binding BtnImageSource}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="CuandoEstoyArribaDelBoton_BeginStoryboard"/>
</Trigger.ExitActions>
<Trigger.EnterActions>
<BeginStoryboard x:Name="CuandoEstoyArribaDelBoton_BeginStoryboard" Storyboard="{StaticResource CuandoEstoyArribaDelBoton}"/>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
here is the problem i don´t know how to solve
<Image HorizontalAlignment="Left" Margin="7,24,0,25" Width="100" Source="{Binding BtnImageSource}"/>
I have a binding named BtnImageSource. But i don´t know how to set it in button definition.
<Button Content="Salir" Height="102" HorizontalAlignment="Right" Margin="0,0,25,26" Name="btn_salir" VerticalAlignment="Bottom" Width="280" ClipToBounds="False" Click="btn_salir_Click" Style="{StaticResource CustomButtonStyle}" />
Do you know how can i have 3 o 4 buttons each one with the same style but different images?
This is a test for a new app. The idea is to use styles with parameters or find another alternative.
Thanks in advance. I hope be clear.

Yes thats possible.... DynamicResource should help. Set the color properties to some DynamicResource (with a resource key). This Key may not exist at the time of declaration. Then when you need a specific color, then create a Brush of that color and declare it same Key and merge with the relevant resource.
E.g. you have this style resource that uses a dynamic color brush DynamicColorBrush to set to a button's background...
<App.Resources ...>
<Style TargetType="{x:Type Button}">
<Setter Background="{DynamicResource DynamicColorBrush}" />
</Style>
....
Note that App.Resources does not have DynamicColorBrush defined. Now suppose you define buttons in two different views
<UserControl ... x:Class="UserControl1">
<UserControl.Resources>
<SolidColorBrush x:Key="DynamicColorBrush" Color="Red"/>
</UserControl.Resources>
<Grid><Button Content="Red Button"/></Grid>
</UserControl>
and
<UserControl ... x:Class="UserControl2">
<UserControl.Resources>
<SolidColorBrush x:Key="DynamicColorBrush" Color="Green"/>
</UserControl.Resources>
<Grid><Button Content="Green Button"/></Grid>
</UserControl>
This should work.
The whole concept of flexi themes where runtime base color change is allowed is done using the dynamic resource concept.

Related

How to trigger a ColorAnimation when TabItem IsSelected?

The following code triggers a ColorAnimation when window is loaded.
How can I trigger a ColorAnimation when TabItem.IsSelected gets true instead?
<Window x:Class="WpfApplication1.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">
<Window.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="True">
<Border x:Name="Bd" Margin="0,0,3,0" BorderThickness="3" BorderBrush="{TemplateBinding BorderBrush}">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop x:Name="myGradientStop" Offset="0.0" Color="Yellow"/>
</LinearGradientBrush>
</Border.Background>
<Border.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<ColorAnimation Storyboard.TargetName="myGradientStop" Storyboard.TargetProperty="Color" From="Pink" To="Lavender" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<ContentPresenter x:Name="Content" ContentSource="Header" RecognizesAccessKey="True"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" TargetName="Bd" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="TabItem1">
<Label Content="TabItem1 content goes here..." />
</TabItem>
<TabItem Header="TabItem2">
<Label Content="TabItem2 content goes here..." />
</TabItem>
<TabItem Header="TabItem3">
<Label Content="TabItem3 content goes here..." />
</TabItem>
</TabControl>
</Grid>
</Window>
Thanks in advance.
You should change your EventTrigger to a Trigger on the TabItem.IsSelected property and move it in the ControlTemplate.Triggers collection that you already have.
Your ControlTemplate would become:
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="True">
<Border x:Name="Bd" Margin="0,0,3,0" BorderThickness="3" BorderBrush="{TemplateBinding BorderBrush}">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop x:Name="myGradientStop" Offset="0.0" Color="Yellow"/>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter x:Name="Content" ContentSource="Header" RecognizesAccessKey="True"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" TargetName="Bd" Value="Black"/>
<Trigger.EnterActions>
<BeginStoryboard x:Name="beginStoryboard">
<Storyboard RepeatBehavior="Forever">
<ColorAnimation Storyboard.TargetName="myGradientStop"
Storyboard.TargetProperty="Color"
From="Pink"
To="Lavender"
Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="beginStoryboard"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I assumed you wanted to stop the animation when the TabItem gets unselected so I added a RemoveStoryboard exit action in the Trigger.

WPF Datagrid trigger row colour based on value

I have a WPF application that contains a datagrid. The datagrid is bound to my object OrderBlock which contains a List of type Orders.
<DataGrid DataContext="{Binding OrderBlock}"
Name="dataGridOrdersGood"
ItemsSource="{Binding Orders}"
This works fine and displays nicely in my datagrid. There is one property (StatusGood) in my List though that I would like to display as a combobox where there can be only two values, "Send" or "Hold".
If the value in the combobox is "Hold" I would like the row to turn different colour. Ideally using a linear gradient going from silver to yellow. I have tried the code below - literally just trying to turn the row red for the moment but nothing happens. I can't see what is wrong with my code below. The trigger part is very close to the bottom of the code below. I'm new to WPF and struggling with it at the moment. The code below has mainly come from a very good post that can be found here, http://www.codeproject.com/Articles/586132/WPF-DataGrid-Custommization-using-Style-and-Templa
<!-- Data grid formatting Grid Row template -->
<Style x:Key="DG_Row" TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="LightGreen"/>
<Setter Property="Opacity" Value="1"/>
<Setter Property="Padding" Value="3,2,2,3"/>
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRow}">
<Border x:Name="DGR_Border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<Border.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Offset="0" Color="Transparent"/>
<GradientStop Offset="1" Color="Silver"/>
</LinearGradientBrush>
</Border.Background>
<SelectiveScrollingGrid>
<SelectiveScrollingGrid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</SelectiveScrollingGrid.ColumnDefinitions>
<SelectiveScrollingGrid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
</SelectiveScrollingGrid.RowDefinitions>
<DataGridCellsPresenter Grid.Column="1"
ItemsPanel="{TemplateBinding ItemsPanel}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<DataGridDetailsPresenter Grid.Row="1"
Grid.Column="1"
SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical},
Converter={x:Static DataGrid.RowDetailsScrollingConverter},
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
Visibility="{TemplateBinding DetailsVisibility}" />
<DataGridRowHeader Grid.RowSpan="2" SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Row},
Converter={x:Static DataGrid.HeadersVisibilityConverter},
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</SelectiveScrollingGrid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Normal_AlternatingRow">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
<EasingColorKeyFrame KeyTime="0" Value="#AAF0C570" />
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
<EasingColorKeyFrame KeyTime="0" Value="#AAFF7F00" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Normal_Selected">
<Storyboard>
<!-- ColorAnimation here same as Normal_AlternatingRow state -->
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<!-- ColorAnimation here same as Normal_AlternatingRow state -->
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
<Style.Triggers>
<DataTrigger Binding="{Binding Active}" Value="Hold">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Setter>
</Style>
As always any help would be great.
Thanks
M
Do you need to change the behaviour of the DataGridRow, or is it sufficient to alter the style?
If changing the row highlighting based on a property is all you need, you should be able to just use a simpler Style, something like this:
<!-- A brush -->
<LinearGradientBrush x:Key="BgBrush1" StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#888888"/>
<GradientStop Offset="1" Color="#FFFFF86E"/>
</LinearGradientBrush>
<!-- Your row style -->
<Style x:Key="HighlightRow" TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding StatusGood}" Value="Hold">
<Setter Property="Background" Value="{StaticResource BgBrush1}" />
</DataTrigger>
</Style.Triggers>
</Style>
You should be able to apply the style when required in a DataGrid by using your style as a StaticResource for the RowStyle property:
<DataGrid DataContext="{Binding OrderBlock}"
Name="dataGridOrdersGood"
ItemsSource="{Binding Orders}"
RowStyle="{StaticResource HighlightRow}" />
Edit:
If you want to retain the rest of your styling and use a control template, you can place your DataTrigger in your ControlTemplate.Triggers, you'll also have to supply a TargetName property, to specify the element you wish the trigger to act on, so using my above brush, and your initial code:
<!-- Data grid formatting Grid Row template -->
<Style x:Key="DG_Row" TargetType="{x:Type DataGridRow}">
<Setter Property="Template">
<Setter.Value>
<!-- Your code -->
<ControlTemplate TargetType="{x:Type DataGridRow}">
<Border x:Name="DGR_Border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<!-- Your code -->
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding StatusGood}" Value="Send">
<Setter TargetName="DGR_Border" Property="Background" Value="{StaticResource BgBrush1}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Where DGR_Border is the name you had given your border with the existing gradient.

Set button as selected state and change style

This is my actual button style:
<Style x:Key="CategoryButtonStyle" TargetType="{x:Type Button}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="grid">
<Path x:Name="TabPath" StrokeThickness="2"
Margin="{Binding ElementName=buttonContent, Converter={x:Static c:ContentToMarginConverter.Value}}"
Stroke="{StaticResource BorderBrush1}"
Fill="{StaticResource TabItemPathBrush}">
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="False" StartPoint="1,0"
Segments="{Binding ElementName=buttonContent, Converter={x:Static c:ContentToPathConverter.Value}}">
</PathFigure>
</PathGeometry>
</Path.Data>
<Path.LayoutTransform>
<!-- For some reason -->
<ScaleTransform ScaleY="-1"/>
</Path.LayoutTransform>
</Path>
<Rectangle x:Name="TabItemTopBorder" Height="2" Visibility="Visible"
VerticalAlignment="Bottom" Fill="{StaticResource BorderBrush1}"
Margin="{Binding ElementName=TabPath, Path=Margin}" />
<ContentPresenter x:Name="buttonContent" Margin="10,2,10,2" VerticalAlignment="Center"
TextElement.Foreground="{StaticResource ForegroundBrush}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Fill" TargetName="TabPath">
<Setter.Value>
<SolidColorBrush Color="#FFe4f6fa"/>
</Setter.Value>
</Setter>
<Setter Property="BitmapEffect">
<Setter.Value>
<DropShadowBitmapEffect Direction="302" Opacity="0.4"
ShadowDepth="2" Softness="0.5"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="grid" Value="0.25"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and I need add code that I could set button to selected state which looks like when button is pressed. I was thinking about using VisualStateManager but I am not sure if it's good way and how can I do this. I've started with something like this:
<VisualStateManager.VisualStateGroups>
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabPath"
Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="#FFe4f6fa" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateManager.VisualStateGroups>
But It's not working. I just don't know what to use in storyboard.
Edit - Almost working:
<VisualState x:Name="Selected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="TabPath" Storyboard.TargetProperty="Fill.(LinearGradientBrush.GradientStops)[0].(GradientStop.Color)" To="#FFe4f6fa" Duration="0:0:0" />
<ColorAnimation Storyboard.TargetName="TabPath" Storyboard.TargetProperty="Fill.(LinearGradientBrush.GradientStops)[1].(GradientStop.Color)" To="#FFa9cde7" Duration="0:0:0" />
</Storyboard>
</VisualState>
Forget to add my brushes:
<LinearGradientBrush x:Key="TabItemSelectedPathBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFe4f6fa" Offset="0"/>
<GradientStop Color="#FFa9cde7" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="TabItemPathBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFa9cde7" Offset="0"/>
<GradientStop Color="#FF3164a5" Offset="1"/>
</LinearGradientBrush>
Use ToggleButton that uses the same style and template.
In your style (the one in your original question) change TargetType on style and control template to ButtonBase.
In control template triggers add this trigger:
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter Property="Fill" TargetName="TabPath">
<Setter.Value>
<SolidColorBrush Color="#FFe4f6fa"/>
</Setter.Value>
</Setter>
<Setter Property="BitmapEffect">
<Setter.Value>
<DropShadowBitmapEffect Direction="302" Opacity="0.4" ShadowDepth="2" Softness="0.5"/>
</Setter.Value>
</Setter>
</Trigger>
Now you can use this style for buttons, toggle buttons, radio buttons and check boxes.
VisualStates should be declared on the root element of the ControlTemplate. With the following code,
<Grid>
<Grid.Resources>
<SolidColorBrush x:Key="FillBrush" Color="Magenta" />
<Color x:Key="StateBrush" >#a3bfb1</Color>
<Style x:Key="CategoryButtonStyle" TargetType="{x:Type Button}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Green" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" x:Name="root">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TabPath"
Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource StateBrush}">
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="grid">
<Path x:Name="TabPath" StrokeThickness="1"
Stroke="Blue"
Fill="{StaticResource FillBrush}" Canvas.Left="16.75"
Canvas.Top="14"
Width="50"
Height="40"
Data="F1 M 26.75,24L 16.75,34L 23.5,34L 34,24L 23.5,14L 16.75,14L 26.75,24 Z ">
<Path.LayoutTransform>
<!-- For some reason -->
<ScaleTransform ScaleY="-1"/>
</Path.LayoutTransform>
</Path>
<ContentPresenter x:Name="buttonContent" Margin="10,2,10,2" VerticalAlignment="Center"
TextElement.Foreground="{TemplateBinding Foreground}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Button x:Name="test" Style="{StaticResource CategoryButtonStyle}" Content="Test" VerticalAlignment="Center" Width="200px" BorderBrush="#888" BorderThickness="1px"/>
</Grid>
this code will change the state as intended.
VisualStateManager.GoToState(test, "TestState", true);
Make changes to the template as required, but make sure you put the VisualState declaration in the Root element of the ControlTemplate (Border in this example)
EDIT:
I've updated the Selected VisualState's transition declaration with correct property path. Let me know if it solves your problem.
Personally I would use Blend for such task, it's really the companion to Visual Studio for developing WPF applications.
In a few clicks you would get to it, nothing prevents you to either use it or just copy the XAML it generated to your project.
Editing the button style
Triggers
Here are all your button states
Blend is like bread for butter, WPF is tastier with it, unless you prefer plain butter :-)
Note that if you are on VS2012 and working on a WPF project, Microsoft Blend + SketchFlow Preview for Visual Studio 2012 is the version that will allow you to edit WPF projects. The version bundled with VS2012 is only for Windows Store apps.

How to create circle button with image background and CLICKING feel IN Silverlight

Right now i can change the look of the button to an ellipse with a background image.
However, when i click on it, i don't feel the CLICKING EFFECT of the normal buttons in Silverlight
Can anyone help me how to get that effect?
this is my XAML style for the round button
<style x:Key="roundButton" TargetType="Button">
<Setter Properties="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Ellipse width="100" height="100">
<Ellipse.Fill>
<ImageBrush ImageSource="./icon.png">
</Ellipse.Fill>
</Ellipse>
</ControlTemplate>
</Setter.Value>
</Setter>
</style>
after searching around i know that i should use the VisualStateManager in Systems.Window. This is how my XAML looks now but i still can't get the CLICKING feeling like normal buttons
<Style x:Key="roundButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Width="100" Height="100">
<Ellipse.Fill>
<ImageBrush ImageSource="./icon.png" />
</Ellipse.Fill>
</Ellipse>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualState x:Name="MouseOver"/>
<vsm:VisualState x:Name="Normal"/>
<vsm:VisualState x:Name="Pressed"/>
<vsm:VisualState x:Name="Disabled"/>
</vsm:VisualStateGroup>
<vsm:VisualStateGroup x:Name="FocusStates">
<vsm:VisualState x:Name="Unfocused"/>
<vsm:VisualState x:Name="Focused"/>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You need to set the triggers for your button for the respective state.
<style x:Key="roundButton" TargetType="Button">
<Setter Properties="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Ellipse width="100" height="100">
<Ellipse.Fill>
<ImageBrush ImageSource="./icon.png"/>
</Ellipse.Fill>
</Ellipse>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!-- mouse over look and feel here -->
</Trigger>
<Trigger Property="IsPressed" Value="True">
<!-- clicked look and feel here -->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</style>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin=".2,.2">
<GradientStop Offset="0.2" Color="White" />
<GradientStop Offset="1" Color="Blue" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<ContentPresenter Content="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Far more simple way is to use Blend. Drag and Drop Ellipse, convert it into control(button). Go to StatesTab adjust the states accordingly. Normally, on pressed state, apply scale trasform to reduce the button size and use translate transform to move the button (appro 2px amount) towards bottom/right would do the trick.
HTH

iPhone like red badge notification in a WPF project?

I have a C# WPF project which generates daily and weekly reports automatically. I want to inform the user when new reports are available, so I thought of a badge like on the iPhone where the number of new messages appears on a little red circle:
I thought of three images: Two images with semi circles on the left and right if the number to display is small. And a third image for the middle for the case that the number is large (123) and wouldn't fit in a circle.
I want a glossy effect, so I've thought of pictures. Does anyone have a good idea how to do this without pictures but programmatically?
Use a Border element and place your text within it. You can set the CornerRadius property for the Border appropriately so that it looks like a circle (or a rounded-rectangle shape, in case the number is bigger).
Here's a first cut, which exploits the fact that CornerRadius will get clamped to half the height or width in Y and X respectively:
<Border Background="Red" CornerRadius="999" Padding="4">
<TextBlock Foreground="White" FontWeight="Bold" FontSize="12">125</TextBlock>
</Border>
I recently had the same requirement, and quickly knocked this UserControl together.
It uses a short animation to draw the user's attention to the badge.
Take a look at "Big Nick's" blog to see some elegant code for applying this UserControl to another UIElement as an Adorner (exactly what a 'badge' is!):
http://blog.bignickolson.com/2009/10/15/overlaying-controls-in-wpf-with-adorners/
(Thanks Nick!)
<UserControl x:Class="BadgeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Opacity="0.8"
ClipToBounds="False"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<Style TargetType="Label" x:Key="BadgeLabel">
<Setter Property="Foreground" Value="White" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Height" Value="22" />
<Setter Property="MinWidth" Value="22" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border Name="badgeOuterBorder" CornerRadius="10" BorderBrush="White" BorderThickness="2" Background="#C80103">
<Border.RenderTransform>
<!--
The TranslateTransform moves the badge so that when used as an Adorner, it bleeds over the upper left
edge of the adorned control.
The ScaleTransform ensures the badge is initially invisible on load ,
but gives the storyboard the ability to 'animate' it into visibility (by manipulating the ScaleTransform).
-->
<TransformGroup>
<TranslateTransform X="-8" Y="-8"/>
<ScaleTransform ScaleX="0" ScaleY="0" />
</TransformGroup>
</Border.RenderTransform>
<Border.BitmapEffect>
<!-- Give some depth to the badge with a drop-shadow -->
<DropShadowBitmapEffect Color="Black" Direction="270" ShadowDepth="3" Softness="0.2" Opacity="1"/>
</Border.BitmapEffect>
<Border CornerRadius="8" Padding="5 0 5 0">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" Opacity="0.8">
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Transparent" Offset="0.6" />
</LinearGradientBrush>
</Border.Background>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}"></ContentPresenter>
</Border>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<!--
The following storyboard animates the ScaleTransform in both the X and Y planes, so that the
badge appears to 'pop' into visibility.
The 1 second delay ensures that the parent control is fully visible before the animation begins,
otherwise, the animation may actually run before the form has rendered to the screen.
-->
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="badgeOuterBorder"
Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleX)"
From="0"
To="0.75"
BeginTime="0:0:1"
Duration="0:0:0.5">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude='1' EasingMode='EaseOut' />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetName="badgeOuterBorder"
Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleY)"
From="0"
To="0.75"
BeginTime="0:0:1"
Duration="0:0:0.5">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude='1' EasingMode='EaseOut' />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" ClipToBounds="False">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Name="d" ClipToBounds="False">
<Label Style="{StaticResource BadgeLabel}" Content="Badge Text" ToolTip="Badge Tooltip" ClipToBounds="False" />
</Grid>
</Grid>
</UserControl>
This is based on Chris1 answer, but this will stretch correctly when the text inside the badge is longer than one digit, I've also set the font to make it more consistent across Windows versions, changed the sizing a bit to compensate and added an outline around the badge.
I've also replaced DropShadowEffect with a Rectangle, this is because I can't use DropShadowEffect in my specific application, DropShadowEffect looks better but my Rectangle shadow is good enough, you can delete the shadow rectangle and use DropShadowEffect if you like.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style TargetType="Label" x:Key="CircularLabel">
<Setter Property="Foreground" Value="White" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="13" />
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle Margin="0 3 0 -3" Fill="LightGray"
RadiusX="11" RadiusY="11" Opacity="0.8"/>
<Border CornerRadius="11"
BorderBrush="DarkGray"
BorderThickness="1">
<Border
HorizontalAlignment="Center"
VerticalAlignment="Center" CornerRadius="10"
Background="#FFC90000"
BorderBrush="White"
BorderThickness="2">
<Grid>
<ContentPresenter
HorizontalAlignment="Center" VerticalAlignment="Center"
Content="{TemplateBinding Content}" Margin="5 1 6 1"/>
<Rectangle x:Name="TopShine" RadiusX="9" RadiusY="9"
VerticalAlignment="Stretch">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" Opacity="0.6">
<GradientStop Color="White" Offset="0.2" />
<GradientStop Color="Transparent" Offset="0.7" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Border>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid>
<UniformGrid>
<Label Style="{StaticResource CircularLabel}">4</Label>
<Label Style="{StaticResource CircularLabel}">100000</Label>
<Label Style="{StaticResource CircularLabel}">CLICK HERE</Label>
</UniformGrid>
</Grid>
</Page>
There are many WPF tutorials out there for glossy buttons. Basically, create a normal button and use the combination of effects and gradients to change the button control template to look like an iPhone button. This is a sample but you can do much more: http://craig.palenshus.com/silverlight/silverlight-and-the-content-presenter-in-an-iphone-like-button/
Here is my go at it, it is not perfect but it looks good enough.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<DropShadowEffect x:Key="ShadowEffect" Direction="270" BlurRadius="5" ShadowDepth="3"/>
<Style TargetType="Label" x:Key="CircularLabel">
<Setter Property="Foreground" Value="White" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Grid>
<Rectangle HorizontalAlignment="Center" VerticalAlignment="Center" Width="20" Height="20" Fill="#FFC90000" RadiusX="10" RadiusY="10" Stroke="White" StrokeThickness="2" Effect="{StaticResource ShadowEffect}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}"></ContentPresenter>
<Rectangle x:Name="TopShine" RadiusX="10" RadiusY="10" Width="20" Height="20" StrokeThickness="2">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" Opacity="0.8">
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Transparent" Offset="0.6" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid>
<Label Style="{StaticResource CircularLabel}">1</Label>
</Grid>
</Page>

Categories