wpf dynamic change image source using timer - wpf

In WPF, I have 2 images, and I need to create a blinking effect (not using opacity).
Assume that I have a.png and b.png, first step showing a.png, after 0.5 seconds, it will show b.png, then after 0.5 seconds, it will show a.png, and repeat non-stop.
I've go through the forum, but I still have no luck to get example in vb, please help.

You may use an appropriate animation without any code behind:
<Window.Resources>
<BitmapImage x:Key="Image1" UriSource="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg"/>
<BitmapImage x:Key="Image2" UriSource="C:\Users\Public\Pictures\Sample Pictures\Jellyfish.jpg"/>
</Window.Resources>
...
<Image x:Name="image" Source="{StaticResource Image1}">
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source"
Duration="0:0:1"
RepeatBehavior="Forever">
<DiscreteObjectKeyFrame Value="{StaticResource Image2}"
KeyTime="0:0:0.5"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
Perhaps replace the Loaded event by one that better suits your needs.
If you really want to do it in code behind, you may create a DispatcherTimer with an Interval set to half a second, and in the timer's Tick event handler alternately set the image's Source property to one of the two images.

I'm not fit in vb.net, but in c# you can do with something like
public ImageSource GetImageSourceFromImage(Bitmap pngFile)
{
MemoryStream imageStream = new MemoryStream();
pngFile.Save(imageStream, ImageFormat.Png);
imageStream.Seek(0, SeekOrigin.Begin);
return BitmapFrame.Create(imageStream);
}
This function gives you an imagesource which you can just assign to your image-object.

Related

Moving a page across screen in wpf

I am new to WPF and just starting to get used to it,
I want to move a page across the screen when I load it. The Code I using for that currently is :
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="1920,0,0,0" />
<SplineThicknessKeyFrame KeyTime="00:00:02" Value="0,0,0,0" />
</ThicknessAnimationUsingKeyFrames>
<DoubleAnimation
Storyboard.TargetName="SummaryPageName"
Storyboard.TargetProperty="Opacity"
From="0" To="1" Duration="0:0:2"
AutoReverse="False">
</DoubleAnimation>
</Storyboard>
While this works fine for me, what I want is to not use hard values(1920) in value field of
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="1920,0,0,0" />
Is there anyway to do that without specifying this value, so that it will work with other resolutions as well.
Thank you
Modify the KeyFrame value with code behind.
You should assign resource name to the storyboard resource to be found by code behind.
[XAML]
<Storyboard x:Key="myStoryboard">
Get the Storyboard object instance by referring x:Key.
[C#]
private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
Storyboard s = this.Resources["myStoryboard"] as Storyboard;
SplineThicknessKeyFrame k = (s.Children[0] as ThicknessAnimationUsingKeyFrames).KeyFrames[0] as SplineThicknessKeyFrame;
k.Value = new Thickness(e.NewSize.Width,0,0,0);
}
Also you may use data binding to change keyframe value. If you need to change a lot of keyframe resources, you should use data binding. Otherwise changing value manually is easy to prepare.

WPF "inherit" storyboard

I have a Storyboard defined in a Resource-XAML (Opacity and Rendertransform). Now I'd like to use it on my different Usercontrols. Since this is a Fade-in animation, it's crucial that the logic of the Usercontrol starts after the animation ends.
So I know about the "Completed" event of a storyboard but I can't see, how to apply here, since I needed to define the Eventhandler on the UserControl consuming the animation. (There are several Usercontrols each with their own actions to perform after being loaded...)
The Styles have a Property called "BasedOn", here I can define the parent... Is there something similar at the Storyboard object too, or do I have to redesign my code?
Anyway if there is a better way for using Standard animations across the project than via Resourcedictionary, please advise me.
Thanks in advance,
Daniel
edit:
here there part of the resdic.
<Storyboard x:Key="ShowAndGrow">
<DoubleAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="RenderTransform.ScaleX"
To="1" />
<DoubleAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="RenderTransform.ScaleY"
To="1" />
<DoubleAnimation Duration="0:0:0.1"
Storyboard.TargetProperty="Opacity"
To="1" />
</Storyboard>
I apply it in a Usercontrol
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource ShowAndGrow}">
</BeginStoryboard>
</EventTrigger>
</UserControl.Triggers>
an here I needed to add the completed Event somehow....
You can access a Storyboard from a Resources collection using the Resources property:
Storyboard storyboard = this.Resources["YourStoryboard"] as Storyboard;
However, you really need to get access to the DoubleAnimation elements, so you'll need to name them too. You'd then be able to reassign the target property like this:
Storyboard.SetTarget(YourDoubleAnimation, YourUiControl);
Storyboard.SetTargetProperty(YourDoubleAnimation,
new PropertyPath(Control.OpacityProperty));
You can find further examples in the Working with Animations Programmatically page on MSDN (ignore the fact that it is for Silverlight as it will work just the same in WPF).
So I followed Core-One's and Sheridan's suggestions and added the Storyboard in Codebehind using findresource. I just wonder, if the "correct" way were to define as much as possible in XAML, there is no way to adapt the templated animations...
Thanks guys to all of you!
BR,
Daniel
Private Sub UserControl_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Dim sb As Storyboard = FindResource("ShowAndGrow")
AddHandler sb.Completed, AddressOf StartAction
sb.Begin(Me)
End Sub

Binding to a DoubleAnimation's duration throws TargetInvocationException

I have a WPF project using CM. I have a progress bar that I would like to animate smoothly. I have a storyboard containing a DoubleAnimation. The problem is that when I try to bind the Duration of the DoubleAnimation to a property on my view model, I get a TargetInvocationException on running the program.
The XAML for the progress bar looks like this:
<ProgressBar Name="ProgressBar" Width="400" Height="18">
<ProgressBar.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMeasuring}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.Target="{Binding TemplatedParent}"
Storyboard.TargetProperty="Value"
From="0"
To="100"
Duration="{Binding MeasurementDuration}"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
While the property in my view model looks like this:
private Duration measurementDuration = new Duration(TimeSpan.FromSeconds(1));
public Duration MeasurementDuration
{
get { return measurementDuration; }
private set
{
measurementDuration = value;
NotifyOfPropertyChange(() => MeasurementDuration);
}
}
I feel that the answer is staring straight at me, but I simply cannot find it. Thanks in advance for any help.
as far as i know, a binding to an animation in this implementation way as yours throws always an error.
In the case to change properties of an Timeline-Object while it is animated, you have to use the methods <StoryboardName>.Begin() to create a new clock for the Storyboard and <StoryboardName>.Seek() to jump to the reached duration.
Before you call the <name>.Begin() method, you change your desired properties and it should work.
Their exists a example in the msdn:
http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=wpfsamples&DownloadId=7734
In fact, that in the msdn example "only" the KeyFrames-objects of a an TimeLine-Object will be changed, you have to call the Storyboard.Stop() method before you change the Duration-property.
Try it and maybe it helps :)
Kind regards
Sb

30 line WPF Application Leaking Memory

I have a simple WPF application consisting of a Window with an orange rectangle and a continuous animation which changes a blur radius which is applied to the rectangle. This application is currently soak testing on two computers in order to diagnose a memory leak related to WPF in a larger program.
On the first computer, the memory usage is consistently maintaining an average which oscillates slightly at the same frequency as the animation duration. The test program has been running reliably for over a week without leaking memory. This computer is running windows 7 32-bit.
On the second computer, the memory usage is showing the same cyclic behaviour, however ~ every 90 seconds the memory usage is increasing by around 100kb. This extra increase is never reclaimed for as long as the application is running. I have previously run this program until the entire system memory is consumed by this one application! An animated glow on a rectangle consuming 4gb of ram! This computer is running windows 7 embedded 32-bit.
There is a significant hardware difference between the two platforms, however both systems are running the latest drivers available for their respective hardware.
The same compiled exe is on both computers running without debuggers attached. The XAML code for the application is included below:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfAnimation.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Window.Resources>
<Storyboard x:Key="Flash" AutoReverse="True" RepeatBehavior="Forever" FillBehavior="Stop">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Effect).(BlurEffect.Radius)" Storyboard.TargetName="rectangle">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="15">
<EasingDoubleKeyFrame.EasingFunction>
<ElasticEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Flash}"/>
</EventTrigger>
</Window.Triggers>
<Grid x:Name="LayoutRoot">
<Rectangle x:Name="rectangle" Fill="#FFFFA400" Margin="113,93,125,101" Stroke="Red" RadiusX="10" RadiusY="10" StrokeThickness="5">
<Rectangle.Effect>
<BlurEffect KernelType="Box" Radius="0"/>
</Rectangle.Effect>
</Rectangle>
</Grid>
</Window>
This code was built against .net Framework 4.0. There is no C# code behind this XAML.
Does anyone have any possible explanation as to why a program this simple is leaking memory?
Enabling software rendering has fixed the leak. In each Window_Loaded event I'm now enabling software rendering using the following code:
public static void EnableSoftwareRendering(Visual visual)
{
try
{
HwndSource source = PresentationSource.FromVisual(visual) as HwndSource;
HwndTarget target = source.CompositionTarget;
target.RenderMode = RenderMode.SoftwareOnly;
}
catch
{ }
}
It is an Event handlers leak.
One of your StoryBoard handler subscribes to FrameworkElement.Loaded and will be retained to the end.
I tried to remove BeginStoryBoard like this:
<EventTrigger RoutedEvent="UserControl.Unloaded" SourceName="CellControl">
<RemoveStoryboard BeginStoryboardName="MouseEnterStoryBoard"/>
</EventTrigger>
But it does not work. So I have no idea how to fix it till now.
The following is the trace of the handler from dotMemory.
System.Windows.Media.Animation.BeginStoryboard._inheritanceContext ->
System.Windows.EventTrigger._routedEventHandler ->
System.Windows.RoutedEventHandler._target ->
System.Windows.EventTrigger+EventTriggerSourceListener

What is simplest way to repeat a video in a MediaElement

I have a MediaElement where the source is bound to some data
<MediaElement Source='{Binding Something}' />
What is the simplest way to have the video repeat? Ideally, MediaElement would have a repeat behavior property.
<MediaElement RepeatBehavior='Forever' ... />
But I can't find such a property.
You need to add a Storyboard to the MediaElement. See the example below:
<MediaElement Name="myMediaElement" >
<MediaElement.Triggers>
<EventTrigger RoutedEvent="MediaElement.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<!-- The MediaTimeline has a RepeatBehavior="Forever" which makes the media play
over and over indefinitely.-->
<MediaTimeline Source="media\tada.wav" Storyboard.TargetName="myMediaElement"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</MediaElement.Triggers>
</MediaElement>
I made it work by setting the UnloadedBehavior to MediaState.Manual and the following code:
private void mediaElement_OnMediaEnded(object sender, RoutedEventArgs e)
{
mediaElement.Position = new TimeSpan(0,0,1);
mediaElement.Play();
}
Setting the position to Zero didnt work...
I know it's a little late, but I couldn't get to work the example from MSDN. So after research I've found this project: WPF Media Kit, just click at the Browse link in the Latest Version at the right side of the screen. You'll enter the code of the sample application. I liked this library because a loop was as simple as:
MediaUriElement MyPlayer.Loop = True;
or
<DirectShowControls:MediaUriElement x:Name="MyPlayer" Loop="True" />
Hope this helps someone else.
Regards!
Adding mediaElement.Position = new TimeSpan(0,0,1) to the media player method doesn't (before playing the media) have any effect rather as suggested by MasterMastic and Guido Zanon. I created MediaElement event for MediaEnded with the given content and it worked.

Resources