I would like to play video on top of the current window. Another video is playing in the background of the current window.
I'm using MMVM and Microsoft's Microsoft.Practices.Unity in my WPF project. I have added a Canvas and in code behind using MediaPlayer, VideoDrawing, DrawingBrush to show the player Canvas and play video.
Most of the time it works perfectly but sometime it stops playing video and shows a blank screen.
Expected :
Unexpected :
UserControl
<UserControl x:Class="VideoDemo.Views.SampleView"
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:VideoDemo.Views"
mc:Ignorable="d"
>
<StackPanel Orientation="Horizontal">
<Canvas x:Name="MainCanvas" Width="540" Height="340">
<MediaElement Width="540" Height="340" Stretch="Fill">
<MediaElement.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<MediaTimeline x:Name="bgVideo" Source="BGLoop.mp4" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</MediaElement.Triggers>
</MediaElement>
<Button Content="Show Popup" Foreground="Black" Click="Button_Click" ></Button>
<!--Video Player-->
<Canvas Name="canvasPlayer" Width="540" Height="292"
Margin="0"
VerticalAlignment="Top"
>
</Canvas>
</Canvas>
</StackPanel>
Button Click
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
Canvas.SetZIndex(canvasPlayer, 99);
bool isMediaClosed = false;
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(10);
MediaPlayer mp = new MediaPlayer();
var bgVideoPath = Environment.CurrentDirectory + #"\Touchdown.mp4";
mp.Open(new Uri(bgVideoPath));
VideoDrawing vd = new VideoDrawing();
vd.Player = mp;
vd.Rect = new Rect(0, 0, 100, 100);
DrawingBrush db = new DrawingBrush(vd);
var btnBg = MainCanvas.Background;
// Affect the drawing brush as a background for all 9 buttons
//foreach (Button b in videoGrid.Children)
canvasPlayer.Background = db;
// Lecture!
mp.Play();
timer.Start();
//Timer to remove the blank screen. Otherwise whole time blank screen sticked
timer.Tick += (t, l) =>
{
timer.Stop();
if (!isMediaClosed)
{
mp.Stop();
mp.Close();
canvasPlayer.Background = btnBg;
Canvas.SetZIndex(canvasPlayer, -1);
isMediaClosed = true;
}
};
mp.MediaEnded += (k, p) =>
{
mp.Stop();
mp.Close();
canvasPlayer.Background = btnBg;
Canvas.SetZIndex(canvasPlayer, -1);
isMediaClosed = true;
};
}
catch (Exception)
{
}
}
FOR THOSE WHO CAN DOWNLOAD AND CHECK MY CODE. I have written an sample application for this and you can download it from here. I have tried to re generate this issue in this demo app but not got.
Related
I have this code. This is just an example. I want to do it with code. How to animate the Foreground property of multiple "Run" elements in a TextBlock?
<Page
x:Class="AnimationTest.MainPage"
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:local="using:AnimationTest"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid>
<TextBlock
x:Name="_textBlockElement"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="72"><Run x:Name="_run1" Text="Hel" /><Run Text="lo" />
<TextBlock.Triggers>
<EventTrigger>
<BeginStoryboard>
<Storyboard x:Name="ColorStoryboard">
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetName="_textBlockElement"
Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
To="Red"
Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Grid>
</Page>
Oke, so this took quite some sorting out, but turned out to be quite doable.
The key is to create two storyboards in code behind with the correct animations and then add those storyboards to the resources of any parent of the Run's.
Let's start of with the XAML code, which is pretty simple:
<Grid>
<TextBlock x:Name="TestBlock"
HorizontalAlignment="Center" VerticalAlignment="Center"
PointerEntered="TestBlock_PointerEntered"
PointerExited="TestBlock_PointerExited">
<Run x:Name="Run1" Text="Test1" Foreground="Blue"/>
<Run x:Name="Run2" Text="Test2" Foreground="Green"/>
<!-- ... -->
</TextBlock>
</Grid>
For simplicity I have already defined the names and foregrounds of the Run's.
Now we need to define the storyboards and animations in code behind.
I've chosen to do this in the constructor (after InitializeComponent()!). In theory you should be able to also paste this code in the Page_Loaded event.
public MainPage()
{
InitializeComponent();
SetupStoryBoards();
}
void SetupStoryBoards()
{
// Define duration and storyboards to red and original color
var duration = new Duration(TimeSpan.FromSeconds(1));
var toRedStory = new Storyboard { Duration = duration };
// completed events can be subscribed to, to register when animation is done
//toRedStory.Completed += Story_Completed;
var toOriginalStory = new Storyboard { Duration = duration };
//toOriginalStory.Completed += ToOriginalStory_Completed;
foreach (Run r in TestBlock.Inlines)
{
// Filter out any inlines that are not a named Run
if (string.IsNullOrEmpty(r.Name))
continue;
// Define the animations
var toRedAnim = new ColorAnimation
{
Duration = duration,
To = Colors.Red,
EnableDependentAnimation = true
};
var toOriginalAnim = new ColorAnimation
{
Duration = duration,
To = (r.Foreground as SolidColorBrush).Color, // Causes animation to go back to original foreground color of Run
EnableDependentAnimation = true
};
// Add animations to the storyboards and associate animations with the Run
toRedStory.Children.Add(toRedAnim);
toOriginalStory.Children.Add(toOriginalAnim);
Storyboard.SetTargetName(toRedAnim, r.Name);
Storyboard.SetTargetName(toOriginalAnim, r.Name);
Storyboard.SetTargetProperty(toRedAnim, "(Run.Foreground).(SolidColorBrush.Color)");
Storyboard.SetTargetProperty(toOriginalAnim, "(Run.Foreground).(SolidColorBrush.Color)");
}
// Add the storyboards to the resources of any parent of the Run's for easy retrieval later and to make the animations find the Run's
// I choose the resources of the textblock that contains the Run's
TestBlock.Resources.Add("toRedStory", toRedStory);
TestBlock.Resources.Add("toOriginalStory", toOriginalStory);
}
Now to execute the animations, we add the PointerEntered and PointerExited eventhandlers, and begin the correct storyboards there:
private void TextBlock_PointerEntered(object sender, PointerRoutedEventArgs e)
{
var story = TestBlock.Resources["toRedStory"] as Storyboard;
story.Begin();
}
private void TextBlock_PointerExited(object sender, PointerRoutedEventArgs e)
{
var story = TestBlock.Resources["toOriginalStory"] as Storyboard;
story.Begin();
}
You should be able to extend this wherever needed, however I have found that EnableDependentAnimation must be set to true since otherwise it won't work.
I have created an ellipse in Windows Phone 8.1 Silverlight App and UWP both
and I wanted to fill it with animating waves,
For this purpose, I am following this solution
but it is for WPF so I am unable to use some control like "Visual Brush".
I wanted to fill ellipse with wave similar to this (ignore 50% in the image) -
And here is my eliipse
<Ellipse Name="WaveEllipse" Grid.Column="1" Grid.Row="0" VerticalAlignment="Top"
Stroke="{StaticResource PhoneAccentBrush}"
StrokeThickness="4"
Width="225"
Height="225">
</Ellipse>
any alternate on the visual brush?
mainly I wanted to implement it in Windows Phone 8.1 Silverlight, but I will switch to UWP if it is not available on WP platform
Before giving you the code, have a look at this animated gif below to try to understand how this animation could be created.
Make sense, right? All we need to do is to create a shape like this, animate its offset X(endlessly) and Y(water level), and finally just clip it with an ellipse.
So first you will need to use Adobe Illustrator or similar tools to create this shape. In AI, there's a Zig Zag effect(see screenshot below) that's perfectly for this. You just need to make sure the starting point is at the same position as the ending one, so when you repeat the animation, it will feel like it's never ending.
What's currently missing in UWP is the ability to clip a UIElement with a non-rectangular shape, so here we have to export this as a png (otherwise we would export it as a svg and use Path to display it).
Also for the same reason, the clipping part requires a lot of work. Like in Jet Chopper's answer, that's tons of code to just get a surfaceBrush! Not to mention that you will also need to manually handle device lost and app lifecycle.
Thankfully, in Creators Update(i.e. 15063), there's a new API called LoadedImageSurface that creates a CompositionSurfaceBrush by an image uri with a couple of lines' code. In my code example below, you will see that I use this, which means, if you want to support older versions of Windows 10, you will need to replace it with what's in Jet's answer.
Code
The idea is to create a UserControl called WaveProgressControl which encapsulates all the animation logic and exposes a dependency property called Percent that controls the water level.
The WaveProgressControl control - XAML
<UserControl x:Class="WaveProgressControlRepo.WaveProgressControl"
Height="160"
Width="160">
<Grid x:Name="Root">
<Ellipse x:Name="ClippedImageContainer"
Fill="White"
Margin="6" />
<Ellipse x:Name="CircleBorder"
Stroke="#FF0289CD"
StrokeThickness="3" />
<TextBlock Foreground="#FF0289CD"
FontSize="36"
FontWeight="SemiBold"
TextAlignment="Right"
VerticalAlignment="Center"
Width="83"
Margin="0,0,12,0">
<Run Text="{x:Bind Percent, Mode=OneWay}" />
<Run Text="%"
FontSize="22" />
</TextBlock>
</Grid>
</UserControl>
The WaveProgressControl control - Code-behind
private readonly Compositor _compositor;
private readonly CompositionPropertySet _percentPropertySet;
public WaveProgressControl()
{
InitializeComponent();
_compositor = Window.Current.Compositor;
_percentPropertySet = _compositor.CreatePropertySet();
_percentPropertySet.InsertScalar("Value", 0.0f);
Loaded += OnLoaded;
}
public double Percent
{
get => (double)GetValue(PercentProperty);
set => SetValue(PercentProperty, value);
}
public static readonly DependencyProperty PercentProperty =
DependencyProperty.Register("Percent", typeof(double), typeof(WaveProgressControl),
new PropertyMetadata(0.0d, (s, e) =>
{
var self = (WaveProgressControl)s;
var propertySet = self._percentPropertySet;
propertySet.InsertScalar("Value", Convert.ToSingle(e.NewValue) / 100);
}));
private void OnLoaded(object sender, RoutedEventArgs e)
{
CompositionSurfaceBrush imageSurfaceBrush;
SetupClippedWaveImage();
SetupEndlessWaveAnimationOnXAxis();
SetupExpressionAnimationOnYAxisBasedOnPercentValue();
void SetupClippedWaveImage()
{
// Note LoadedImageSurface is only available in 15063 onward.
var imageSurface = LoadedImageSurface.StartLoadFromUri(new Uri(BaseUri, "/Assets/wave.png"));
imageSurfaceBrush = _compositor.CreateSurfaceBrush(imageSurface);
imageSurfaceBrush.Stretch = CompositionStretch.None;
imageSurfaceBrush.Offset = new Vector2(120, 248);
var maskBrush = _compositor.CreateMaskBrush();
var maskSurfaceBrush = ClippedImageContainer.GetAlphaMask(); // CompositionSurfaceBrush
maskBrush.Mask = maskSurfaceBrush;
maskBrush.Source = imageSurfaceBrush;
var imageVisual = _compositor.CreateSpriteVisual();
imageVisual.RelativeSizeAdjustment = Vector2.One;
ElementCompositionPreview.SetElementChildVisual(ClippedImageContainer, imageVisual);
imageVisual.Brush = maskBrush;
}
void SetupEndlessWaveAnimationOnXAxis()
{
var waveOffsetXAnimation = _compositor.CreateScalarKeyFrameAnimation();
waveOffsetXAnimation.InsertKeyFrame(1.0f, -80.0f, _compositor.CreateLinearEasingFunction());
waveOffsetXAnimation.Duration = TimeSpan.FromSeconds(1);
waveOffsetXAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
imageSurfaceBrush.StartAnimation("Offset.X", waveOffsetXAnimation);
}
void SetupExpressionAnimationOnYAxisBasedOnPercentValue()
{
var waveOffsetYExpressionAnimation = _compositor.CreateExpressionAnimation("Lerp(248.0f, 120.0f, Percent.Value)");
waveOffsetYExpressionAnimation.SetReferenceParameter("Percent", _percentPropertySet);
imageSurfaceBrush.StartAnimation("Offset.Y", waveOffsetYExpressionAnimation);
}
}
The MainPage
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<local:WaveProgressControl x:Name="WaveProgressControl" />
<Slider Grid.Row="1"
Margin="24"
Value="{x:Bind WaveProgressControl.Percent, Mode=TwoWay}" />
</Grid>
I have put everything into this sample project and below is a live demo. Enjoy! :)
Here's the UWP sample. You may adjust it as you wish:
<Canvas>
<Ellipse x:Name="Ellipse" Width="256" Height="256" Fill="DarkViolet" Stroke="DeepSkyBlue" StrokeThickness="8"/>
<Border x:Name="VisualBorder" Opacity="0.5"/>
</Canvas>
And code behind:
private async void CreateVisuals()
{
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var bitmap = await CanvasBitmap.LoadAsync(CanvasDevice.GetSharedDevice(),
new Uri("ms-appx:///Assets/Wave-PNG-Transparent-Picture.png"));
var drawingSurface =
CanvasComposition.CreateCompositionGraphicsDevice(compositor, CanvasDevice.GetSharedDevice())
.CreateDrawingSurface(bitmap.Size,
DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface))
{
ds.Clear(Colors.Transparent);
ds.DrawImage(bitmap);
}
var surfaceBrush = compositor.CreateSurfaceBrush(drawingSurface);
surfaceBrush.Stretch = CompositionStretch.None;
var maskedBrush = compositor.CreateMaskBrush();
maskedBrush.Mask = Ellipse.GetAlphaMask();
maskedBrush.Source = surfaceBrush;
var sprite = compositor.CreateSpriteVisual();
sprite.Size = new Vector2((float)Ellipse.Width, (float)Ellipse.Height);
sprite.Brush = maskedBrush;
sprite.CenterPoint = new Vector3(sprite.Size / 2, 0);
sprite.Scale = new Vector3(0.9f);
ElementCompositionPreview.SetElementChildVisual(VisualBorder, sprite);
var offsetAnimation = compositor.CreateScalarKeyFrameAnimation();
offsetAnimation.InsertKeyFrame(0, 0);
offsetAnimation.InsertKeyFrame(1, 256, compositor.CreateLinearEasingFunction());
offsetAnimation.Duration = TimeSpan.FromMilliseconds(1000);
offsetAnimation.IterationBehavior = AnimationIterationBehavior.Forever;
surfaceBrush.StartAnimation("Offset.X", offsetAnimation);
}
}
Here's how it looks like:
I have achieved this using a simple solution:
Wave2.png is a extended ( copy pasted the image and added to the end of the first image ) to make it longer.
The solution works on WP8/Store apps/UWP/Silverlight
<Border
Background="White"
VerticalAlignment="Center"
HorizontalAlignment="Center"
CornerRadius="10000"
BorderBrush="Black"
BorderThickness="5">
<Grid>
<Ellipse
x:Name="ellipse"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Height="200"
Width="200">
<Ellipse.Fill>
<ImageBrush
x:Name="WaveImage"
Stretch="None"
ImageSource="wave2.png">
<ImageBrush.Transform>
<CompositeTransform
TranslateY="200"
TranslateX="299" />
</ImageBrush.Transform>
</ImageBrush>
</Ellipse.Fill>
</Ellipse>
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="HUJ" />
</Grid>
</Border>
And here is the animation code:
<Storyboard
x:Name="AnimateWave">
<DoubleAnimationUsingKeyFrames
RepeatBehavior="Forever"
EnableDependentAnimation="True"
Storyboard.TargetProperty="(Shape.Fill).(Brush.Transform).(CompositeTransform.TranslateX)"
Storyboard.TargetName="ellipse">
<EasingDoubleKeyFrame
KeyTime="0:0:5"
Value="-299" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
I'm making a WPF application using C# and Visual Studio and I need a button to jump to a random location in the window when the mouse hovers over it. I then need the same thing to happen when you hover over it again. I also don't need an animation, just for it to jump there.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void butNo_MouseEnter(object sender, MouseEventArgs e)
{
}
}
I tried this but it didn't work and is also an animation:
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="100" Duration="0:0:2" Storyboard.TargetProperty="(Canvas.Left)" AutoReverse="False" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
Any help would be much appreciated, thanks.
Edit:
Tried this but 'Location' comes with error code CS1061 in VS.
private void butNo_MouseEnter(object sender, MouseEventArgs e)
{
Random x = new Random();
Point pt = new Point(int.Parse(x.Next(200).ToString()), int.Parse(x.Next(250).ToString()));
butNo.Location = pt;
}
Here's a solution using a Canvas and animations.
<Canvas Name="cnv">
<Button Name="btn"
Content="Click Me!"
IsTabStop="False"
Canvas.Left="0"
Canvas.Top="0"
MouseEnter="Button_MouseEnter"/>
</Canvas>
And the code-behind:
Random rnd = new Random();
private void Button_MouseEnter(object sender, MouseEventArgs e)
{
//Work out where the button is going to move to.
double newLeft = rnd.Next(Convert.ToInt32(cnv.ActualWidth - btn.ActualWidth));
double newTop = rnd.Next(Convert.ToInt32(cnv.ActualHeight - btn.ActualHeight));
//Create the animations for left and top
DoubleAnimation animLeft = new DoubleAnimation(Canvas.GetLeft(btn), newLeft, new Duration(TimeSpan.FromSeconds(1)));
DoubleAnimation animTop = new DoubleAnimation(Canvas.GetTop(btn), newTop, new Duration(TimeSpan.FromSeconds(1)));
//Set an easing function so the button will quickly move away, then slow down
//as it reaches its destination.
animLeft.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
animTop.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
//Start the animation.
btn.BeginAnimation(Canvas.LeftProperty, animLeft, HandoffBehavior.SnapshotAndReplace);
btn.BeginAnimation(Canvas.TopProperty, animTop, HandoffBehavior.SnapshotAndReplace);
}
And here is a gif of it in action.
I really don't normally like doing homework problems for people, but I'm bored at work so here you go.
You need to just use the Margin and update the Left and Top values to random numbers within the height/width of your grid so it doesn't go outside of the view.
Also, make sure to use IsTabStop="False" otherwise, you could tab to it and still click it.
So, for the simplest case using codebehind:
XAML:
<Window x:Class="mousemove.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="Grid1">
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="0,0,0,0" Name="button1" Width="75" MouseEnter="button1_MouseEnter" IsTabStop="False"/>
</Grid>
MainWindow.xaml.cs
private void button1_MouseEnter(object sender, MouseEventArgs e)
{
int maxLeft = Convert.ToInt32(Grid1.ActualWidth - button1.Width);
int maxTop = Convert.ToInt32(Grid1.ActualHeight - button1.Height);
Random rand = new Random();
button1.Margin = new Thickness(rand.Next(maxLeft), rand.Next(maxTop), 0, 0);
}
I have these two animations here, one to close a slide out grid navigation menu, and the other to set a rectangles fill to transparent as that menu closes.
I would like these to both happen at the same time. Right now the animations happen in the order they are invoked.
How can I implement this as simple and clean as possible using C# code? I am only creating this application to learn about animations and different ways layout controls.
private void _CloseSlideGrid()
{
DoubleAnimation da = new DoubleAnimation();
da.Duration = TimeSpan.FromSeconds(0.3d);
da.DecelerationRatio = 1.0d;
da.From = 500.0d;
da.To = 0.0d;
_slideGrid.BeginAnimation(Grid.WidthProperty, da);
}
private void _DisableTransparentCover()
{
BrushAnimation ba = new BrushAnimation();
ba.Duration = TimeSpan.FromSeconds(0.3d);
ba.DecelerationRatio = 1.0d;
ba.From = _GetBrush("#77000000");
ba.To = _GetBrush("#00000000");
_tranparentCover.BeginAnimation(Rectangle.FillProperty, ba);
}
An event callback for my close button invokes my two private functions that will handle the animations.
private void _NavCloseButton_Click(object sender, RoutedEventArgs e)
{
_CloseSlideGrid();
_DisableTransparentCover();
}
Here is a link to an Imgur album with a screenshot of the two states of my window, if you are intrested:
http://imgur.com/a/ZaSr1
Let me know if I can provide any more information,
Thanks.
Just add them on the same storyboard and it should be fine. I'm not sure what your BrushAnimation is but using ColorAnimation with the property path as below is working just fine.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
SizeToContent="WidthAndHeight">
<Window.Resources>
<Storyboard x:Key="CloseAnimation">
<DoubleAnimation From="500.0" To="0.0" DecelerationRatio="1.0" Duration="00:00:03"
Storyboard.TargetName="MyTextBox" Storyboard.TargetProperty="Width"/>
<ColorAnimation From="#77000000" To="#00000000" DecelerationRatio="1.0" Duration="00:00:03"
Storyboard.TargetName="MyGrid" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"/>
</Storyboard>
</Window.Resources>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox x:Name="MyTextBox" Grid.Column="0" Width="500"/>
<Grid x:Name="MyGrid" Grid.Column="1" Background="#77000000" Width="100"/>
</Grid>
<Button Content="Animate">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click" >
<BeginStoryboard Storyboard="{StaticResource CloseAnimation}"/>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
</Window>
If you REALLY want to do this in code behind and have no other way around it translates as such.
private void _CloseSlideGrid(Storyboard sb)
{
DoubleAnimation da = new DoubleAnimation();
da.Duration = TimeSpan.FromSeconds(0.3d);
da.DecelerationRatio = 1.0d;
da.From = 500.0d;
da.To = 0.0d;
Storyboard.SetTarget(da, MyTextBox);
Storyboard.SetTargetProperty(da, new PropertyPath("Width"));
sb.Children.Add(da);
}
private void _DisableTransparentCover(Storyboard sb)
{
ColorAnimation ba = new ColorAnimation();
ba.Duration = TimeSpan.FromSeconds(0.3d);
ba.DecelerationRatio = 1.0d;
ba.From = (Color)ColorConverter.ConvertFromString("#77000000");
ba.To = (Color)ColorConverter.ConvertFromString("#00000000");
Storyboard.SetTarget(ba, MyGrid);
Storyboard.SetTargetProperty(ba, new PropertyPath("(Background).(SolidColorBrush.Color)"));
sb.Children.Add(ba);
}
private void _NavCloseButton_Click(object sender, RoutedEventArgs e)
{
var sb = new Storyboard();
_CloseSlideGrid(sb);
_DisableTransparentCover(sb);
sb.Begin();
}
I'm developing a Windows Phone 8.1 app with a MapControl as the main focal point of my app. I basically want to integrate a similar experience design wise as the Nokia Here Maps App.
The bottom black Frame can be pulled upwards to reveal its content.
How am I able to do this?
EDIT
I now have:
ExtraInfo.RenderTransform = new TranslateTransform();
ExtraInfo.ManipulationDelta += OnManipulationDelta;
ExtraInfo.ManipulationMode = Windows.UI.Xaml.Input.ManipulationModes.TranslateY;
in my constructor
The eventhandler
private void OnManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
{
try
{
Storyboard myStoryboard = (Storyboard)this.Resources["TestStoryboard"];
TranslateTransform myTranslate = new TranslateTransform();
myTranslate.Y = e.Delta.Translation.Y;
ExtraInfo.RenderTransform = myTranslate;
Storyboard.SetTarget(myStoryboard.Children[0] as DoubleAnimation, ExtraInfo);
myStoryboard.Begin();
}
catch (Exception)
{
Debug.WriteLine("Animation called");
}
}
My XAML
<Grid>
<StackPanel>
<Maps:MapControl Height="{Binding ActualHeight, ElementName=pageRoot}" x:Name="Map" LandmarksVisible="False" ZoomLevel="{Binding zoomlevel, Mode=TwoWay, FallbackValue=8}" MapServiceToken="#######" TrafficFlowVisible="True">
<Image x:Name="NewCheckImage" Visibility="Collapsed" Maps:MapControl.Location="{Binding Center, ElementName=Map}" Maps:MapControl.NormalizedAnchorPoint=".5,.5"></Image>
</Maps:MapControl>
<StackPanel x:Name="ExtraInfo" Height="{Binding ActualHeight, ElementName=pageRoot}" Background="Black" Margin="0,-250,0,0" Canvas.ZIndex="1">
<StackPanel.RenderTransform>
<TranslateTransform X="0" Y="0">
</TranslateTransform>
</StackPanel.RenderTransform>
</StackPanel>
</StackPanel>
</Grid>
The storyboard
<Page.Resources>
<Storyboard x:Key="TestStoryboard">
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"
To="0">
</DoubleAnimation>
</Storyboard>
</Page.Resources>
But the panel does some jumpy unpredictable moves.
Set RenderTransform = new TranslateTransform() for your StackPanel, handle Page ManipulationDelta event and there change your (StackPanel.RenderTransform as TranslateTransform).Y value. Use Storyboard (animation on RenderTransform) to achieve effect of pulling up/down on touch release.
You should do something like this: (pseudocode)
void OnStackPanelLoaded(..)
{
StackPanel.VerticalAlingment = VerticalAlingment.Bottom;
StackPanel.RenderTransform = new TranslateTransform(0, StackPanel.ActualHeight);
// translate stackpanel out of page, be sure stackpanel has bottom alingment of grid
}
void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs args)
{
var stackPanelTransform = MyStackPanel.RenderTransform as TranslateTransform;
stackPanelTransform.Y += args.Delta.Translation.Y;
}
You should also register to ManipulationCompleted event and there run close/open animation.
void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs args)
{
// you can also add additional logic here to reverse open/close logic
// for example: if user touch translation delta is too small then instead of opening panel - close it like in Here
if (IsPanelOpened())
Resources["ClosePanelStoryboard"].BeginStoryboard();
else
Resources["OpenPanelStoryboard"].BeginStoryboard();
}
bool IsPanelOpened()
{
var translateTransform = myStackPanel.RenderTransform as TranslateTransform;
return translateTransform.Y > double.Epsilon;
}
Check DoubleAnimation.EasingFunction - to achieve same animation effect like in Here Drive (animated open/close).
Implementing good panel takes time. Initially it should have Opacity = 0, IsHitTest = false (because it can blink on page start - before RenderTransform is set) - you should also register to SizeChanged event in StackPanel to ensure that TranslateTransform is set correctly (sometimes you can get StackPanel.ActualHeight value of 0 - most likely in release build because they're faster).