Brian Var
Brian Var

Reputation: 6227

How to call stop to MediaElement after a set duration?

I have added a media element to a WPF window that plays a gif file. But I'm not sure how to stop the gif playing after a set number of seconds.

In my current implementation the gif plays to instruct the user how to perform an action when the window is loaded but I don't want the gif to play in a loop, I would like to be able to stop the gif after a number of seconds.

Is it possible to achieve this with a media element?

private void Window_Loaded(object sender, RoutedEventArgs e)
{
      // set the phrases to listen for and start listening
      listener.Phrases = PhrasesTextBox.Text;
      listener.StartListening();

      gifMediaElement.Play();

}

Upvotes: 0

Views: 1877

Answers (2)

Peter Ritchie
Peter Ritchie

Reputation: 35881

If you wanted to continue to use the MediaElement type, one method would be to use a DispatcherTimer. You can set it to tick on a certain number of seconds and turn both the timer off and the MediaElement. For example:

DispatcherTimer timer = new DispatcherTimer();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    //...
    gifMediaElement.Play();
    timer.Interval = TimeSpan.FromSeconds(5);
    timer.Start();
    timer.Tick += (o, args) =>
    {
        timer.Stop();
        gifMediaElement.Stop();
    };
    //...

Upvotes: 1

Anatoliy Nikolaev
Anatoliy Nikolaev

Reputation: 22702

Try use AnimatedGIFControl:

In WPF MediaElement could show animated GIF images with some less desirable limitations:

  1. The Source property must be set with absolute path;
  2. Play-back functionality is not supported by default;
  3. Transparent pixels display as black.

Below is example of using AnimatedGIFControl:

XAML

<Window x:Class="CSWPFAnimatedGIF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CSWPFAnimatedGIF"
        Title="Animated GIF" Height="300" Width="300">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <local:AnimatedGIFControl x:Name="GIFCtrl"/>

        <Button x:Name="btnStart" Width="70" Height="30" Margin="50" 
                HorizontalAlignment="Left" Grid.Row="1" Click="btnStart_Click">Start</Button>

        <Button x:Name="btnStop" Width="70" Height="30" Margin="50"
                HorizontalAlignment="Right" Grid.Row="1" Click="btnStop_Click">Stop</Button>        
    </Grid>
</Window>

Code-behind

public class AnimatedGIFControl : System.Windows.Controls.Image
{
    private Bitmap _bitmap; // Local bitmap member to cache image resource
    private BitmapSource _bitmapSource;
    public delegate void FrameUpdatedEventHandler();


    /// <summary>
    /// Delete local bitmap resource
    /// Reference: http://msdn.microsoft.com/en-us/library/dd183539(VS.85).aspx
    /// </summary>
    [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool DeleteObject(IntPtr hObject);

    /// <summary>
    /// Override the OnInitialized method
    /// </summary>
    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
        this.Loaded += new RoutedEventHandler(AnimatedGIFControl_Loaded);
        this.Unloaded += new RoutedEventHandler(AnimatedGIFControl_Unloaded);           
    }

    /// <summary>
    /// Load the embedded image for the Image.Source
    /// </summary>

    void AnimatedGIFControl_Loaded(object sender, RoutedEventArgs e)
    {
        // Get GIF image from Resources
        if (Properties.Resources.ProgressIndicator != null)
        {
            _bitmap = Properties.Resources.ProgressIndicator;
            Width = _bitmap.Width;
            Height = _bitmap.Height;

            _bitmapSource = GetBitmapSource();
            Source = _bitmapSource;  
        }             
    }

    /// <summary>
    /// Close the FileStream to unlock the GIF file
    /// </summary>
    private void AnimatedGIFControl_Unloaded(object sender, RoutedEventArgs e)
    {
        StopAnimate();
    }

    /// <summary>
    /// Start animation
    /// </summary>
    public void StartAnimate()
    {
        ImageAnimator.Animate(_bitmap, OnFrameChanged);
    }

    /// <summary>
    /// Stop animation
    /// </summary>
    public void StopAnimate()
    {
        ImageAnimator.StopAnimate(_bitmap, OnFrameChanged);
    }

    /// <summary>
    /// Event handler for the frame changed
    /// </summary>
    private void OnFrameChanged(object sender, EventArgs e)
    {
        Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                               new FrameUpdatedEventHandler(FrameUpdatedCallback));
    }

    private void FrameUpdatedCallback()
    {
        ImageAnimator.UpdateFrames();

        if (_bitmapSource != null)
            _bitmapSource.Freeze();

        // Convert the bitmap to BitmapSource that can be display in WPF Visual Tree
        _bitmapSource = GetBitmapSource();
        Source = _bitmapSource;
        InvalidateVisual();
    }

    private BitmapSource GetBitmapSource()
    {
        IntPtr handle = IntPtr.Zero;                

        try
        {
            handle = _bitmap.GetHbitmap();
            _bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
                handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
        finally
        {
            if (handle != IntPtr.Zero)
                DeleteObject(handle);
        }

        return _bitmapSource;
    }
}

Code Logic

  1. Use ImageAnimator to animates a GIF image that has time-based frames.
  2. Render every frame of GIF image in another thread using InvalidateVisual method.
  3. Derive from the Image control, in order to make it easy to use as Image control.
  4. Dispose the dump resources to ensure the efficiency.

Upvotes: 2

Related Questions