iPhone like red badge notification in a WPF project? - c#

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>

Related

How to create a simple menu with labels on the left side with WPF?

I've been developing some simple apps (just for educational purposes) with Windows Forms and now I'm starting to learn WPF, but it seems a bit more complex to me.
I would like to create a simple menu like the one you can see in the pictures. I've been trying to find it on Google and YouTube, but I only found tutorials about "Hamburger menu", which isn't what I'm looking for.
This is really an area where WPF shines: the layout you describe can be implemented with nothing more than a restyled tab control.
Start with an unstyled tab control with TabStripPlacement of Left:
Then edit the TabControl style to add gradient and margins behind the TabPanel:
Add the image and override the TabItem style to set the font and remove the background. I used a chevron to indicate selection rather than bolding the text, but that would have been handled the same way.
Here is the full XAML used for the screenshots above:
<Window x:Class="StackOverflowTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackOverflowTabControl"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style x:Key="ItemContainerStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid Margin="15,5">
<Path Width="10" Height="14" Margin="0,2,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" Stretch="Fill" Fill="#FF000000" Data="F1 M 39.8307,37.6042L 36.6641,34.4375L 25.1849,23.3542L 35.4766,23.3542L 50.5182,37.6042L 35.4766,51.8542L 25.1849,51.8542L 36.6641,40.7708L 39.8307,37.6042 Z " Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}, RelativeSource={RelativeSource TemplatedParent}}"/>
<ContentPresenter Content="{TemplateBinding Header}" Margin="20,5,10,5">
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Light" />
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
<Setter Property="TabStripPlacement" Value="Left" />
<Setter Property="ItemContainerStyle" Value="{StaticResource ItemContainerStyle}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Padding="5">
<Border.Background>
<LinearGradientBrush EndPoint="0,0" StartPoint="1,0">
<GradientStop Color="#FFC7C7C7" Offset="0"/>
<GradientStop Color="#FFECECEC" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<DockPanel>
<Image DockPanel.Dock="Bottom" HorizontalAlignment="Center" Margin="20" Source="pack://application:,,,/StackOverflowTabControl;component/twc.png" Width="200" />
<TabPanel x:Name="headerPanel" Background="Transparent" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
</DockPanel>
</Border>
<Border x:Name="contentPanel" Grid.Column="1" Margin="5,0,0,0">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl Style="{DynamicResource TabControlStyle1}">
<TabItem Header="System Information">
<TextBlock Text="Windows 10 pro" />
</TabItem>
<TabItem Header="Something else">
<TextBlock Text="Other page" />
</TabItem>
</TabControl>
</Grid>
</Window>

creating custom design for control in WPF [duplicate]

Would somebody know how to recreate this button style in WPF? As I do not know how to make the different compartments. As well as the 2 different texts and text styles?
To solve your question definitely need to use the Style and Template for the Button. But how exactly does he look like? Decisions may be several. For example, Button are two texts to better define the relevant TextBlocks? Can be directly in the template, but then use the buttons will be limited, because the template can be only one ContentPresenter. I decided to do things differently, to identify one ContentPresenter with an icon in the form of a Path, and the content is set using the buttons on the side.
The style:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#373737" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<Path x:Name="PathIcon" Width="15" Height="25" Stretch="Fill" Fill="#4C87B3" HorizontalAlignment="Left" Margin="17,0,0,0" Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z "/>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E59400" />
<Setter Property="Foreground" Value="White" />
<Setter TargetName="PathIcon" Property="Fill" Value="Black" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="OrangeRed" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Sample of using:
<Button Width="200" Height="50" VerticalAlignment="Top" Margin="0,20,0,0" />
<Button.Content>
<StackPanel>
<TextBlock Text="Watch Now" FontSize="20" />
<TextBlock Text="Duration: 50m" FontSize="12" Foreground="Gainsboro" />
</StackPanel>
</Button.Content>
</Button>
Output
It is best to StackPanel determine the Resources and set the Button so:
<Window.Resources>
<StackPanel x:Key="MyStackPanel">
<TextBlock Name="MainContent" Text="Watch Now" FontSize="20" />
<TextBlock Name="DurationValue" Text="Duration: 50m" FontSize="12" Foreground="Gainsboro" />
</StackPanel>
</Window.Resources>
<Button Width="200" Height="50" Content="{StaticResource MyStackPanel}" VerticalAlignment="Top" Margin="0,20,0,0" />
The question remains with setting the value for TextBlock Duration, because this value must be dynamic. I implemented it using attached DependencyProperty. Set it to the window, like that:
<Window Name="MyWindow" local:MyDependencyClass.CurrentDuration="Duration: 50m" ... />
Using in TextBlock:
<TextBlock Name="DurationValue" Text="{Binding ElementName=MyWindow, Path=(local:MyDependencyClass.CurrentDuration)}" FontSize="12" Foreground="Gainsboro" />
In fact, there is no difference for anyone to determine the attached DependencyProperty, because it is the predominant feature.
Example of set value:
private void Button_Click(object sender, RoutedEventArgs e)
{
MyDependencyClass.SetCurrentDuration(MyWindow, "Duration: 101m");
}
A complete listing of examples:
XAML
<Window x:Class="ButtonHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ButtonHelp"
Name="MyWindow"
Title="MainWindow" Height="350" Width="525"
WindowStartupLocation="CenterScreen"
local:MyDependencyClass.CurrentDuration="Duration: 50m">
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#373737" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
<Setter Property="FontFamily" Value="./#Segoe UI" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}">
<Grid>
<Path x:Name="PathIcon" Width="15" Height="25" Stretch="Fill" Fill="#4C87B3" HorizontalAlignment="Left" Margin="17,0,0,0" Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z "/>
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E59400" />
<Setter Property="Foreground" Value="White" />
<Setter TargetName="PathIcon" Property="Fill" Value="Black" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="OrangeRed" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<StackPanel x:Key="MyStackPanel">
<TextBlock Name="MainContent" Text="Watch Now" FontSize="20" />
<TextBlock Name="DurationValue" Text="{Binding ElementName=MyWindow, Path=(local:MyDependencyClass.CurrentDuration)}" FontSize="12" Foreground="Gainsboro" />
</StackPanel>
</Window.Resources>
<Grid>
<Button Width="200" Height="50" Content="{StaticResource MyStackPanel}" VerticalAlignment="Top" Margin="0,20,0,0" />
<Button Content="Set some duration" Style="{x:Null}" Width="140" Height="30" VerticalAlignment="Top" HorizontalAlignment="Left" Click="Button_Click" />
</Grid>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MyDependencyClass.SetCurrentDuration(MyWindow, "Duration: 101m");
}
}
public class MyDependencyClass : DependencyObject
{
public static readonly DependencyProperty CurrentDurationProperty;
public static void SetCurrentDuration(DependencyObject DepObject, string value)
{
DepObject.SetValue(CurrentDurationProperty, value);
}
public static string GetCurrentDuration(DependencyObject DepObject)
{
return (string)DepObject.GetValue(CurrentDurationProperty);
}
static MyDependencyClass()
{
PropertyMetadata MyPropertyMetadata = new PropertyMetadata("Duration: 0m");
CurrentDurationProperty = DependencyProperty.RegisterAttached("CurrentDuration",
typeof(string),
typeof(MyDependencyClass),
MyPropertyMetadata);
}
}
Here's my attempt. Looks more similar to the OP's sample and provides settable properties for icon (FrameworkElement), title (string) and subtitle (string). The output looks like this:
Here's XAML:
<Button x:Class="Controls.FancyButton"
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"
xmlns:local="clr-namespace:Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Width="300" Height="80"
BorderBrush="{x:Null}" BorderThickness="0">
<Button.Effect>
<DropShadowEffect BlurRadius="12" Color="Gray" Direction="270" Opacity=".8" ShadowDepth="3" />
</Button.Effect>
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Width="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=ActualWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=ActualHeight}">
<Border x:Name="MainBorder" CornerRadius="3" Grid.ColumnSpan="2" Margin="0,0,4,4" BorderBrush="Black" BorderThickness="1">
<Border.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#FF5E5E5E" Offset="0" />
<GradientStop Color="#FF040404" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.2*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Border CornerRadius="2" Margin="0" BorderBrush="LightGray" BorderThickness="0,1,0,0" Grid.ColumnSpan="2" Grid.RowSpan="2" />
<Line X1="10" Y1="0" X2="10" Y2="10" Stretch="Fill" Grid.Column="0" HorizontalAlignment="Right" Stroke="#0C0C0C" Grid.RowSpan="2" />
<Line X1="10" Y1="0" X2="10" Y2="10" Stretch="Fill" Grid.Column="1" HorizontalAlignment="Left" Grid.RowSpan="2">
<Line.Stroke>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#4D4D4D" Offset="0" />
<GradientStop Color="#2C2C2C" Offset="1" />
</LinearGradientBrush>
</Line.Stroke>
</Line>
<ContentControl HorizontalAlignment="Center" VerticalAlignment="Center" Grid.RowSpan="2">
<ContentControl.Content>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Image">
<Binding.FallbackValue>
<Path Data="M0,0 L30,15 L0,30Z">
<Path.Effect>
<DropShadowEffect Direction="50" ShadowDepth="2" />
</Path.Effect>
<Path.Fill>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Color="#4B86B2" Offset="0" />
<GradientStop Color="#477FA8" Offset="1" />
</LinearGradientBrush>
</Path.Fill>
</Path>
</Binding.FallbackValue>
</Binding>
</ContentControl.Content>
</ContentControl>
<Grid Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="Title" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title, FallbackValue='Watch Now'}" Grid.Column="1" VerticalAlignment="Bottom" FontFamily="Calibri" FontWeight="Bold" FontSize="28" Foreground="White" Margin="20,0,0,0" />
<TextBlock x:Name="SubTitle" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SubTitle, FallbackValue='Duration: 50 min'}" Grid.Column="1" Grid.Row="1" VerticalAlignment="top" FontFamily="Calibri" FontSize="14" Foreground="White" Margin="20,0,0,0" />
</Grid>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Title" Property="TextDecorations" Value="Underline" />
<Setter TargetName="SubTitle" Property="TextDecorations" Value="Underline" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="MainBorder" Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="#FF5E5E5E" Offset="0" />
<GradientStop Color="#FFA4A4A4" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
Here's the code-behind:
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
public partial class FancyButton : Button
{
public FancyButton()
{
InitializeComponent();
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(FancyButton), new FrameworkPropertyMetadata("Title", FrameworkPropertyMetadataOptions.AffectsRender));
public string SubTitle
{
get { return (string)GetValue(SubTitleProperty); }
set { SetValue(SubTitleProperty, value); }
}
public static readonly DependencyProperty SubTitleProperty =
DependencyProperty.Register("SubTitle", typeof(string), typeof(FancyButton), new FrameworkPropertyMetadata("SubTitle", FrameworkPropertyMetadataOptions.AffectsRender));
public FrameworkElement Image
{
get { return (FrameworkElement)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register("Image", typeof(FrameworkElement), typeof(FancyButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
}
}
Here is how to use it:
<controls:FancyButton Grid.Row="1" HorizontalAlignment="Right" Margin="3" Title="Watch Now" SubTitle="Duration: 50 min">
<controls:FancyButton.Image>
<Path Data="M0,0 L30,15 L0,30Z">
<Path.Effect>
<DropShadowEffect Direction="50" ShadowDepth="2" />
</Path.Effect>
<Path.Fill>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Color="#4B86B2" Offset="0" />
<GradientStop Color="#477FA8" Offset="1" />
</LinearGradientBrush>
</Path.Fill>
</Path>
</controls:FancyButton.Image>
</controls:FancyButton>
<!--Customize button -->
<LinearGradientBrush x:Key="Buttongradient" StartPoint="0.500023,0.999996" EndPoint="0.500023,4.37507e-006">
<GradientStop Color="#5e5e5e" Offset="1" />
<GradientStop Color="#0b0b0b" Offset="0" />
</LinearGradientBrush>
<Style x:Key="hhh" TargetType="{x:Type Button}">
<Setter Property="Background" Value="{DynamicResource Buttongradient}"/>
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border CornerRadius="4" Background="{TemplateBinding Background}" BorderBrush="Black" BorderThickness="0.5">
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="2"></DropShadowEffect>
</Border.Effect>
<Grid>
<Path Width="9" Height="16.5" Stretch="Fill" Fill="#000" HorizontalAlignment="Left" Margin="16.5,0,0,0" Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z " Opacity="0.2">
</Path>
<Path x:Name="PathIcon" Width="8" Height="15" Stretch="Fill" Fill="#4C87B3" HorizontalAlignment="Left" Margin="17,0,0,0" Data="F1 M 30.0833,22.1667L 50.6665,37.6043L 50.6665,38.7918L 30.0833,53.8333L 30.0833,22.1667 Z ">
<Path.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="5"></DropShadowEffect>
</Path.Effect>
</Path>
<Line HorizontalAlignment="Left" Margin="40,0,0,0" Name="line4" Stroke="Black" VerticalAlignment="Top" Width="2" Y1="0" Y2="640" Opacity="0.5" />
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,0" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#E59400" />
<Setter Property="Foreground" Value="White" />
<Setter TargetName="PathIcon" Property="Fill" Value="Black" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="OrangeRed" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In this day and age of mouse driven computers and tablets with touch screens etc, it is often forgotten to cater for input via keyboard only. A button should support a focus rectangle (the dotted rectangle when the button has focus) or another shape matching the button shape.
To add a focus rectangle to the button, use this XAML (from this site).
Focus rectangle style:
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle Margin="2" StrokeThickness="1" Stroke="#60000000" StrokeDashArray="1 2" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Applying the style to the button:
<Style TargetType="Button">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}" />
...
<Button x:Name="mybtnSave" FlowDirection="LeftToRight" HorizontalAlignment="Left" Margin="813,614,0,0" VerticalAlignment="Top" Width="223" Height="53" BorderBrush="#FF2B3830" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="B Titr" FontSize="15" FontWeight="Bold" BorderThickness="2" TabIndex="107" Click="mybtnSave_Click" >
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FF080505" Offset="1"/>
<GradientStop Color="White" Offset="0.536"/>
</LinearGradientBrush>
</Button.Background>
<Button.Effect>
<DropShadowEffect/>
</Button.Effect>
<StackPanel HorizontalAlignment="Stretch" Cursor="Hand" >
<StackPanel.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF3ED82E" Offset="0"/>
<GradientStop Color="#FF3BF728" Offset="1"/>
<GradientStop Color="#FF212720" Offset="0.52"/>
</LinearGradientBrush>
</StackPanel.Background>
<Image HorizontalAlignment="Left" Source="image/Append Or Save 3.png" Height="36" Width="203" />
<TextBlock HorizontalAlignment="Center" Width="145" Height="22" VerticalAlignment="Top" Margin="0,-31,-35,0" Text="Save Com F12" FontFamily="Tahoma" FontSize="14" Padding="0,4,0,0" Foreground="White" />
</StackPanel>
</Button>

Mouseover-trigger on Slider Template

I'm changing the Standard WPF Slider's template. And I want it where you move your mouse over the area the slider occupies and the thumb starts an animation to change its size, even if the cursor isn't directly on top of the thumb.
But I don't know how to bind to a parent like that.
I'll try to post what I got without making it look nasty. Here's what I got that's relevant (I think. If you need more, tell me)
<ControlTemplate x:Key="SliderHorizontal" TargetType="{x:Type Slider}" x:Name="SliderHorizontal">
<Track x:Name="PART_Track" Grid.Row="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource LeftRepeatButtonTransparent}">
</RepeatButton>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RightRepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Focusable="False" Height="20" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbHorizontalDefault}" VerticalAlignment="Center" Width="Auto" Margin="0,0,-5.5,0">
</Thumb>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
triggers galore
</ControlTemplate.Triggers>
</ControlTemplate>
And here is the template for the thumb itself. It's the ellipse grip I want to change the size of.
<ControlTemplate x:Key="SliderThumbHorizontalDefault" TargetType="{x:Type Thumb}">
<Ellipse x:Name="grip" Fill="White" Height="15" Width="15" Effect="{StaticResource z-depth1}">
</Ellipse>
<ControlTemplate.Triggers>
more triggers
</ControlTemplate.Triggers>
</ControlTemplate>
How would I go about doing this binding?
Any help would be appreciated!!
Within the RenderTransform block I would add a scaleTransform
<Style x:Key="HorizontalSliderThumbStyle" TargetType="{x:Type Thumb}">
.....
.....
<ControlTemplate TargetType="{x:Type Thumb}">
<Canvas x:Name="canvas" SnapsToDevicePixels="true">
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<TranslateTransform X="5.5" Y="11"/>
</TransformGroup>
</Canvas.RenderTransform>
Then within the control template's triggers I would add the scaling up of the canvas.
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Trigger.EnterActions>
<BeginStoryboard Name="EnlargeThumb">
<Storyboard TargetName="canvas"
TargetProperty="RenderTransform.Children[1].ScaleX" >
<DoubleAnimation To="2" Duration="0:0:0" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="EnlargeThumb" />
</Trigger.ExitActions>
</Trigger>
Note the style and what not that I got is from the template extracted via visual studio.

How to parameterize styles?

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.

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

Categories