How do I get an animated gif to work in WPF?
Solution 1:
I couldn't get the most popular answer to this question (above by Dario) to work properly. The result was weird, choppy animation with weird artifacts. Best solution I have found so far: https://github.com/XamlAnimatedGif/WpfAnimatedGif
You can install it with NuGet
PM> Install-Package WpfAnimatedGif
and to use it, at a new namespace to the Window where you want to add the gif image and use it as below
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gif="http://wpfanimatedgif.codeplex.com" <!-- THIS NAMESPACE -->
Title="MainWindow" Height="350" Width="525">
<Grid>
<!-- EXAMPLE USAGE BELOW -->
<Image gif:ImageBehavior.AnimatedSource="Images/animated.gif" />
The package is really neat, you can set some attributes like below
<Image gif:ImageBehavior.RepeatBehavior="3x"
gif:ImageBehavior.AnimatedSource="Images/animated.gif" />
and you can use it in your code as well:
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(fileName);
image.EndInit();
ImageBehavior.SetAnimatedSource(img, image);
EDIT: Silverlight support
As per josh2112's comment if you want to add animated GIF support to your Silverlight project then use github.com/XamlAnimatedGif/XamlAnimatedGif
Solution 2:
I post a solution extending the image control and using the Gif Decoder. The gif decoder has a frames property. I animate the FrameIndex
property. The event ChangingFrameIndex
changes the source property to the frame corresponding to the FrameIndex
(that is in the decoder). I guess that the gif has 10 frames per second.
class GifImage : Image
{
private bool _isInitialized;
private GifBitmapDecoder _gifDecoder;
private Int32Animation _animation;
public int FrameIndex
{
get { return (int)GetValue(FrameIndexProperty); }
set { SetValue(FrameIndexProperty, value); }
}
private void Initialize()
{
_gifDecoder = new GifBitmapDecoder(new Uri("pack://application:,,," + this.GifSource), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
_animation = new Int32Animation(0, _gifDecoder.Frames.Count - 1, new Duration(new TimeSpan(0, 0, 0, _gifDecoder.Frames.Count / 10, (int)((_gifDecoder.Frames.Count / 10.0 - _gifDecoder.Frames.Count / 10) * 1000))));
_animation.RepeatBehavior = RepeatBehavior.Forever;
this.Source = _gifDecoder.Frames[0];
_isInitialized = true;
}
static GifImage()
{
VisibilityProperty.OverrideMetadata(typeof (GifImage),
new FrameworkPropertyMetadata(VisibilityPropertyChanged));
}
private static void VisibilityPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if ((Visibility)e.NewValue == Visibility.Visible)
{
((GifImage)sender).StartAnimation();
}
else
{
((GifImage)sender).StopAnimation();
}
}
public static readonly DependencyProperty FrameIndexProperty =
DependencyProperty.Register("FrameIndex", typeof(int), typeof(GifImage), new UIPropertyMetadata(0, new PropertyChangedCallback(ChangingFrameIndex)));
static void ChangingFrameIndex(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
var gifImage = obj as GifImage;
gifImage.Source = gifImage._gifDecoder.Frames[(int)ev.NewValue];
}
/// <summary>
/// Defines whether the animation starts on it's own
/// </summary>
public bool AutoStart
{
get { return (bool)GetValue(AutoStartProperty); }
set { SetValue(AutoStartProperty, value); }
}
public static readonly DependencyProperty AutoStartProperty =
DependencyProperty.Register("AutoStart", typeof(bool), typeof(GifImage), new UIPropertyMetadata(false, AutoStartPropertyChanged));
private static void AutoStartPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
(sender as GifImage).StartAnimation();
}
public string GifSource
{
get { return (string)GetValue(GifSourceProperty); }
set { SetValue(GifSourceProperty, value); }
}
public static readonly DependencyProperty GifSourceProperty =
DependencyProperty.Register("GifSource", typeof(string), typeof(GifImage), new UIPropertyMetadata(string.Empty, GifSourcePropertyChanged));
private static void GifSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
(sender as GifImage).Initialize();
}
/// <summary>
/// Starts the animation
/// </summary>
public void StartAnimation()
{
if (!_isInitialized)
this.Initialize();
BeginAnimation(FrameIndexProperty, _animation);
}
/// <summary>
/// Stops the animation
/// </summary>
public void StopAnimation()
{
BeginAnimation(FrameIndexProperty, null);
}
}
Usage example (XAML):
<controls:GifImage x:Name="gifImage" Stretch="None" GifSource="/SomeImage.gif" AutoStart="True" />
Solution 3:
How about this tiny app: Code behind:
public MainWindow()
{
InitializeComponent();
Files = Directory.GetFiles(@"I:\images");
this.DataContext= this;
}
public string[] Files
{get;set;}
XAML:
<Window x:Class="PicViewer.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>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="175" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox x:Name="lst" ItemsSource="{Binding Path=Files}"/>
<MediaElement Grid.Column="1" LoadedBehavior="Play" Source="{Binding ElementName=lst, Path=SelectedItem}" Stretch="None"/>
</Grid>
</Window>