Como obtenho um gif animado para trabalhar no WPF?

Que tipo de controle devo usar – Image , MediaElement , etc.?

Eu não consegui obter a resposta mais popular para esta pergunta (acima por Dario) para funcionar corretamente. O resultado foi uma animação estranha e agitada com artefatos estranhos. A melhor solução que encontrei até agora: https://github.com/XamlAnimatedGif/WpfAnimatedGif

Você pode instalá-lo com o NuGet

PM> Install-Package WpfAnimatedGif

e usá-lo, em um novo namespace para a janela onde você deseja adicionar a imagem gif e usá-lo como abaixo

  Title="MainWindow" Height="350" Width="525">    

O pacote é realmente puro, você pode definir alguns atributos como abaixo

   

e você pode usá-lo em seu código também:

 var image = new BitmapImage(); image.BeginInit(); image.UriSource = new Uri(fileName); image.EndInit(); ImageBehavior.SetAnimatedSource(img, image); 

Eu publico uma solução estendendo o controle de imagem e usando o Gif Decoder. O decodificador de gif tem uma propriedade de frameworks. Eu FrameIndex propriedade FrameIndex . O evento ChangingFrameIndex altera a propriedade de origem para o quadro correspondente ao FrameIndex (que está no decodificador). Eu acho que o gif tem 10 frameworks por segundo.

 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]; } ///  /// Defines whether the animation starts on it's own ///  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(); } ///  /// Starts the animation ///  public void StartAnimation() { if (!_isInitialized) this.Initialize(); BeginAnimation(FrameIndexProperty, _animation); } ///  /// Stops the animation ///  public void StopAnimation() { BeginAnimation(FrameIndexProperty, null); } } 

Exemplo de uso (XAML):

  

Eu também fiz uma pesquisa e encontrei várias soluções diferentes em apenas um thread nos antigos fóruns do MSDN. (link não funciona mais então eu removi)

O mais simples de executar parece ser usar um PictureBox WinForms PictureBox , e foi assim (mudou algumas coisas do thread, a maioria do mesmo).

Adicione uma referência a System.Windows.Forms , WindowsFormsIntegration e System.Drawing ao seu projeto primeiro.

         

Em seguida, no manipulador Window_Loaded , você deve definir a propriedade pictureBoxLoading.ImageLocation como o caminho do arquivo de imagem que deseja mostrar.

 private void Window_Loaded(object sender, RoutedEventArgs e) { pictureBoxLoading.ImageLocation = "../Images/mygif.gif"; } 

O controle MediaElement foi mencionado nesse segmento, mas também é mencionado que é um controle bastante pesado, portanto, havia várias alternativas, incluindo pelo menos dois controles baseados em homebrew baseado no controle Image , portanto, este é o mais simples.

Como sobre este pequeno aplicativo: Código por trás:

 public MainWindow() { InitializeComponent(); Files = Directory.GetFiles(@"I:\images"); this.DataContext= this; } public string[] Files {get;set;} 

XAML:

           

É muito simples se você usar :

  

Aqui está a minha versão do controle de imagem animada. Você pode usar a propriedade padrão Source para especificar a origem da imagem. Eu melhorei ainda mais. Eu sou um russo, o projeto é russo, então os comentários também estão em russo. Mas de qualquer forma você deve ser capaz de entender tudo sem comentários. 🙂

 ///  /// Control the "Images", which supports animated GIF. ///  public class AnimatedImage : Image { #region Public properties ///  /// Gets / sets the number of the current frame. ///  public int FrameIndex { get { return (int) GetValue(FrameIndexProperty); } set { SetValue(FrameIndexProperty, value); } } ///  /// Gets / sets the image that will be drawn. ///  public new ImageSource Source { get { return (ImageSource) GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } #endregion #region Protected interface ///  /// Provides derived classs an opportunity to handle changes to the Source property. ///  protected virtual void OnSourceChanged(DependencyPropertyChangedEventArgs aEventArgs) { ClearAnimation(); BitmapImage lBitmapImage = aEventArgs.NewValue as BitmapImage; if (lBitmapImage == null) { ImageSource lImageSource = aEventArgs.NewValue as ImageSource; base.Source = lImageSource; return; } if (!IsAnimatedGifImage(lBitmapImage)) { base.Source = lBitmapImage; return; } PrepareAnimation(lBitmapImage); } #endregion #region Private properties private Int32Animation Animation { get; set; } private GifBitmapDecoder Decoder { get; set; } private bool IsAnimationWorking { get; set; } #endregion #region Private methods private void ClearAnimation() { if (Animation != null) { BeginAnimation(FrameIndexProperty, null); } IsAnimationWorking = false; Animation = null; Decoder = null; } private void PrepareAnimation(BitmapImage aBitmapImage) { Debug.Assert(aBitmapImage != null); if (aBitmapImage.UriSource != null) { Decoder = new GifBitmapDecoder( aBitmapImage.UriSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); } else { aBitmapImage.StreamSource.Position = 0; Decoder = new GifBitmapDecoder( aBitmapImage.StreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); } Animation = new Int32Animation( 0, Decoder.Frames.Count - 1, new Duration( new TimeSpan( 0, 0, 0, Decoder.Frames.Count / 10, (int) ((Decoder.Frames.Count / 10.0 - Decoder.Frames.Count / 10) * 1000)))) { RepeatBehavior = RepeatBehavior.Forever }; base.Source = Decoder.Frames[0]; BeginAnimation(FrameIndexProperty, Animation); IsAnimationWorking = true; } private bool IsAnimatedGifImage(BitmapImage aBitmapImage) { Debug.Assert(aBitmapImage != null); bool lResult = false; if (aBitmapImage.UriSource != null) { BitmapDecoder lBitmapDecoder = BitmapDecoder.Create( aBitmapImage.UriSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); lResult = lBitmapDecoder is GifBitmapDecoder; } else if (aBitmapImage.StreamSource != null) { try { long lStreamPosition = aBitmapImage.StreamSource.Position; aBitmapImage.StreamSource.Position = 0; GifBitmapDecoder lBitmapDecoder = new GifBitmapDecoder( aBitmapImage.StreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); lResult = lBitmapDecoder.Frames.Count > 1; aBitmapImage.StreamSource.Position = lStreamPosition; } catch { lResult = false; } } return lResult; } private static void ChangingFrameIndex (DependencyObject aObject, DependencyPropertyChangedEventArgs aEventArgs) { AnimatedImage lAnimatedImage = aObject as AnimatedImage; if (lAnimatedImage == null || !lAnimatedImage.IsAnimationWorking) { return; } int lFrameIndex = (int) aEventArgs.NewValue; ((Image) lAnimatedImage).Source = lAnimatedImage.Decoder.Frames[lFrameIndex]; lAnimatedImage.InvalidateVisual(); } ///  /// Handles changes to the Source property. ///  private static void OnSourceChanged (DependencyObject aObject, DependencyPropertyChangedEventArgs aEventArgs) { ((AnimatedImage) aObject).OnSourceChanged(aEventArgs); } #endregion #region Dependency Properties ///  /// FrameIndex Dependency Property ///  public static readonly DependencyProperty FrameIndexProperty = DependencyProperty.Register( "FrameIndex", typeof (int), typeof (AnimatedImage), new UIPropertyMetadata(0, ChangingFrameIndex)); ///  /// Source Dependency Property ///  public new static readonly DependencyProperty SourceProperty = DependencyProperty.Register( "Source", typeof (ImageSource), typeof (AnimatedImage), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure, OnSourceChanged)); #endregion } 

Eu uso essa biblioteca: http://wpfanimatedgif.codeplex.com/

Primeiro, instale a biblioteca no seu projeto (usando o Console do Gerenciador de Pacotes):

  PM > Install-Package WpfAnimatedGif 

Em seguida, use este trecho no arquivo XAML:

     ... 

Espero que ajude.

Fonte: http://wpfanimatedgif.codeplex.com/

Basicamente, a mesma solução PictureBox acima, mas desta vez com o code-behind para usar um recurso incorporado em seu projeto:

Em XAML:

    

Em Code-Behind:

 public partial class ProgressIcon { public ProgressIcon() { InitializeComponent(); var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("My.Namespace.ProgressIcon.gif"); var image = System.Drawing.Image.FromStream(stream); Loaded += (s, e) => _loadingPictureBox.Image = image; } } 

Eu modifiquei o código do Mike Eshva, e o fiz funcionar melhor.Você pode usá-lo com 1frame jpg png bmp ou mutil-frame gif.Se você quiser ligar um uri ao controle, ligar as propriedades UriSource ou você quer ligar qualquer in- stream de memory que você liga a propriedade Source, que é um BitmapImage.

  ///  /// Элемент управления "Изображения", поддерживающий анимированные GIF. ///  public class AnimatedImage : Image { static AnimatedImage() { DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimatedImage), new FrameworkPropertyMetadata(typeof(AnimatedImage))); } #region Public properties ///  /// Получает/устанавливает номер текущего кадра. ///  public int FrameIndex { get { return (int)GetValue(FrameIndexProperty); } set { SetValue(FrameIndexProperty, value); } } ///  /// Get the BitmapFrame List. ///  public List Frames { get; private set; } ///  /// Get or set the repeatBehavior of the animation when source is gif formart.This is a dependency object. ///  public RepeatBehavior AnimationRepeatBehavior { get { return (RepeatBehavior)GetValue(AnimationRepeatBehaviorProperty); } set { SetValue(AnimationRepeatBehaviorProperty, value); } } public new BitmapImage Source { get { return (BitmapImage)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } public Uri UriSource { get { return (Uri)GetValue(UriSourceProperty); } set { SetValue(UriSourceProperty, value); } } #endregion #region Protected interface ///  /// Provides derived classs an opportunity to handle changes to the Source property. ///  protected virtual void OnSourceChanged(DependencyPropertyChangedEventArgs e) { ClearAnimation(); BitmapImage source; if (e.NewValue is Uri) { source = new BitmapImage(); source.BeginInit(); source.UriSource = e.NewValue as Uri; source.CacheOption = BitmapCacheOption.OnLoad; source.EndInit(); } else if (e.NewValue is BitmapImage) { source = e.NewValue as BitmapImage; } else { return; } BitmapDecoder decoder; if (source.StreamSource != null) { decoder = BitmapDecoder.Create(source.StreamSource, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnLoad); } else if (source.UriSource != null) { decoder = BitmapDecoder.Create(source.UriSource, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnLoad); } else { return; } if (decoder.Frames.Count == 1) { base.Source = decoder.Frames[0]; return; } this.Frames = decoder.Frames.ToList(); PrepareAnimation(); } #endregion #region Private properties private Int32Animation Animation { get; set; } private bool IsAnimationWorking { get; set; } #endregion #region Private methods private void ClearAnimation() { if (Animation != null) { BeginAnimation(FrameIndexProperty, null); } IsAnimationWorking = false; Animation = null; this.Frames = null; } private void PrepareAnimation() { Animation = new Int32Animation( 0, this.Frames.Count - 1, new Duration( new TimeSpan( 0, 0, 0, this.Frames.Count / 10, (int)((this.Frames.Count / 10.0 - this.Frames.Count / 10) * 1000)))) { RepeatBehavior = RepeatBehavior.Forever }; base.Source = this.Frames[0]; BeginAnimation(FrameIndexProperty, Animation); IsAnimationWorking = true; } private static void ChangingFrameIndex (DependencyObject dp, DependencyPropertyChangedEventArgs e) { AnimatedImage animatedImage = dp as AnimatedImage; if (animatedImage == null || !animatedImage.IsAnimationWorking) { return; } int frameIndex = (int)e.NewValue; ((Image)animatedImage).Source = animatedImage.Frames[frameIndex]; animatedImage.InvalidateVisual(); } ///  /// Handles changes to the Source property. ///  private static void OnSourceChanged (DependencyObject dp, DependencyPropertyChangedEventArgs e) { ((AnimatedImage)dp).OnSourceChanged(e); } #endregion #region Dependency Properties ///  /// FrameIndex Dependency Property ///  public static readonly DependencyProperty FrameIndexProperty = DependencyProperty.Register( "FrameIndex", typeof(int), typeof(AnimatedImage), new UIPropertyMetadata(0, ChangingFrameIndex)); ///  /// Source Dependency Property ///  public new static readonly DependencyProperty SourceProperty = DependencyProperty.Register( "Source", typeof(BitmapImage), typeof(AnimatedImage), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure, OnSourceChanged)); ///  /// AnimationRepeatBehavior Dependency Property ///  public static readonly DependencyProperty AnimationRepeatBehaviorProperty = DependencyProperty.Register( "AnimationRepeatBehavior", typeof(RepeatBehavior), typeof(AnimatedImage), new PropertyMetadata(null)); public static readonly DependencyProperty UriSourceProperty = DependencyProperty.Register( "UriSource", typeof(Uri), typeof(AnimatedImage), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure, OnSourceChanged)); #endregion } 

Este é um controle personalizado. Você precisa criá-lo no projeto de aplicativo do WPF e excluir a substituição de modelo em estilo.

Eu tive esse problema, até que descobri que no WPF4, você pode simular suas próprias animações de imagem de quadro-chave. Primeiro, divida sua animação em uma série de imagens, classifique-as como “Image1.gif”, “Image2, gif” e assim por diante. Importe essas imagens para os resources da sua solução. Estou supondo que você os coloque no local de resources padrão para imagens.

Você vai usar o controle de imagem. Use o seguinte código XAML. Eu removi os não essenciais.

                                       

Obrigado pelo seu post Joel, isso me ajudou a resolver a falta de suporte do WPF para GIFs animados. Apenas adicionando um pequeno código desde que eu tive um monte de tempo com a configuração da propriedade pictureBoxLoading.Image devido à API do Winforms.

Eu tive que definir a ação Build Build da minha imagem gif como “Content” e o diretório Copy to output para “Copy if newer” ou “always”. Então, no MainWindow () eu chamei esse método. O único problema é que quando tentei descartar o stream, ele me deu um gráfico de envelope vermelho em vez da minha imagem. Vou ter que resolver esse problema. Isso removeu a dificuldade de carregar um BitmapImage e transformá-lo em um Bitmap (que obviamente matou minha animação porque não é mais um gif).

 private void SetupProgressIcon() { Uri uri = new Uri("pack://application:,,,/WPFTest;component/Images/animated_progress_apple.gif"); if (uri != null) { Stream stream = Application.GetContentStream(uri).Stream; imgProgressBox.Image = new System.Drawing.Bitmap(stream); } } 

Eu tentei o caminho todo, mas cada um tem sua falta, e graças a todos vocês, eu trabalho com o meu próprio GifImage:

  using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Controls; using System.Windows; using System.Windows.Media.Imaging; using System.IO; using System.Windows.Threading; namespace IEXM.Components { public class GifImage : Image { #region gif Source, such as "/IEXM;component/Images/Expression/f020.gif" 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(null, GifSourcePropertyChanged)); private static void GifSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { (sender as GifImage).Initialize(); } #endregion #region control the animate ///  /// Defines whether the animation starts on it's own ///  public bool IsAutoStart { get { return (bool)GetValue(AutoStartProperty); } set { SetValue(AutoStartProperty, value); } } public static readonly DependencyProperty AutoStartProperty = DependencyProperty.Register("IsAutoStart", typeof(bool), typeof(GifImage), new UIPropertyMetadata(false, AutoStartPropertyChanged)); private static void AutoStartPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { if ((bool)e.NewValue) (sender as GifImage).StartAnimation(); else (sender as GifImage).StopAnimation(); } #endregion private bool _isInitialized = false; private System.Drawing.Bitmap _bitmap; private BitmapSource _source; [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); private BitmapSource GetSource() { if (_bitmap == null) { _bitmap = new System.Drawing.Bitmap(Application.GetResourceStream( new Uri(GifSource, UriKind.RelativeOrAbsolute)).Stream); } IntPtr handle = IntPtr.Zero; handle = _bitmap.GetHbitmap(); BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); DeleteObject(handle); return bs; } private void Initialize() { // Console.WriteLine("Init: " + GifSource); if (GifSource != null) Source = GetSource(); _isInitialized = true; } private void FrameUpdatedCallback() { System.Drawing.ImageAnimator.UpdateFrames(); if (_source != null) { _source.Freeze(); } _source = GetSource(); // Console.WriteLine("Working: " + GifSource); Source = _source; InvalidateVisual(); } private void OnFrameChanged(object sender, EventArgs e) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(FrameUpdatedCallback)); } ///  /// Starts the animation ///  public void StartAnimation() { if (!_isInitialized) this.Initialize(); // Console.WriteLine("Start: " + GifSource); System.Drawing.ImageAnimator.Animate(_bitmap, OnFrameChanged); } ///  /// Stops the animation ///  public void StopAnimation() { _isInitialized = false; if (_bitmap != null) { System.Drawing.ImageAnimator.StopAnimate(_bitmap, OnFrameChanged); _bitmap.Dispose(); _bitmap = null; } _source = null; Initialize(); GC.Collect(); GC.WaitForFullGCComplete(); // Console.WriteLine("Stop: " + GifSource); } public void Dispose() { _isInitialized = false; if (_bitmap != null) { System.Drawing.ImageAnimator.StopAnimate(_bitmap, OnFrameChanged); _bitmap.Dispose(); _bitmap = null; } _source = null; GC.Collect(); GC.WaitForFullGCComplete(); // Console.WriteLine("Dispose: " + GifSource); } } } 

Uso:

  

Como não causaria memory leaks e animava a própria linha de tempo da imagem gif, você pode tentar.

Anteriormente, eu enfrentei um problema semelhante, eu precisava jogar o arquivo .gif em seu projeto. Eu tive duas escolhas:

  • Usando PictureBox do WinForms

  • usando uma biblioteca de terceiros, como WPFAnimatedGif de codeplex.com.

A versão com PictureBox não funcionou para mim e o projeto não pôde usar bibliotecas externas para ele. Então eu fiz para mim mesmo através do Bitmap com ajuda do ImageAnimator . Porque, o BitmapImage padrão não suporta a reprodução de arquivos .gif .

Exemplo completo:

XAML

      

Code behind

 public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } Bitmap _bitmap; BitmapSource _source; private BitmapSource GetSource() { if (_bitmap == null) { string path = Directory.GetCurrentDirectory(); // Check the path to the .gif file _bitmap = new Bitmap(path + @"\anim.gif"); } IntPtr handle = IntPtr.Zero; handle = _bitmap.GetHbitmap(); return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { _source = GetSource(); SampleImage.Source = _source; ImageAnimator.Animate(_bitmap, OnFrameChanged); } private void FrameUpdatedCallback() { ImageAnimator.UpdateFrames(); if (_source != null) { _source.Freeze(); } _source = GetSource(); SampleImage.Source = _source; InvalidateVisual(); } private void OnFrameChanged(object sender, EventArgs e) { Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(FrameUpdatedCallback)); } } 

Bitmap does not support URI directive, so I load .gif file from the current directory.

Small improvement of GifImage.Initialize() method, which reads proper frame timing from GIF metadata.

  private void Initialize() { _gifDecoder = new GifBitmapDecoder(new Uri("pack://application:,,," + this.GifSource), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); int duration=0; _animation = new Int32AnimationUsingKeyFrames(); _animation.KeyFrames.Add(new DiscreteInt32KeyFrame(0, KeyTime.FromTimeSpan(new TimeSpan(0)))); foreach (BitmapFrame frame in _gifDecoder.Frames) { BitmapMetadata btmd = (BitmapMetadata)frame.Metadata; duration += (ushort)btmd.GetQuery("/grctlext/Delay"); _animation.KeyFrames.Add(new DiscreteInt32KeyFrame(_gifDecoder.Frames.IndexOf(frame)+1, KeyTime.FromTimeSpan(new TimeSpan(duration*100000)))); } _animation.RepeatBehavior = RepeatBehavior.Forever; this.Source = _gifDecoder.Frames[0]; _isInitialized = true; } 

I am not sure if this has been solved but the best way is to use the WpfAnimatedGid library . It is very easy, simple and straight forward to use. It only requires 2lines of XAML code and about 5 lines of C# Code in the code behind.

You will see all the necessary details of how this can be used there. This is what I also used instead of re-inventing the wheel

Adding on to the main response that recommends the usage of WpfAnimatedGif , you must add the following lines in the end if you are swapping an image with a Gif to ensure the animation actually executes:

 ImageBehavior.SetRepeatBehavior(img, new RepeatBehavior(0)); ImageBehavior.SetRepeatBehavior(img, RepeatBehavior.Forever); 

So your code will look like:

 var image = new BitmapImage(); image.BeginInit(); image.UriSource = new Uri(fileName); image.EndInit(); ImageBehavior.SetAnimatedSource(img, image); ImageBehavior.SetRepeatBehavior(img, new RepeatBehavior(0)); ImageBehavior.SetRepeatBehavior(img, RepeatBehavior.Forever);