Running multiple animations in Windows Store App - wpf

The following code is was originally part of a WPF app that I'm converting over to WinRT; however, when trying to run the animations, they appear to be mutually exclusive (that is, they both work, but only one at a time - whereas in WPF I could run them together):
private void SpinAndDisappear_Click(object sender, RoutedEventArgs e)
{
UIElement obj = (UIElement)SpinAndDisappear;
obj.RenderTransform = new CompositeTransform();
var story = new Storyboard();
var xAnim = new DoubleAnimation();
var yAnim = new DoubleAnimation();
xAnim.Duration = TimeSpan.FromSeconds(2);
yAnim.Duration = TimeSpan.FromSeconds(2);
xAnim.To = 0;
yAnim.To = 0;
story.Children.Add(xAnim);
story.Children.Add(yAnim);
Storyboard.SetTarget(xAnim, obj);
Storyboard.SetTarget(yAnim, obj);
Storyboard.SetTargetProperty(xAnim, "(UIElement.RenderTransform).(CompositeTransform.ScaleX)");
Storyboard.SetTargetProperty(yAnim, "(UIElement.RenderTransform).(CompositeTransform.ScaleY)");
story.Begin();
SpinAnimation(); // If commented out, the button changes size,
// and if not, it spins, but not both
}
void SpinAnimation()
{
UIElement obj = (UIElement)SpinAndDisappear;
obj.RenderTransform = new RotateTransform();
var storySpin = new Storyboard();
var spinAnim = new DoubleAnimation();
spinAnim.Duration = TimeSpan.FromSeconds(2);
spinAnim.From = 0;
spinAnim.To = 360;
storySpin.Children.Add(spinAnim);
Storyboard.SetTarget(spinAnim, obj);
Storyboard.SetTargetProperty(spinAnim, "(UIElement.RenderTransform).(RotateTranform.Angle)");
storySpin.Begin();
}
So my question is: how to do both simultaneously in WinRT?

Only one Storyboard can run on a single element in WinRT/XAML. If you need to run two of them independently from each other - the easiest way to do it is to have two elements and target separate elements. In your case you could have a parent Grid with a ScaleTransform and a child control with a RotateTransform. Then you would call Storyboard.SetTarget() to target the separate transforms in separate storyboards and everything should just work.

Related

Save Controls.Image to PDF with more than 1 Control.Image

I'm here for a solution to a little unresolved problem. Maybe I haven't searched for the right things as I haven't found a solution and I hope you will be able to help.
So I have a WPF application where I load an image, here I have no problems. Next I have to add some points by clicking, so i have this function:
private void ClickMouse(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(this);
schema.PointFromScreen(p);
var myImage3 = new Image();
var bi3 = new BitmapImage();
bi3.BeginInit();
bi3.UriSource = new Uri(_clickImagePath, UriKind.Relative);
bi3.EndInit();
myImage3.Stretch = Stretch.Fill;
myImage3.Source = bi3;
myImage3.MinWidth = 30;
myImage3.MinHeight = 30;
myImage3.Width = 30;
myImage3.Height = 30;
myImage3.Name = _pointName;
var oMargin = new Thickness(p.X, p.Y, 0, 0);
myImage3.Margin = oMargin;
mainCanva.Children.Add(myImage3);
_listImg.Add(myImage3);
PointList.Items.Add(_pointName);
}
The problem is not here but I need a context.
Now on to the main problem. I have to save the final Image to make a PDF with. I use a piece of sample code I found here (http://stackoverflow.com/questions/1824989/how-to-store-system-windows-controls-image-to-local-disk) to convert to a jpg file using ITextsharp. The only thing I have on the PDF is the first picture, so I admitted that it probably take only the first image and not the other created images on it but I really don't know how to fix it. Does some fonction exist to make a kind of screenshot of the image zone? or maybe to pay attention to all image in the zone of the principal Control.Image ?
Thank you for your help.
You should use the following code to render your Canvas as an image :
var rect = new Rect(canvas.RenderSize);
var rtb = new RenderTargetBitmap((int)rect.Right, (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default);
rtb.Render(canvas);
//encode as PNG
varpngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));
//save to memory stream
using(var ms = new System.IO.MemoryStream())
{
pngEncoder.Save(ms);
System.IO.File.WriteAllBytes("logo.png", ms.ToArray());
}
(Source : Write WPF output to image file )

WPF TranslateTransform Error

I have a StackPanel that I am sliding left and right to simulate moving pages using TranslateTransform.
If I call the slide method once it works well. If I call my slide method twice in quick succession (in code), the second transform has the wrong start position and ends up in the wrong place.
How do I get my second translate to "refresh" its starting position?
Here is the StackPanel
<StackPanel
x:Name="MainPanel"
Orientation="Horizontal">
<StackPanel.RenderTransform>
<TranslateTransform
x:Name="MainPanelTransform"
/>
</StackPanel.RenderTransform>
</StackPanel>
Here is the slide code:
private void SlidePage(int pagesToMove)
{
Storyboard sb = SlideEffect(MainPanel, (-PageWidth * pagesToMove));
sb.Completed += SlideCompleted;
sb.Begin();
}
private Storyboard SlideEffect(UIElement controlToAnimate, double positionToMove)
{
//Get position of stackpanel
var gt = controlToAnimate.TransformToVisual(MainGrid);
var p = gt.Transform(new Point(0, 0));
//add new storyboard and animation
var sb = new Storyboard();
var da = new DoubleAnimation { To = p.X + positionToMove };
Storyboard.SetTarget(da, controlToAnimate);
Storyboard.SetTargetProperty(da, new PropertyPath("RenderTransform.(TranslateTransform.X)"));
//Storyboard.SetTargetProperty(da, new PropertyPath("RenderTransform.Children[0].X"));
var ee = new ExponentialEase { Exponent = 6.0, EasingMode = EasingMode.EaseOut };
da.EasingFunction = ee;
sb.Children.Add(da);
return sb;
}
The offending line of code is this:
var p = gt.Transform(new Point(0, 0));
The second time I call the SlideEffect method it has the same value as the first time. It seems like the animations are getting buffered and run together. Is there any way to stop the buffering?
Did you try to change a FillBehavior property of Storyboard?
UPDATE:
I have a bug in VS, so I couldn't reproduce your situation. But I may recommend you:
Try to disable the EasingFunction. Maybe Storyboard.Completed fires before the Storyboard actually completed;
Are you sure, that transform changes actual coordinates? I think it is the solution, but not sure.
In the Storyboard.Completed you could manually update transform coordinates:
MainPanelTransform.BeginAnimation(TranslateTransform.XProperty, null);
MainPanelTransform.X = -100;

Bing map silverlight binding for moving target

I want to animate a "car" dot on a Bing map. I can easily draw multiple dots as the item travels around, but I want to have a single dot move around per car.
XAML
<m:Map Name="myMap" Grid.Row="2" MouseClick="myMap_MouseClick" UseInertia="True">
<m:MapLayer x:Name="carLayer" />
</m:Map>
Some code:
private void AddCarDot(double latitude, double longitude)
{
Ellipse point = new Ellipse();
point.Width = 15;
point.Height = 15;
point.Fill = new SolidColorBrush(Colors.Blue);
point.Opacity = 0.65;
Location location = new Location(latitude, longitude);
MapLayer.SetPosition(point, location);
MapLayer.SetPositionOrigin(point, PositionOrigin.Center);
carLayer.Children.Add(point);
}
private void cmbCar_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(cmbCar.SelectedItem != null)
{
Binding binding = new Binding("CarLocation");
binding.Source = cmbCar.SelectedItem;
binding.Mode = BindingMode.OneWay;
carLayer.SetBinding(MapLayer.PositionProperty, binding);
}
}
The CarLocation is a property on the Car object of type Location.
However that does not work and I'm not quite sure how to get the "car" to move around the map. Can someone point me in the right direction?
Well you're question kind gets cloudly when a mysterious "taxiLayer" appears positively gets muddy when you want set a binding on it instead of the "point" (which I guess represents a car).
What needs to happen is you are using the MapLayer.Position dependency property as an attached property. When the UIElement to which this is attached is a child of a MapLayer map layer knows how to layout it.
So the question is how would assign a binding to this property so that when the value of the bound object changes the position is updated. I'm going to make an assumption the Elipse created in the earlier part of the code is available as field I'll call car. Then the code might look something like this:-
private Elipse AddCarDot(object source)
{
Ellipse point = new Ellipse();
point.Width = 15;
point.Height = 15;
point.Fill = new SolidColorBrush(Colors.Blue);
point.Opacity = 0.65;
MapLayer.SetPositionOrigin(point, PositionOrigin.Center);
point.SetBinding(MapLayer.PositionProperty, new Binding("CarLocation") {Source = source});
carLayer.Children.Add(point);
}
private void cmbCar_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(cmbCar.SelectedItem != null)
{
AddCarDot(cmbCar);
}
}
Now assuming you object that has a CarLocation property implement INotifyPropertyChanged so the binding can be alerted when CarLocation changes the dot will move appropriately.

wp7, silverlight, Why event fires twice?

In this case when user click some UIElement I want this element yo be surrounded by dashed border. If there is some other object surrounded then this code removes it first.
Everything is fine but "private void activateElem" fires twice and I have no idea why. Maybe somebody can help, I really have no more ideas.
Anybody knows some ideas to debug issues like this? Maybe there is some way to print out all events queue. There is silverlight spy but I think it doesn't work for windows phone 7.
My code:
public class ManipulationEngine
{
private Canvas sheet;
private static FrameworkElement current_active_element;
public ManipulationEngine(Canvas sheet)
{
this.sheet = sheet;
foreach (FrameworkElement elem in sheet.Children)
{
elem.MouseLeftButtonUp += new MouseButtonEventHandler(activateElem);
}
}
private void activateElem(object sender, MouseButtonEventArgs e)
{
FrameworkElement elem = sender as FrameworkElement;
if (current_active_element != null)
{
desactivateElem();
}
Grid grid = new Grid();
Rectangle recentagle = new Rectangle();
grid.SetValue(Canvas.TopProperty, (double)elem.GetValue(Canvas.TopProperty) - 10);
grid.SetValue(Canvas.LeftProperty, (double)elem.GetValue(Canvas.LeftProperty) - 10);
DoubleCollection stroke = new DoubleCollection();
stroke.Add(4);
stroke.Add(2);
recentagle.StrokeDashArray = stroke;
grid.Children.Add(recentagle);
sheet.Children.Remove(elem);
elem.Margin = new Thickness(10);
grid.Children.Add(elem);
sheet.Children.Add(grid);
current_active_element = elem;
}
private void desactivateElem()
{
if (current_active_element != null)
{
Grid grid = VisualTreeHelper.GetParent(current_active_element) as Grid;
grid.Children.Remove(current_active_element);
sheet.Children.Remove(grid);
current_active_element.SetValue(Canvas.TopProperty, (double)grid.GetValue(Canvas.TopProperty) + 10);
current_active_element.SetValue(Canvas.LeftProperty, (double)grid.GetValue(Canvas.LeftProperty) + 10);
current_active_element.Margin = new Thickness(0);
sheet.Children.Add(current_active_element);
current_active_element = null;
}
}
I'd really advise looking into the Parts and States model. You may be able to do this with a button, or perhaps a radio button.
Usually if you're coding changes to the visual tree, you're not doing it right.
Karen Corby dealt with this very clearly at MIX08, take a look!
http://archive.visitmix.com/blogs/2008Sessions/T20/
Luke

Performing a Flip animation completely through code WPF

I am try to add a flip animation to a user control I built. The user control is simple it has a 87x87 image front and back and some properties. It is suppose to represent a tile in a game I am working on for fun. I am trying to animate a flipping affect of the user picking the tile from the deck. I feel I need to do this through code instead of xaml for two reasons: 1. There is another transform after the tile is flip to rotate the tile (currently working) 2. After the tile is flipped I want to unhook the event.
The issue that I am getting is only the last animation runs after the method has exited.
I think I need a Storyboard but all the examples I looked at confused me in two ways:
How do I change the image mid story board, and what do I set the targetProperty to be
I have been working off these two blogs.
http://www.codeguru.com/csharp/csharp/cs_misc/userinterface/article.php/c12221
http://blogs.msdn.com/tess/archive/2009/03/16/silverlight-wpf-flipimage-animation.aspx
public void FlipFront()
{
DoubleAnimation flipfront = new DoubleAnimation(0, 90, new Duration(new TimeSpan(0, 0, 1)));
SkewTransform skew = new SkewTransform();
this.RenderTransform = skew;
skew.BeginAnimation(SkewTransform.AngleYProperty, flipfront);
}
public void FlipBack()
{
ImageSourceConverter source = new ImageSourceConverter();
this.ImageFace.Source = new BitmapImage(new Uri("Back.jpg", UriKind.Relative));
DoubleAnimation flipfront = new DoubleAnimation(90, 0, new Duration(new TimeSpan(0, 0, 1)));
SkewTransform skew = new SkewTransform();
this.RenderTransform = skew;
skew.BeginAnimation(SkewTransform.AngleYProperty, flipfront);
}
public void Flip()
{
FlipFront();
FlipBack();
}
I broke flip into two separate methods because I though it would help fix the issue I am experiencing.
Wow, this hasn't been updated in a loong time...just in case anybody's tracking this one:
The problem is you're not waiting for the "flip front" animation to complete before immediately starting the "flip back" - now since you're basically force-jumping the Y angle animation immediately to 90 degrees, that's why it looks like it's not firing properly.
There are a LOT of ways you can work around this - the first thing that jumps to mind is that the DoubleAnimations have a method on them called CreateClock, which will return you back an AnimationClock object. That object has a Completed event on it, which will tell you when that animation is "done". Attach a handler (remember you'll want to detach it lest you leak memory), and call your "start flipping to back" method there. I've thrown something very inefficient together, but it'll show the principle:
public AnimationClock StartFlipFrontAnimation()
{
this.ImageFace.Source = _frontFace;
DoubleAnimation flipfront = new DoubleAnimation(0, 90, new Duration(new TimeSpan(0, 0, 3)));
SkewTransform skew = new SkewTransform();
this.RenderTransform = skew;
skew.BeginAnimation(SkewTransform.AngleYProperty, flipfront);
return flipfront.CreateClock();
}
public AnimationClock StartFlipBackAnimation()
{
this.ImageFace.Source = _backFace;
DoubleAnimation flipfront = new DoubleAnimation(90, 0, new Duration(new TimeSpan(0, 0, 3)));
SkewTransform skew = new SkewTransform();
this.RenderTransform = skew;
skew.BeginAnimation(SkewTransform.AngleYProperty, flipfront);
return flipfront.CreateClock();
}
public void BeginFlip()
{
var frontClk = StartFlipFrontAnimation();
frontClk.Completed += FrontFlipDone;
}
private void FrontFlipDone(object sender, EventArgs args)
{
var clk = sender as AnimationClock;
if(clk != null)
{
clk.Completed -= FrontFlipDone;
}
var backClk = StartFlipBackAnimation();
}

Resources