How can I pause a storyboard? - wpf

This seems like it should be a no-brainer, but I can't get a WPF storyboard to pause. I call Pause and nothing happens -- it keeps right on animating.
Here's a repro case: a button that animates its width. If you click the button, it calls Pause on the storyboard. I would expect that, as soon as I click the button, its width should stop changing; instead its width keeps right on animating as if I never called Pause.
NameScope.SetNameScope(this, new NameScope());
var storyboard = new Storyboard();
var button = new Button { Content = "Pause", Name = "pause" };
this.Content = button;
RegisterName(button.Name, button);
var animation = new DoubleAnimation(0, 200, TimeSpan.FromSeconds(5));
Storyboard.SetTargetName(animation, button.Name);
Storyboard.SetTargetProperty(animation,
new PropertyPath(FrameworkElement.WidthProperty));
storyboard.Children.Add(animation);
button.Click += (sender, e) => { storyboard.Pause(this); };
storyboard.Begin(this);
From what I understand of the docs, I should call the Pause(FrameworkElement) overload with the same parameter I passed to Begin, hence the Pause(this) above. But I've also tried storyboard.Pause(), with no change in behavior. I also tried storyboard.Pause(button) just for the heck of it, again with no effect. I would have tried storyboard.Pause(storyboard) and storyboard.Pause(animation) just to exhaust the possibilities, but neither one compiles -- it wants a FrameworkElement (or FrameworkContentElement).
How do I get the storyboad to pause?

I don't know why you are using that weired SetNameScope etc. Clearing your code i could make it work:
//NameScope.SetNameScope(this, new NameScope());
var storyboard = new Storyboard();
var button = new Button { Content = "Pause", Name = "pause" };
this.Content = button;
//RegisterName(button.Name, button);
var animation = new DoubleAnimation(0, 200, TimeSpan.FromSeconds(5));
Storyboard.SetTarget(animation, button);
Storyboard.SetTargetProperty(animation,
new PropertyPath(FrameworkElement.WidthProperty));
storyboard.Children.Add(animation);
button.Click += (sender, e) => { storyboard.Pause(); };
storyboard.Begin();

Related

Transparent control not capturing mouse events

I have a window with a transparent background (not null). Inside that window, I have a user control, also with a transparent background.
The window receives mouse events, but the user control does not.
If I change the background of the user control from Transparent to #01000000, then the user control starts to receive mouse events. However, controls hosted within the user control (which are themselves visible) never receive mouse events, regardless of the user control's background.
Any ideas?
There must be something handling the event or you have some configuration issue, since it works ok for me: http://share.linqpad.net/ijx3vb.linq. (Get Linqpad free.)
var t = new TextBlock() { Text = "test" };
var uc1 = new UserControl() { Background = new SolidColorBrush(Colors.Transparent) };
uc1.MouseEnter += (s, args) => { t.Text = "UC1"; };
var uc2 = new UserControl() { Background = new SolidColorBrush(Color.FromArgb(01, 00, 00, 00)) };
uc2.MouseEnter += (s, args) => { t.Text = "UC2"; };
var g = new Grid();
g.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
g.RowDefinitions.Add(new RowDefinition());
g.RowDefinitions.Add(new RowDefinition());
g.Children.Add(t);
g.Children.Add(uc1);
g.Children.Add(uc2);
Grid.SetRow(t, 0);
Grid.SetRow(uc1, 1);
Grid.SetRow(uc2, 2);
PanelManager.DisplayWpfElement(g);

WPF: Move control into new window

I have a control that placed into a custom panel. Into view model exist a boolean variable IsStandAlone. I wish when IsStandAlone is true that this control will be in new window.
I do this on setting IsStandAlone to true:
var window = new Window();
window.Content = this;
window.Closed += (s, ea) =>
{
window.Content = null;
ViewModel.IsStandAlone = false;
}
window.Show();
It's work good when i set IsStandAlone true but when i close the window control doesn't appear in the panel.
Like this?
...
If(IsStandAlone){
var newWindow = new MyNewWindow();
newWindow.Show();
}
...

Grid Background Image Opacity Animation

Created a simple jquery-nivo-like slider using wpf and want to add an animation between slides that fades the background, changes the background image, and finally fades back in the new background image. I was trying to do the following....I get no errors, background changes, but there wasn't any animation either...what am I doing wrong?
public void SetSlider(MyItem item)
{
//Fade out
DoubleAnimation fadeOutAnimation = new DoubleAnimation(0, TimeSpan.FromSeconds(3));
fadeOutAnimation.AutoReverse = false;
grdContent.Background.BeginAnimation(Brush.OpacityProperty, fadeOutAnimation);
//set background
ImageBrush bgBrush = new ImageBrush();
bgBrush.ImageSource = new BitmapImage(new Uri(item.ImageFile.SavedDirectoryAndFile, UriKind.Absolute));
grdContent.Background = bgBrush;
//Set title
txtTitle.Text = item.Title;
//set Summary
txtSummary.Text = item.Summary;
//Fade back in
DoubleAnimation fadeInAnimation = new DoubleAnimation(1, TimeSpan.FromSeconds(3));
fadeInAnimation.AutoReverse = false;
grdContent.Background.BeginAnimation(Brush.OpacityProperty, fadeInAnimation);
}
Figured it out... I had to apply the animation to the brush that was set in the background property...not the background property itself and I had to make some timing changes. Here is my final solution:
public void SetSlider(MyItem item)
{
//Create the fade out animation.
DoubleAnimation fadeOutAnimation = new DoubleAnimation(0, TimeSpan.FromMilliseconds(500));
fadeOutAnimation.AutoReverse = false;
//wait until the first animation is complete before changing the background, or else it will appear to just "fadeIn" with now fadeout.
fadeOutAnimation.Completed += delegate(object sender, EventArgs e)
{
//once the fadeout is complete set the new back ground and fade back in.
//Create a new background brush.
ImageBrush bgBrush = new ImageBrush();
bgBrush.ImageSource = new BitmapImage(new Uri(item.ImageFile.SavedDirectoryAndFile, UriKind.Absolute));
bgBrush.Opacity = 0;
//Set the grid background to the new brush.
grdContent.Background = bgBrush;
//Set the brush...(not the background property) with the animation.
DoubleAnimation fadeInAnimation = new DoubleAnimation(1, TimeSpan.FromMilliseconds(500));
fadeInAnimation.AutoReverse = false;
bgBrush.BeginAnimation(Brush.OpacityProperty, fadeInAnimation);
};
//Fade out..before changing the background.
var currentBackground = grdContent.Background;
currentBackground.BeginAnimation(Brush.OpacityProperty, fadeOutAnimation);
//Set title
txtTitle.Text = item.Title;
//set Summary
txtSummary.Text = item.Summary;
}
A simpler approach will be using Transitional's they have a sample project of image animation.
References:
xmlns:trans="clr-namespace:Transitionals;assembly=Transitionals"
xmlns:transc="clr-namespace:Transitionals.Controls;assembly=Transitionals"
xmlns:transt="clr-namespace:Transitionals.Transitions;assembly=Transitionals"
xmlns:refl="clr-namespace:System.Reflection;assembly=mscorlib"
<transc:TransitionElement x:Name="TransitionBox" Grid.Row="1" Content="{Binding
CurrentImage}">
<transc:TransitionElement.Transition>
<transt:TranslateTransition StartPoint="1,0" EndPoint="0,0"
Duration="0:0:0.6"/>
</transc:TransitionElement.Transition>
</transc:TransitionElement>
or use SlideShow Control it has if its an automatic Transition.
<transc:Slideshow.TransitionSelector>
<trans:RandomTransitionSelector>
<trans:RandomTransitionSelector.TransitionAssemblies>
<refl:AssemblyName Name="Transitionals" />
</trans:RandomTransitionSelector.TransitionAssemblies>
</trans:RandomTransitionSelector>
</transc:Slideshow.TransitionSelector>

WPF Animating a Run element to flash

This is kind of a weird problem I am having right now. What I am trying to do is animate a Run element to essentially flash/blink. The parent is a Hyperlink which contains multiple Inlines of type Run and Image. Now I am trying to animate the Foreground color of the element but it does not seem to work.
Here is my code for a hyperlink.
CallbackHyperLink callbackLink = new CallbackHyperLink();
ToolTipService.SetShowDuration(callbackLink, 3600000);
ToolTipService.SetInitialShowDelay(callbackLink, 0);
callbackLink.Foreground = new SolidColorBrush(Colors.Magenta); // Default text color of the link
callbackLink.TextDecorations = null; // Disable the underline until mouse over
callbackLink.ToolTip = f.Tooltip; // Set the tooltip string
DoubleAnimation opacityAnim = new DoubleAnimation();
opacityAnim.From = 1.0;
opacityAnim.To = 0.0;
opacityAnim.FillBehavior = FillBehavior.Stop;
opacityAnim.Duration = TimeSpan.FromSeconds(BlinkDurationOff);
opacityAnim.AutoReverse = true;
_blinkAnimation.Children.Add(opacityAnim);
Storyboard.SetTarget(opacityAnim, callbackLink.Foreground);
Storyboard.SetTargetProperty(opacityAnim, new PropertyPath(SolidColorBrush.OpacityProperty));
_blinkAnimation.Stop();
_blinkAnimation.Begin();
So that gets put in a storyboard which get fired. However the foreground is not getting animated and I am not seeing any warnings that im trying to animate something I shouldn't. Anybody have any ideas?
Thanks
This works:
Storyboard.SetTarget(opacityAnim, callbackLink);
Storyboard.SetTargetProperty(opacityAnim, new PropertyPath(UIElement.OpacityProperty));
Edit full working example with a TextBlock stolen from here :
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
TextBlock callbackLink = new TextBlock();
callbackLink.HorizontalAlignment = HorizontalAlignment.Center;
callbackLink.VerticalAlignment = VerticalAlignment.Center;
callbackLink.Text = "Test";
this.Content = callbackLink;
NameScope.SetNameScope(this, new NameScope());
var b = new SolidColorBrush(Colors.Magenta);
callbackLink.Foreground = b;
this.RegisterName("MyAnimatedBrush", b);
DoubleAnimation opacityAnimation = new DoubleAnimation();
opacityAnimation.To = 0.0;
opacityAnimation.Duration = TimeSpan.FromSeconds(0.5);
opacityAnimation.AutoReverse = true;
opacityAnimation.RepeatBehavior = RepeatBehavior.Forever;
Storyboard.SetTargetName(opacityAnimation, "MyAnimatedBrush");
Storyboard.SetTargetProperty(
opacityAnimation, new PropertyPath(SolidColorBrush.OpacityProperty));
Storyboard mouseLeftButtonDownStoryboard = new Storyboard();
mouseLeftButtonDownStoryboard.Children.Add(opacityAnimation);
callbackLink.MouseEnter += delegate(object sender2, MouseEventArgs ee)
{
mouseLeftButtonDownStoryboard.Begin(this, true);
};
callbackLink.MouseLeave += delegate(object sender2, MouseEventArgs ee)
{
mouseLeftButtonDownStoryboard.Stop(this);
};
}
Also another way to link to the foreground opacity call without registering the name of the brush is the following.
Storyboard.SetTarget(opacityAnim, callbackLink);
Storyboard.SetTargetProperty(opacityAnim, new PropertyPath("Foreground.Opacity"));
This seems to finally work for me. Still tweaking my solution as I am doing a lot of Stop/Begin calls on the animation which I believe is not good way of doing things.

Animate Canvas.Left property

I'm trying to animate the left property of my image that is in a canvas.
When I'm doing :
image.SetValue(Canvas.LeftProperty, destX[i]);
this is working.
But when I'm doing :
Animate(image, lastValue, destX[i], 500);
with
private void Animate(Image image, double val1, double val2, double miliseconds)
{
DoubleAnimation myDoubleAnimation = new DoubleAnimation { From = val1, To = val2, Duration = new Duration(TimeSpan.FromMilliseconds(miliseconds)) };
TranslateTransform ts = new TranslateTransform();
image.RenderTransform = ts;
Storyboard.SetTarget(myDoubleAnimation, ts);
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(TranslateTransform.XProperty));
Storyboard myMovementStoryboard = new Storyboard();
myMovementStoryboard.Children.Add(myDoubleAnimation);
myMovementStoryboard.Begin();
myMovementStoryboard.Completed += (s, e) =>
{
image.SetValue(Canvas.LeftProperty, val2);
};
}
It's not working
What can be wrong in my Animate function ?
Even if animation can be bad done, the completed event should reset the good value to canvas.leftproperty.
But in my case, something gets wrong.
How would you have done the Animate function ?
Thanks in advance for any help
I did it this way, and it works fine.
DoubleAnimation myDoubleAnimation = new DoubleAnimation { From = val1, To = val2, Duration = new Duration(TimeSpan.FromMilliseconds(miliseconds)) };
//set the target of the animation
Storyboard.SetTarget(myDoubleAnimation, Image);
//set the target property of the animation. Don't forget the ( ) around canvas.left
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath("(Canvas.Left)"));
//create the storyboard
Storyboard myMovementStoryboard = new Storyboard();
//add the animation to the storyboard
myMovementStoryboard.Children.Add(myDoubleAnimation);
//begin animation
myMovementStoryboard.Begin();
You're setting Canvas.LeftProperty, but you're animating TranslateTransform.XProperty. These are very different properties, as the translate transform is applied after the layout pass. So the object is laid out in the Canvas using Canvas.Left, but then the TranslateTransform causes it to be drawn shifted from that original origin. What you should do is set the TranslateTransform.XProperty back to val2.
myMovementStoryboard.Completed += (s, e) =>
{
ts.X = val2;
};
That said, the animation should not really fail in the middle, so this extra safeguard should not be necessary.

Resources