The animation hardly stops and the image resets its position but I want the animation to finish to the next full 360°.
Any ideas on that?
The XAML code:
<Button
BorderThickness="0"
Cursor="Hand"
Command="{Binding RefreshCommand}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
<Image Source="../Resources/RefreshIcon.png">
<Image.Style>
<Style>
<Setter Property="Image.RenderTransform">
<Setter.Value>
<RotateTransform />
</Setter.Value>
</Setter>
<Setter Property="Image.RenderTransformOrigin" Value=".5,.5">
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRefreshing}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="RotationStoryboard">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Angle"
From="0"
To="360"
Duration="0:0:0.8"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsRefreshing}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="RotationStoryboard"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
The final solution except the fact that it has to be put into a UserControl to make it more generic (also see #Sheridans post and my comment below):
<Button
BorderThickness="0"
Cursor="Hand"
Command="{Binding RefreshCommand}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
<Image
Name="RefreshImage"
Source="../Resources/RefreshIcon.png"
RenderTransformOrigin=".5,.5">
<Image.Resources>
<Storyboard
x:Key="RotationStoryboard"
Completed="RotationStoryboardCompleted">
<DoubleAnimation
Storyboard.Target="{Binding ElementName=RefreshImage}"
Storyboard.TargetProperty="RenderTransform.Angle"
From="0"
To="360"
Duration="0:0:1.5">
<DoubleAnimation.EasingFunction>
<CircleEase EasingMode="EaseInOut"></CircleEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</Image.Resources>
<Image.Style>
<Style>
<Setter Property="Image.RenderTransform">
<Setter.Value>
<RotateTransform />
</Setter.Value>
</Setter>
<Setter Property="Image.RenderTransformOrigin" Value=".5,.5">
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRefreshing}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<StaticResource ResourceKey="RotationStoryboard"/>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
Code behind:
public partial class SomeView
{
public SomeView()
{
InitializeComponent();
}
private void RotationStoryboardCompleted(object sender, EventArgs e)
{
var viewModel = (ISomeViewModel)DataContext;
var storyboard = (Storyboard)((ClockGroup)sender).Timeline;
if (viewModel.IsRefreshing)
{
storyboard.Begin();
}
}
}
I don't know of any way to do this in XAML, but with code, there is a Timeline.Completed Event that you can use. If you attach a handler to your Storyboard, then it will get called when it is finished and you can do whatever you want:
<BeginStoryboard>
<Storyboard Name="RotationStoryboard" Completed="StoryboardCompleted">
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" From="0"
To="360" Duration="0:0:0.8" />
</Storyboard>
</BeginStoryboard>
In code:
private void StoryboardCompleted(object sender, EventArgs e)
{
// Restart your Storyboard here each time until you want it to stop.
}
For further help, please see the example in the linked page on MSDN.
Related
I tried to open the ContextMenu on button left click not on the right clcik so I did something as below. But menu items 'All' and 'Selected' are not firing their respective events in .cs.
Xaml
<Button Content="Import" ContextMenuService.IsEnabled="false">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="All"
Click="ImportAll_Click"/>
<MenuItem Header="Selected"
Click="ImportSelected_Click"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
Xaml.cs
private void ImportAll_Click(object sender, RoutedEventArgs e)
{
}
private void ImportSelected_Click(object sender, RoutedEventArgs e)
{
}
Is there something that I am missing here?
Try to define the ContextMenu as a resource:
<Button Content="Import" ContextMenuService.IsEnabled="false">
<Button.Resources>
<ContextMenu x:Key="cm">
<MenuItem Header="All" Click="ImportAll_Click"/>
<MenuItem Header="Selected" Click="ImportSelected_Click"/>
</ContextMenu>
</Button.Resources>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<Setter Property="ContextMenu" Value="{StaticResource cm}" />
</Style>
</Button.Style>
</Button>
I have a button which shows a text and an image:
For this I use a StackPanel with a TextBlock and an Image inside of it.
When the variable "ActiveState" changes the Background of the StackPanel should change too, for this I use DataTriggers
ActiveState=0 -> Red /
ActiveState=1 -> Blue /
ActiveState=2 -> blinking Blue (for this I use a Storyboard and a Color Animation)
The blinking Trigger (Value=2) is working fine, but the two other Triggers (Value=0 + Value=1) are not working.
When I remove the Background of the Stackpanel (Background="Transparent") the first two Triggers are working but the last one get the following Exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
Additional information: Background property does not point to a dependencyobject in path '(0).(1)'
This is my code:
<Button>
<Button.Template>
<ControlTemplate TargetType="Button">
<StackPanel Orientation="Horizontal" Name="SelectButtonStackpanel" Background="Transparent">
<TextBlock Text="{Binding Text}"/>
<Image Source="{Binding Image}" Stretch="Uniform" Height="40" Width="40"/>
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding ActiveState}" Value="0">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="1">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(StackPanel.Background).(SolidColorBrush.Color)"
To="Blue" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever"
>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(StackPanel.Background).(SolidColorBrush.Color)"
Duration="0:0:1"
>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Do you have any idea how I get all three Triggers working?
best regards
Phil
When you directly set Background="Transparent" on the StackPanel, this has higher precedence than a value set from a Style Setter. So remove the direct assignment and add another Setter for the default Background.
Besides that, if you want to animate Background.Color you should always explictly assign SolidColorBrushes instead of predefined Brushes like Background="Red".
<StackPanel Orientation="Horizontal" Name="SelectButtonStackpanel">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ActiveState}" Value="0">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Red"/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="1">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Blue"/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ActiveState}" Value="2">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Background.Color"
To="Blue" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
<TabControl x:Name="tabControl" TabStripPlacement="Top" BorderBrush="White" FontSize="14" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="98" Margin="0,2,0,0" VerticalAlignment="Top" Width="992" FontFamily="Segoe UI">
<TabControl.Resources>
<Style TargetType="TabItem">
<Style.Triggers>
<Trigger Property="TabItem.IsSelected" Value="True">
<Setter Property="TabItem.Foreground" Value="#FF0090D3"/>
<Setter Property="TabItem.FontSize" Value="14"/>
<Setter Property="TabItem.FontFamily" Value="Segoe Ui SemiBold"/>
</Trigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border" BorderThickness="0,0,0,0" BorderBrush="White" Background="White" CornerRadius="13,13,13,13" Margin="1,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="10,2"/>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline>
<ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="(Border.Background).Color" From="White" To="LightGray" Duration="0:0:0.2"/>
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline>
<ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="(Border.Background).Color" From="LightGray" To="White" Duration="0:0:0.2"/>
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Width="190" Visibility="Hidden" />
<TabItem Height="25" IsSelected="True" Width="63" Header="Home">
<Canvas>
<Rectangle x:name="rect1" Fill="#FFF4F4F5" Height="59" Width="58" Canvas.Top="3" Canvas.Left="1">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="LightGray" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="White" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Canvas>
</TabItem>
<TabItem Width="63" Header="Tools"/>
<TabItem Width="76" Header="Add-ons" />
</TabControl>
The code allows me to change the tab header color when the mouse is over the header.However,the problem is....when mouse is over a content inside a tabitem,the MouseEnter event of both the TabItem and the content fires.Which results in : If i hover over a content(eg. a rectangle that i'm using),the MouseEnter event of the content/control is fired.But it also fires the 'MouseEnter' event of the tabItem...So the tabItem/TabHeader chages it's color even when i don't hover over the header/TabItem rather when i hover over a control/content inside the tabitem...How do i prevent this ?
Update
I found this code :
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true" />
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}" Value="Top"/>
from here.But where should i put it ?
Damn!! It was reallllyyy easy! Just changed :
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
To :
<ControlTemplate.Triggers>
<EventTrigger SourceName="ContentSite" RoutedEvent="MouseEnter">
i want the WPF button behaves in a way on mouse over only i want to show content of button (its an image)
and also on mouseover i want the background as transparent + no border .
Button content is an image and i am giving a padding of 50 px . so mouse is anywhere near to 50px on button i can see the button content.
The xaml i used is
<Button Style="{StaticResource FadeOutButton}" Padding="50" Opacity="0" >
<Image Source="Images\myimage.JPG"></Image>
and
<Style x:Key="FadeOutButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<EventTrigger RoutedEvent="Control.MouseEnter">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation Duration="0:0:1" To="1" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Control.MouseLeave">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation Duration="0:0:1" To="0" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
What else i have to add to make the background transparent on mouseover in addition to current effect
Try this
<Window.Resources>
<Style x:Key="FadeOutButton" TargetType="{x:Type Button}">
<Style.Resources>
<Storyboard x:Key="MouseOverAnimation" >
<DoubleAnimation Duration="0:0:1" To="1" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
<Storyboard x:Key="MouseOutAnimation">
<DoubleAnimation Duration="0:0:1" To="0" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Transparent" >
<ContentPresenter Margin="{TemplateBinding Padding}" HorizontalAlignment="Center" Content="{TemplateBinding Content}" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Transparent"/>
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource MouseOverAnimation}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource MouseOutAnimation}" />
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Button Style="{StaticResource FadeOutButton}" Padding="50" Opacity="0" >
<Image Source="Screenshot_3.png"></Image>
</Button>
I would like to have a button that blinks/animate when triggered by DataTrigger. I want to animate the button's background. Below is my xaml code.
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid>
<Button x:Name="Button" Content="Button" Width="25" Height="25" Margin="158,62,320,224" Click="Button_Click"></Button>
<Button Style="{StaticResource ButtonStyle}" Content="Button" Focusable="False" Height="75" HorizontalAlignment="Left" Margin="23,146,0,0" Name="btnImgBrush" VerticalAlignment="Top" Width="160"></Button>
</Grid>
</Grid>
Here are the back end code:
public Boolean Notification
{
get { return new_notification; }
set
{
new_notification = value;
RaisePropertyChanged("Notification");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (Notification)
{
Notification = false;
}
else
{
Notification = true;
}
}
But, it didn't work. Any ideas why it didn't work?
Any help is greatly appreciated, Thanks.
At last its working. Thanks :)
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
Try this-
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Notification,RelativeSource={RelativeSource AncestorType=Window}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" From="Transparent" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Notification,,RelativeSource={RelativeSource AncestorType=Window}}" Value="False">
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
Both TM Rocket and Vishal answer are correct but probably the following is the most correct and clean way to do it
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Transparent"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Notification}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking">
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Orange" Duration="00:00:00.4" RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>