So i have StackPanel that i want to show with blink Style for several seconds and after that i want it to disappear.
I do not want it to be Automatically but control it from code behind:
So currently this is what i have so far:
<Style x:Key="FaderStyle" TargetType="{x:Type StackPanel}">
<Style.Resources>
<Storyboard x:Key="FadeStoryboard">
<DoubleAnimation Storyboard.TargetProperty="(StackPanel.Opacity)"
From="0"
To="1" Duration="0:0:0.7"
RepeatBehavior="0:0:5"
AutoReverse="True"/>
</Storyboard>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FadeStoryboard}"/>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
Code behind:
StackPanel sp;
Storyboard storyboard = Resources["FaderStyle"] as Storyboard;
if (storyboard != null)
storyboard.Begin(sp);
So currently my StackPanel Visibility is Collapsed and after i start the Animation i still cannot see it.
Your code is fine. But your approach to starting the animation is wrong. The trigger starts the animation when Visibility changes to Visible. Not the other way around (which your last piece of code indicates) starting the animation does not change visibility because you didn't write the logic to do that
So with your given code, you need to change the visibility in order to start the animation:
StackPanel sp;
sp.Visibility = Visibility.Visible;
Note that the animation only starts when it enters Visible state. Which means you need to make it collapsed or hidden first.
Related
I have 3 grids. canvas, main and sidebar
<Grid x:Name="canvas">
<Grid x:Name="main"/>
<Grid x:Name="sidebar"/>
</Grid>
I'm trying to create an animation in my WPF MVVM application in which when I click a certain button, the main panel should move to the left (outside of the canvas) and sidebar should take its place with the same animation. Basically, it should look like the sidebar is pushing the main outside of the canvas. And when I click another button the reverse of the exact animation should run. (like the main is pushing sidebar outside of the canvas.
I tried to create a Style and add some Triggers on Visibility property of the Grids. I was somewhat successful in half of the animation but couldn't get it to reverse and animation both panels at the same time.
<Style TargetType="Grid" x:Key="VisibleAnimation">
<Setter Property="Visibility" Value="Collapsed"/>
<Setter Property="RenderTransform">
<Setter.Value>
<TranslateTransform/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.(TranslateTransform.X)"
From="300" To="0" Duration="0:0:0.5"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
Please note that I'm looking for an MVVM solution so no code behind should be involved if possible.
In WPF app I am trying to animate a border colour change on MouseEnter event of a TextBox.
I searched for a while and followed different tutorials, but everything seems to end up the same way:
When the mouse enters the colour of the border changes to what I have set in the animation "From"
Then nothing happens, no animation at all
When mouse leaves after a period longer then the animation duration the colour changes to what I have set in the animation "To"
If the mouse leaves before the animation duration, the colour of the border changes to some colour "in between"
From this I figured that the animation is happening, but it is not showing it as it animates...
The code is here:
private void txtSpeakMe_MouseEnter(object sender, MouseEventArgs e)
{
ColorAnimation ca = new ColorAnimation();
ca.From = (Color)ColorConverter.ConvertFromString("#0066FF");
ca.To = (Color)ColorConverter.ConvertFromString("#FF0000");
ca.Duration = TimeSpan.FromSeconds(3);
txtSpeakMe.BorderBrush.BeginAnimation(SolidColorBrush.ColorProperty, ca);
}
Any ideas on why it is not showing the animation as it is happening? I tried animation in XAML using MS tutorials, the same effect - it animates but it is not showing the process of animation until mouse leaves...
It may be easier to use a Trigger in the Xaml to perform this animation, Triggers have a EnterActions and ExitActions so you could use the IsMouseOver event to start/stop the animation
Example:
<Border Name="border" BorderThickness="5" Width="200" Height="30">
<TextBox Text="StackOverflow"/>
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="#0066FF" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard HandoffBehavior="SnapshotAndReplace">
<Storyboard>
<ColorAnimation Duration="0:0:3" To="#FF0000" Storyboard.TargetProperty="BorderBrush.Color" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard HandoffBehavior="SnapshotAndReplace">
<Storyboard>
<ColorAnimation Duration="0:0:3" To="#0066FF" Storyboard.TargetProperty="BorderBrush.Color" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
Not sure why TextBox border color is not changing, but you could try this:
<Border Name = "border" BorderThickness="5">
<TextBox MouseEnter="TextBox_MouseEnter" MouseLeave="TextBox_MouseLeave"/>
</Border>
Then try this code on MouseEnter and MaouseLeave:
ColorAnimation ca = new ColorAnimation();
ca.From = (Color)ColorConverter.ConvertFromString("#0066FF");
ca.To = (Color)ColorConverter.ConvertFromString("#FF0000");
ca.Duration = TimeSpan.FromSeconds(3);
Storyboard sb = new Storyboard();
sb.Children.Add(ca);
Storyboard.SetTarget(ca, border);
Storyboard.SetTargetProperty(ca, new PropertyPath("(Border.BorderBrush).(SolidColorBrush.Color)"));
sb.Begin();
I wish to attach a time delay to a mouseover event on a WPF expander I have on my form (xaml supported by VB.NET code behind). This mouseover event essentially triggers the expansion as oppose to clicking - but I'd like a short wait before the content is expanded. So far I have not managed to find anything to solve this via the wider internet.
The current xaml code to enable the trigger is:
<Style x:Key="HoverExpander" TargetType="{x:Type Expander}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsExpanded" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
This style is then applied to:
<Expander Style="{StaticResource HoverExpander}"
HorizontalAlignment="Right"
ExpandDirection="Left"
Height="Auto"
Width="Auto">
<!-- Content here -->
</Expander>
Note that I've stripped out other aesthetics (such as borders, gridrefs etc for readability).
I think there should be some way to set a delay on the MouseOver Trigger but haven't had much luck finding it. This could either be set in xaml or perhaps as an event in the code behind.
I'm working on this currently, so when I find a solution I shall post it here. Grateful for any ideas meantime. Thanks!
Use an EventTrigger on the MouseOver event and a Storyboard with a BooleanAnimationUsingKeyFrames instead. In the Timeline of the Storyboard, you could have KeyFrames, so that the animation waits for some time before it affects the properties you want to change.
This was the code I settled on - based on the ideas already given:
<Style x:Key="HoverExpander" TargetType="{x:Type Expander}">
<Style.Setters>
<Setter Property="IsExpanded" Value="False"/><!-- Initially collapsed -->
</Style.Setters>
<Style.Triggers>
<!-- Impose a short delay (500ms) before expanding control -->
<EventTrigger RoutedEvent="Expander.MouseEnter">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetProperty="IsExpanded"
Duration="0:0:0.5">
<DiscreteBooleanKeyFrame Value="True" KeyTime="100%"/><!-- I.E. after 500ms -->
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<!-- Collapse when mouse leaves control-->
<EventTrigger RoutedEvent="Expander.MouseLeave">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetProperty="IsExpanded"
Duration="0:0:0.1">
<DiscreteBooleanKeyFrame Value="False" KeyTime="0%"/><!-- I.E. Immediately -->
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
Then apply as before. This was tested and works in .NET 4.0. Other neat tricks could be applied if you do so wish, I found the following to be quite helpful in getting ideas:
Animation Overview (MSDN)
Storyboards Overview (MSDN)
What I want to achieve is that when the mouse is hovering over the main window, all the UI elements should freeze, which I think can be done by setting Window.IsEnabled to false, and after the mouse leaves the main window, everything should be back to normal.
I've tried to define a property trigger in a style targetting Window, but it doesn't work. The code is as lollow,
<Style.Triggers>
<Trigger Property="Window.IsMouseOver" Value="True">
<Setter Property="Window.IsEnabled" Value="false"/>
</Trigger>
</Style.Triggers>
In fact this kind of property trigger wouldn't work on Grid either. Can anyone make some explanations?
I also tried to explicitly use the MouseEnter and MouseLeave events on Window, and set the disable/enable logic in the handlers. This works. I wonder if it's possible to do this in XAML?
Well to be honest I don't know why your code doesn't work, I think it goes in some kind of conflict but I don't know why
Anyway you can do it in XAML using eventsetter, It's not so elegant but it works
<Window.Triggers>
<EventTrigger RoutedEvent="Window.MouseEnter">
<BeginStoryboard>
<Storyboard Name="sb">
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsEnabled" >
<BooleanKeyFrameCollection>
<DiscreteBooleanKeyFrame Value="False" KeyTime="0:0:0:1"></DiscreteBooleanKeyFrame>
</BooleanKeyFrameCollection>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
I am trying to create a simple (I think) animation effect based on a property change in my ViewModel. I would like the target to be a specific textblock in the control template of a custom control, which inherits from Window.
From the article examples I've seen, a DataTrigger is the easiest way to accomplish this. It appears that Window.Triggers doesn't support DataTriggers, which led me to try to apply the trigger in the style. The problem I am currently having is that I can't seem to target the TextBlock (or any other child control)--what happens is which the code below is that the animation is applied to the background of the whole window.
If I leave off StoryBoard.Target completely, the effect is exactly the same.
Is this the right approach with the wrong syntax, or is there an easier way to accomplish this?
<Style x:Key="MyWindowStyle" TargetType="{x:Type Window}">
<Setter Property="Template" Value="{StaticResource MyWindowTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ChangeOccurred}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard BeginTime="00:00:00" Duration="0:0:2" Storyboard.Target="{Binding RelativeSource={RelativeSource AncestorType=TextBlock}}"
Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)">
<ColorAnimation FillBehavior="Stop" From="Black" To="Red" Duration="0:0:0.5" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
Update
Should have also mentioned that I tried to name the TextBlock and reference it via StoryBoard.TargetName (as Timores suggested), and got the error "TargetName property cannot be set on a Style Setter."
EDIT: I have overseen the fact that the TextBlock is in the ControlTemplate of your custom Window/Control. I do not think that it is possible to target a control within the ControlTemplate from a Storyboard outside of this ControlTemplate. You could however define a property on your custom Window which you then databind to your ChangeOccurred property, and then add the trigger to your ControlTemplate which will now get triggered by the custom Control's property rather than the Window's ViewModel's property (of course, indirectly it is triggered by the ViewModel because ChangeOccurred is bound to the property of the custom Window which in turn triggers the animation - uh, complex sentence, hope you understand). Is this an option? Could you follow? ;-)
Maybe some code helps:
public class MyCustomWindow : Window
{
public static readonly DependencyProperty ChangeOccurred2 = DependencyProperty.Register(...);
public bool ChangeOccurred2 { ... }
// ...
}
And some XAML:
<local:MyCustomWindow ChangeOccurred2="{Binding ChangeOccurred}" ... >
<!-- Your content here... -->
</local:MyCustomWindow>
<!-- Somewhere else (whereever your ControlTemplate is defined) -->
<ControlTemplate TargetType="{x:Type local:MyCustomWindow}">
<!-- your template here -->
<ControlTemplate.Triggers>
<Trigger Property="ChangeOccurred2" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard BeginTime="00:00:00" Duration="0:0:2"
Storyboard.TargetName="txtWhatever"
Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)">
<ColorAnimation FillBehavior="Stop"
From="Black" To="Red"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Note: I named the Window's property ChangeOccurred2 because I wanted it to be distinguishable from the ViewModel's ChangeOccurred property. Of course, you should choose a better name for this property. However, I am missing the background for such a decision.
My old answer:
So, you want to animate a TextBlock which is in the content of a (custom) Window?!
Why do you want to set the style on the Window, and not on the TextBlock itself? Maybe you should try something like this (did not test this!):
<local:MyCustomWindow ... >
<!-- ... -->
<TextBlock x:Name="textBlockAnimated" ... >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ChangeOccurred}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard BeginTime="00:00:00" Duration="0:0:2"
Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)">
<ColorAnimation FillBehavior="Stop"
From="Black" To="Red"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<!-- ... -->
</local:MyCustomWindow>
The {Binding ChangeOccurred} might not be sufficient. You might have to add a DataContext to the TextBlock, or add a RelativeSource or something.
Is the TextBlock in the MyWindowTemplate ?
If so, give the TextBlock a name and use Storyboard.TargetName to reference it.
See another question in SO