简体   繁体   中英

Play Gif in WPF

I am currently trying to display and play an animated gif in WPF without much luck

I have tried all the solutions found here including the one in the question

Here is what i currently have

<Window x:Class="Sooooothing.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Attached="clr-namespace:Sooooothing"
    Title="MainWindow" Height="327.861" Width="525">
<Grid>
    <MediaElement x:Name="gif" MediaEnded="myGif_MediaEnded" UnloadedBehavior="Manual" 
                  Source="Images\7c6516d73fc8643abf1df969fcc1a72c.gif" 
                  LoadedBehavior="Play" Stretch="None"/>
</Grid>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Sooooothing
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //gif.Play();
        }
        private void myGif_MediaEnded(object sender, RoutedEventArgs e)
        {
            gif.Position = new TimeSpan(0, 0, 1);
            gif.Play();
        }
    }
}

When the application starts all i get is the white background for the window, at first i though it was the gif not loading but i let it sit for a couple minutes without any change.

Here is my solution

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Sooooothing
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        GifBitmapDecoder decoder2;
        int ImageNumber = 0;
        bool mouseIn = true;
        double opasity = 0;
        List<Thread> threadList = new List<Thread>();
        bool programClosed = false;
        public MainWindow()
        {
            InitializeComponent();

            Classes.DataHouse.load(); //Im storing all my gif links in this List<string> so i can 
            // loop through them with buttons on the window

            #region thread gif frame changer
            Uri myUri = new Uri(Classes.DataHouse.images[ImageNumber], UriKind.RelativeOrAbsolute);
            decoder2 = new GifBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            BitmapSource bitmapSource2; // Decode the gif using GifBitmapDecoder then start a thread to 
            int frameCount = decoder2.Frames.Count;// loop through all the images and put them one after
            Thread th = new Thread(() => {// another into an image on your window
                while (!programClosed)
                {

                    for (int i = 0; i < frameCount; i++)
                    {
                        try{
                            this.Dispatcher.Invoke(new Action(delegate()
                            {
                                frameCount = decoder2.Frames.Count;
                                if (frameCount >= i)
                                {
                                    bitmapSource2 = decoder2.Frames[i];
                                    image.Source = bitmapSource2;
                                }

                            }));
                        }
                        catch
                        {
                            //the thread was probably aborted
                        }
                        System.Threading.Thread.Sleep(100);
                    }
                }
            });
            threadList.Add(th);
            th.Start();
            #endregion
        }

        private void Window_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Left)
                this.DragMove();
        }

        private void img_forward_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (ImageNumber+1 >= Classes.DataHouse.images.Count)
                ImageNumber = 0;
            else
                ImageNumber++;
            Uri myUri = new Uri(Classes.DataHouse.images[ImageNumber], UriKind.RelativeOrAbsolute);
            decoder2 = new GifBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
        }

        private void Grid_MouseEnter(object sender, MouseEventArgs e)
        {
            mouseIn = true;
            Thread th = new Thread(() => 
            {
                while (opasity < 100 && mouseIn)
                {
                    System.Threading.Thread.Sleep(25);
                    opasity++;
                    try
                    {
                        this.Dispatcher.Invoke(new Action(delegate()
                        {
                            img_forward.Opacity = opasity / 100;
                            img_exit.Opacity = opasity / 100;
                            img_backward.Opacity = opasity / 100;
                        }));
                    }
                    catch
                    {
                        //the thread was probably aborted
                    }
                }
            });
            threadList.Add(th);
            th.Start();


        }

        private void Grid_MouseLeave(object sender, MouseEventArgs e)
        {
            mouseIn = false;
            Thread th = new Thread(() =>
            {

                while (opasity > 0 && !mouseIn)
                {
                    System.Threading.Thread.Sleep(25);
                    opasity--;
                    try{
                        this.Dispatcher.Invoke(new Action(delegate()
                        {
                            img_forward.Opacity = opasity / 100;
                            img_exit.Opacity = opasity / 100;
                            img_backward.Opacity = opasity / 100;
                        }));
                    }
                    catch
                    {
                        //the thread was probably aborted
                    }
                }
            });
            threadList.Add(th);
            th.Start();
        }

        private void img_backward_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (ImageNumber - 1 < 0)
                ImageNumber = Classes.DataHouse.images.Count-1;
            else
                ImageNumber--;
            Uri myUri = new Uri(Classes.DataHouse.images[ImageNumber], UriKind.RelativeOrAbsolute);
            decoder2 = new GifBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
        }

        private void img_exit_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            foreach (Thread th in threadList)
            {
                while(th.ThreadState == ThreadState.Running)
                    th.Abort();
            }
            programClosed = true;
            this.Close();
        }

    }
}

Unfortunately, animated GIF images were somewhat of an oversight when Microsoft developed WPF, so there is no 'built in' functionality that handles this. There are several working examples found online, but you should still be aware that code needs to be run on the UI thread to animate these images.

Therefore, certain situations, such as trying to use a 'busy' GIF during loading will not work because the UI thread will already be busy.

Having announced that disclaimer, you can find some working code that will do what you want in Thomas Levesque's GitHub project at the link below:

thomaslevesque/WpfAnimatedGif

Using a Thread

public MainWindow()
        {
            InitializeComponent();

            Uri myUri = new Uri(@"Images\2b3601fe2b62e87481bd301da52a2182.gif", UriKind.RelativeOrAbsolute);
            GifBitmapDecoder decoder2 = new GifBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            BitmapSource bitmapSource2;
            int frameCount = decoder2.Frames.Count;

            Thread th = new Thread(() => {
                while (true)
                {
                    for (int i = 0; i < frameCount; i++)
                    {
                        this.Dispatcher.Invoke(new Action(delegate()
                        {
                            bitmapSource2 = decoder2.Frames[i];
                            image.Source = bitmapSource2;
                        }));
                        System.Threading.Thread.Sleep(100);
                    }
                }
            });
            th.Start();
        }

This only works with physical files that aren't compiled as Resources, etc.

Try to change your image resource Build Action to Content or something similar, instead of Resource (And activate Copy to Output Directory, maybe?).

I managed to get a sample working that way. The key is that you must reference a physical file in some folder or internet URL.

For more info, check this out: https://social.msdn.microsoft.com/Forums/vstudio/en-US/93d50a97-0d8d-4b18-992e-cd3200693337/how-to-use-an-animated-gif?forum=wpf

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM