Làm cách nào để có một gif hoạt hình hoạt động trong WPF?


217

Tôi nên sử dụng kiểm soát những gì loại - Image, MediaElementvv?


4
Dưới đây là một bản tóm tắt gần đây của các giải pháp dưới đây. Tôi đã thực hiện những điều này bằng cách sử dụng VS2015. Lớp GifImage được gửi bởi Dario đã hoạt động rất tốt, nhưng một số gifs của tôi đã được tạo ra. Cách tiếp cận MediaEuity của Pradip Daunde và nicael dường như hoạt động trong khu vực xem trước, nhưng không có gifs nào của tôi được hiển thị trong thời gian chạy. Giải pháp WpfAnimatedGif của IgorVaschuk và SaiyanGirl hoạt động rất tốt mà không gặp vấn đề gì nhưng yêu cầu cài đặt thư viện của bên thứ ba (rõ ràng). Tôi đã không thử phần còn lại.
Heath Carroll

Câu trả lời:


214

Tôi không thể có câu trả lời phổ biến nhất cho câu hỏi này (ở trên bởi Dario) để hoạt động đúng. Kết quả là kỳ lạ, hoạt hình nhảm nhí với các tạo tác kỳ lạ. Giải pháp tốt nhất tôi đã tìm thấy cho đến nay: https://github.com/XamlAnimatedGif/WpfAnimatedGif

Bạn có thể cài đặt nó với NuGet

PM> Install-Package WpfAnimatedGif

và để sử dụng nó, tại một không gian tên mới cho Cửa sổ nơi bạn muốn thêm hình ảnh gif và sử dụng nó như dưới đây

<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" />

Gói thực sự gọn gàng, bạn có thể đặt một số thuộc tính như bên dưới

<Image gif:ImageBehavior.RepeatBehavior="3x"
       gif:ImageBehavior.AnimatedSource="Images/animated.gif" />

và bạn cũng có thể sử dụng nó trong mã của mình:

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

EDIT: Hỗ trợ Silverlight

Theo nhận xét của josh2112 nếu bạn muốn thêm hỗ trợ GIF hoạt hình cho dự án Silverlight của mình thì hãy sử dụng github.com/XamlAnimatedGif/XamlAnimatedGif


13
Điều này làm việc rất tốt, và mất ít hơn 60 giây để thực hiện. Cảm ơn!
Ryan Sorensen

3
Cách trả lời tốt hơn bất kỳ câu hỏi phổ biến nào IMO, đặc biệt là vì nó không phụ thuộc vào bạn khi sử dụng C #
Jamie E

8
Điều này tốt hơn nhiều so với câu trả lời được chấp nhận: sử dụng siêu dữ liệu của gif, không bị giật, là gói NuGet, là ngôn ngữ bất khả tri. Tôi muốn stackoverflow cho phép bỏ phiếu không tin tưởng vào câu trả lời được chấp nhận.
John Gietzen

6
Thông báo dịch vụ công cộng: Tác giả của WpfAnimatedGif đã 'khởi động lại' dự án của mình với tên XamlAnimatedGif và nó hỗ trợ WPF, Windows Store (Win8), Windows 10 và Silverlight: github.com/XamlAnimatedGif/XamlAnimatedGif
19

2
Cái gì imgđây
amit jha

104

Tôi đăng một giải pháp mở rộng điều khiển hình ảnh và sử dụng Bộ giải mã Gif. Bộ giải mã gif có thuộc tính khung. Tôi animate FrameIndextài sản. Sự kiện ChangingFrameIndexthay đổi thuộc tính nguồn thành khung tương ứng với FrameIndex(đó là trong bộ giải mã). Tôi đoán rằng gif có 10 khung hình mỗi giây.

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);
    }
}

Ví dụ sử dụng (XAML):

<controls:GifImage x:Name="gifImage" Stretch="None" GifSource="/SomeImage.gif" AutoStart="True" />

1
Ứng dụng này hoạt động và tốt hơn cho các ứng dụng XBAP, vì bạn không cần thêm tài liệu tham khảo.
Max Galkin

1
Thật tuyệt. Bằng cách đặt mã xây dựng của bạn vào sự kiện "Đã khởi tạo" và giới thiệu thuộc tính Uri, điều khiển này cũng có thể được đặt trong tệp XAML.
flq

1
+1, một cái tốt đẹp! Tuy nhiên, nó không tính đến thời lượng khung hình thực tế của hình ảnh ... Nếu bạn có thể tìm cách đọc thông tin đó, bạn có thể thay đổi mã để sử dụngInt32AnimationUsingKeyFrames
Thomas Levesque

7
Trên thực tế, tốc độ khung hình là không đổi đối với GIF, vì vậy sau tất cả, bạn không cần khung hình chính ... Bạn có thể đọc tốc độ khung hình với gf.Frames[0].MetaData.GetQuery("/grctlext/Delay")(trả về một ushort có thời lượng khung hình trong hàng trăm giây)
Thomas Levesque

3
@vidstige, vâng, tôi không nhớ tại sao tôi lại đưa ra nhận xét này vào lúc đó (gần 2 năm trước). Tôi biết rằng độ trễ có thể khác nhau đối với từng khung và thư viện GIF hoạt hình WPF của tôi sẽ tính đến nó.
Thomas Levesque

38

Tôi cũng vậy, tôi đã tìm kiếm và tìm thấy một số giải pháp khác nhau chỉ trong một chủ đề trên các diễn đàn MSDN cũ. (liên kết không còn hoạt động nên tôi đã gỡ bỏ nó)

Cách đơn giản nhất để thực thi dường như là sử dụng PictureBoxđiều khiển WinForms và thực hiện như thế này (đã thay đổi một số thứ từ luồng, hầu hết đều giống nhau).

Thêm một tham chiếu đến System.Windows.Forms, WindowsFormsIntegrationSystem.Drawingđể dự án của bạn đầu tiên.

<Window x:Class="GifExample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
    xmlns:winForms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
    Loaded="Window_Loaded" >
    <Grid>
        <wfi:WindowsFormsHost>
            <winForms:PictureBox x:Name="pictureBoxLoading">
            </winForms:PictureBox>
        </wfi:WindowsFormsHost>
    </Grid>
</Window >

Sau đó, trong Window_Loadedtrình xử lý, bạn sẽ đặt thuộc pictureBoxLoading.ImageLocationtính thành đường dẫn tệp hình ảnh mà bạn muốn hiển thị.

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

Các MediaElementkiểm soát đã được đề cập trong chủ đề đó, nhưng nó cũng được đề cập rằng nó là một điều khiển khá nặng, vì vậy đã có một số lựa chọn thay thế, trong đó có ít nhất 2 điều khiển homebrewed dựa trên Imagekiểm soát, vì vậy đây là đơn giản nhất.


bạn có thể đặt cửa sổ chính này với AllowTrans minh bạch = "Đúng" khi sử dụng WindowsFormshost không?
Junior Mayhé

@Junior: Vâng, bạn có thể thiết lập AllowTransparency="True". Có hay không điều đó sẽ tạo ra kết quả bạn có trong tâm trí là một vấn đề khác. Bản thân tôi đã không thử nó, nhưng tôi cá là nó WindowsFormsHostsẽ không trở nên trong suốt. Phần còn lại của sức Windowmạnh. Tôi nghĩ đơn giản là bạn sẽ thử nó.
Joel B Fant

Tôi gặp sự cố với imageBoxLoading.Image do API winform. Tôi đã đăng mã dưới đây đã giải quyết vấn đề của tôi. Cảm ơn giải pháp của bạn, Joel!
sondlerd

Hình như bạn thích đã chết. Có phải đây là chủ đề ?
lau

2
Khi thêm tham chiếu Tích hợp, tên của nó trong Giao diện người dùng của tôi là WindowsFormsIntegration, không có dấu chấm: i.imgur.com/efMiC23.png
yu yang Jian

36

Làm thế nào về ứng dụng nhỏ bé này: Mã phía sau:

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>

1
Đẹp ! Mã ngắn, làm tốt công việc. Tôi không thể tin rằng nó không có nhiều upvote.
lau

2
Câu trả lời hay nhất ... Nên đứng đầu! Tôi đã có thể làm cho nó hoạt động mà không cần bất kỳ mã nào phía sau - chỉ thế này <MediaElement LoadedBehavior="Play" Source="{Binding MyGifFile}" >- MyGifFile chỉ là tên tệp (và đường dẫn) của gif hoạt hình của tôi.
Anthony Nichols

Jeez, tại sao thậm chí bận tâm để liên kết với ListBox, hoặc ràng buộc ở tất cả? Tôi đã thử nó mà không ràng buộc, chỉ cần đặt đường dẫn tệp trong Nguồn và nó xuất hiện, nhưng không hoạt hình. Nếu tôi sử dụng ràng buộc, ngay cả với ListBox, nó hoàn toàn không xuất hiện, đối với tôi - nó sẽ cho tôi một ngoại lệ rằng đường dẫn tệp của tôi không chính xác, mặc dù nó giống với cái tôi sử dụng khi nó xuất hiện.
vapcguy

Phải mất nhiều thời gian để cập nhật và cần được cập nhật mỗi khi nó được xem.
Yola

15

Nó rất đơn giản nếu bạn sử dụng <MediaElement>:

<MediaElement  Height="113" HorizontalAlignment="Left" Margin="12,12,0,0" 
Name="mediaElement1" VerticalAlignment="Top" Width="198" Source="C:\Users\abc.gif"
LoadedBehavior="Play" Stretch="Fill" SpeedRatio="1" IsMuted="False" />

Chỉ trong trường hợp tệp của bạn được đóng gói trong ứng dụng của bạn, bạn có thể sử dụng DataBinding cho Nguồn và tìm đường dẫn trong mã : public string SpinnerLogoPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Assets\images\mso_spinninglogo_blue_2.gif");. Đảm bảo đặt tệp thành Build = Content và sao chép vào thư mục đầu ra.
Người đàn ông Muffin

Tôi đã sử dụng phương pháp này vì gói NuGet của WpfAnimatedGif không hoạt động tốt đối với tôi - dường như bị trục trặc khi tải CPU nặng. Tôi đặt gif thành Build = Resource và đặt Nguồn bằng cách sử dụng đường dẫn tương đối từ thư mục mà Window nằm trong ví dụ Source = "../../ Hình ảnh / Xoay-e.gif". Làm việc tốt cho tôi và không cần DLL của bên thứ 3.
Richard Moore

Đây là giải pháp đơn giản nhất cho đến nay. Nhưng vấn đề với nó là một khi tất cả các khung hình của gif hoạt hình được quét qua, hoạt ảnh sẽ dừng lại. Và không có cách nào để đưa gif hoạt hình từ khung 0 nữa. Không có cách nào để khởi động lại hoạt hình hoặc vòng lặp mãi mãi. Ít nhất, tôi chưa tìm được cách sử dụng <MediaEuity />.
BoiseBakes

Ngoài ra <MediaEuity /> chậm đến mức không thể tin được và có đầy đủ các vấn đề đua luồng giữa các phương thức của nó. Grrrẻ.
BoiseBakes

10

Đây là phiên bản điều khiển hình ảnh hoạt hình của tôi. Bạn có thể sử dụng Nguồn thuộc tính tiêu chuẩn để chỉ định nguồn hình ảnh. Tôi tiếp tục cải thiện nó. Tôi là người Nga, dự án là tiếng Nga nên bình luận cũng bằng tiếng Nga. Nhưng dù sao bạn cũng có thể hiểu mọi thứ mà không cần bình luận. :)

/// <summary>
/// Control the "Images", which supports animated GIF.
/// </summary>
public class AnimatedImage : Image
{
    #region Public properties

    /// <summary>
    /// Gets / sets the number of the current frame.
    /// </summary>
    public int FrameIndex
    {
        get { return (int) GetValue(FrameIndexProperty); }
        set { SetValue(FrameIndexProperty, value); }
    }

    /// <summary>
    /// Gets / sets the image that will be drawn.
    /// </summary>
    public new ImageSource Source
    {
        get { return (ImageSource) GetValue(SourceProperty); }
        set { SetValue(SourceProperty, value); }
    }

    #endregion

    #region Protected interface

    /// <summary>
    /// Provides derived classes an opportunity to handle changes to the Source property.
    /// </summary>
    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();
    }

    /// <summary>
    /// Handles changes to the Source property.
    /// </summary>
    private static void OnSourceChanged
        (DependencyObject aObject, DependencyPropertyChangedEventArgs aEventArgs)
    {
        ((AnimatedImage) aObject).OnSourceChanged(aEventArgs);
    }

    #endregion

    #region Dependency Properties

    /// <summary>
    /// FrameIndex Dependency Property
    /// </summary>
    public static readonly DependencyProperty FrameIndexProperty =
        DependencyProperty.Register(
            "FrameIndex",
            typeof (int),
            typeof (AnimatedImage),
            new UIPropertyMetadata(0, ChangingFrameIndex));

    /// <summary>
    /// Source Dependency Property
    /// </summary>
    public new static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register(
            "Source",
            typeof (ImageSource),
            typeof (AnimatedImage),
            new FrameworkPropertyMetadata(
                null,
                FrameworkPropertyMetadataOptions.AffectsRender |
                FrameworkPropertyMetadataOptions.AffectsMeasure,
                OnSourceChanged));

    #endregion
}

15
Mã này là một phần của một trong các dự án của tôi. Tôi là một nhà phát triển người Nga làm việc tại Nga. Vì vậy, ý kiến ​​cũng bằng tiếng Nga. Không phải mọi dự án trên thế giới đều là dự án "American-english", Corey.
Mike Eshva

2
đã thử sử dụng mã của bạn với đánh dấu sau: <local: AnimatedImage Source = "/ Resources / ajax-loader.gif" /> nhưng cho đến nay không có gì xảy ra
Sonic Soul

nếu tôi thay đổi nó bằng cách sử dụng jpeg, nó sẽ hiển thị hình ảnh tĩnh. chỉ không phải là gif. mã đẹp BTW
Sonic Soul

Rực rỡ, tôi cần một giải pháp trong đó tôi có thể ngoại trừ một GIF từ Từ điển tài nguyên -> BitmapImage -> GIF hoạt hình. Đây là nó!
mtbennett

9

Tôi sử dụng thư viện này: https://github.com/XamlAnimatedGif/WpfAnimatedGif

Đầu tiên, cài đặt thư viện vào dự án của bạn (sử dụng Bảng điều khiển quản lý gói):

    PM > Install-Package WpfAnimatedGif

Sau đó, sử dụng đoạn mã này vào tệp XAML:

    <Window x:Class="WpfAnimatedGif.Demo.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"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Image gif:ImageBehavior.AnimatedSource="Images/animated.gif" />
        ...

Tôi hy vọng sẽ giúp.

Nguồn: https://github.com/XamlAnimatedGif/WpfAnimatedGif


3
Đây là câu trả lời tương tự (ít chi tiết hơn) như câu trả lời của @ IgorVaschuk từ tháng 6 năm 2012, hiện là giải pháp bình chọn thứ 2.
Heath Carroll

5

Về cơ bản, cùng một giải pháp PictureBox ở trên, nhưng lần này với mã phía sau để sử dụng Tài nguyên nhúng trong dự án của bạn:

Trong XAML:

<WindowsFormsHost x:Name="_loadingHost">
  <Forms:PictureBox x:Name="_loadingPictureBox"/>
</WindowsFormsHost>

Trong Code-Phía sau:

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;
    }
}

Tốt bổ sung. Thực sự hợp lý hóa nó, từ những gì tôi có thể nói. (Điều đó nói rằng, tôi đã không viết trong WPF trong hơn ba năm nay.)
CodeMouse92

Tôi thực sự không nghĩ rằng đây là một ý tưởng tốt bởi vì một trong những lý do chính khiến bạn đi với WPF là vì tỷ lệ hiển thị của nó. Bạn sẽ kết thúc với một tạo tác (hình ảnh) không đúng tỷ lệ.
Người đàn ông Muffin

5

Tôi đã sửa đổi mã của Mike Eshva và tôi đã làm cho nó hoạt động tốt hơn. Bạn có thể sử dụng nó với 1frame jpg png bmp hoặc mutil-frame gif. luồng bộ nhớ mà bạn liên kết với nguồn thích hợp là BitmapImage.

    /// <summary> 
/// Элемент управления "Изображения", поддерживающий анимированные GIF. 
/// </summary> 
public class AnimatedImage : Image
{
    static AnimatedImage()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimatedImage), new FrameworkPropertyMetadata(typeof(AnimatedImage)));
    }

    #region Public properties

    /// <summary> 
    /// Получает/устанавливает номер текущего кадра. 
    /// </summary> 
    public int FrameIndex
    {
        get { return (int)GetValue(FrameIndexProperty); }
        set { SetValue(FrameIndexProperty, value); }
    }

    /// <summary>
    /// Get the BitmapFrame List.
    /// </summary>
    public List<BitmapFrame> Frames { get; private set; }

    /// <summary>
    /// Get or set the repeatBehavior of the animation when source is gif formart.This is a dependency object.
    /// </summary>
    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

    /// <summary> 
    /// Provides derived classes an opportunity to handle changes to the Source property. 
    /// </summary> 
    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();
    }

    /// <summary> 
    /// Handles changes to the Source property. 
    /// </summary> 
    private static void OnSourceChanged
        (DependencyObject dp, DependencyPropertyChangedEventArgs e)
    {
        ((AnimatedImage)dp).OnSourceChanged(e);
    }

    #endregion

    #region Dependency Properties

    /// <summary> 
    /// FrameIndex Dependency Property 
    /// </summary> 
    public static readonly DependencyProperty FrameIndexProperty =
        DependencyProperty.Register(
            "FrameIndex",
            typeof(int),
            typeof(AnimatedImage),
            new UIPropertyMetadata(0, ChangingFrameIndex));

    /// <summary> 
    /// Source Dependency Property 
    /// </summary> 
    public new static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register(
            "Source",
            typeof(BitmapImage),
            typeof(AnimatedImage),
            new FrameworkPropertyMetadata(
                null,
                FrameworkPropertyMetadataOptions.AffectsRender |
                FrameworkPropertyMetadataOptions.AffectsMeasure,
                OnSourceChanged));

    /// <summary>
    /// AnimationRepeatBehavior Dependency Property
    /// </summary>
    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
}

Đây là một điều khiển tùy chỉnh. Bạn cần tạo nó trong Dự án ứng dụng WPF và xóa ghi đè Mẫu theo kiểu.


1
Tôi vừa phải đặt UriSource thành gói: // application: ,,, / Images / loader.gif. Đặt UriSource hoặc Nguồn thành Uri tương đối không thành công khi chạy.
Farzan

Vâng, tôi đã thử nó và tôi đang nhận được một ngoại lệ. Nó không hoạt động với uris tương đối.
SuperJMN

3

Tôi đã có vấn đề này, cho đến khi tôi phát hiện ra rằng trong WPF4, bạn có thể mô phỏng hình ảnh động khung hình chính của riêng bạn. Đầu tiên, chia hoạt hình của bạn thành một loạt các hình ảnh, đặt tên cho chúng là "Image1.gif", "Image2, gif", v.v. Nhập những hình ảnh đó vào tài nguyên giải pháp của bạn. Tôi giả sử bạn đặt chúng ở vị trí tài nguyên mặc định cho hình ảnh.

Bạn sẽ sử dụng điều khiển hình ảnh. Sử dụng mã XAML sau. Tôi đã loại bỏ những thứ không cần thiết.

<Image Name="Image1">
   <Image.Triggers>
      <EventTrigger RoutedEvent="Image.Loaded"
         <EventTrigger.Actions>
            <BeginStoryboard>
               <Storyboard>
                   <ObjectAnimationUsingKeyFrames Duration="0:0:1" Storyboard.TargetProperty="Source" RepeatBehavior="Forever">
                      <DiscreteObjectKeyFrames KeyTime="0:0:0">
                         <DiscreteObjectKeyFrame.Value>
                            <BitmapImage UriSource="Images/Image1.gif"/>
                         </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrames>
                     <DiscreteObjectKeyFrames KeyTime="0:0:0.25">
                        <DiscreteObjectKeyFrame.Value>
                           <BitmapImage UriSource="Images/Image2.gif"/>
                        </DiscreteObjectKeyFrame.Value>
                     </DiscreteObjectKeyFrames>
                     <DiscreteObjectKeyFrames KeyTime="0:0:0.5">
                        <DiscreteObjectKeyFrame.Value>
                           <BitmapImage UriSource="Images/Image3.gif"/>
                        </DiscreteObjectKeyFrame.Value>
                     </DiscreteObjectKeyFrames>
                     <DiscreteObjectKeyFrames KeyTime="0:0:0.75">
                        <DiscreteObjectKeyFrame.Value>
                           <BitmapImage UriSource="Images/Image4.gif"/>
                        </DiscreteObjectKeyFrame.Value>
                     </DiscreteObjectKeyFrames>
                     <DiscreteObjectKeyFrames KeyTime="0:0:1">
                        <DiscreteObjectKeyFrame.Value>
                           <BitmapImage UriSource="Images/Image5.gif"/>
                        </DiscreteObjectKeyFrame.Value>
                     </DiscreteObjectKeyFrames>
                  </ObjectAnimationUsingKeyFrames>
               </Storyboard>
            </BeginStoryboard>
         </EventTrigger.Actions>
      </EventTrigger>
   </Image.Triggers>
</Image>

1
Dường như một nhược điểm của phương pháp này là theo mặc định, hình ảnh động vẫn tiếp tục ngay cả sau khi nó bị Thu gọn, có thể gây ra hiệu ứng.
Lynn

Đó không phải là Disc rờiObjectKeyFrames, đó là Disc rờiObjectKeyFrame. Số ít.
jairhumber đến

@jairhumberto Tôi nghĩ rằng có thể đã thay đổi giữa các phiên bản. Điều này khá cũ (2011), nhưng tôi thực sự đã sử dụng mã chính xác này trong một dự án.
CodeMouse92

3

Cảm ơn bài đăng của bạn Joel, nó đã giúp tôi giải quyết sự vắng mặt của WPF về hỗ trợ cho GIF hoạt hình. Chỉ cần thêm một ít mã kể từ khi tôi có một chút thời gian với việc đặt thuộc tính imageBoxLoading.Image do api Winforms.

Tôi đã phải đặt Build Action của ảnh gif hoạt hình của mình là "Nội dung" và thư mục Sao chép vào đầu ra thành "Sao chép nếu mới hơn" hoặc "luôn luôn". Sau đó, trong MainWindow () tôi đã gọi phương thức này. Vấn đề duy nhất là khi tôi cố gắng loại bỏ luồng, nó đã cho tôi một hình ảnh phong bì màu đỏ thay vì hình ảnh của tôi. Tôi sẽ phải giải quyết vấn đề đó. Điều này đã loại bỏ nỗi đau khi tải BitmapImage và thay đổi nó thành Bitmap (rõ ràng đã giết chết hoạt hình của tôi vì nó không còn là gif nữa).

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);
   }
}

re: khi tôi cố gắng xử lý luồng Theo MSDN, Bitmap sử dụng Luồng phải có Luồng tồn tại trong vòng đời của Bitmap. Cách giải quyết là Freeze hoặc Clone bitmap.
Jesse Chisholm

1
Anh chỉ cần nói để thiết lập .ImageLocationthay vì .Image. Ông đã có phương pháp sai. .ImageLocationhoạt động từ gốc của dự án Visual Studio, vì vậy giả sử bạn có một Imagesthư mục, đường dẫn của bạn là sau đó imgBox.ImageLocation = "/Images/my.gif";. Nếu bạn có một thư mục được gọi là Viewsnơi bạn có Chế độ xem sẽ hiển thị hình ảnh, để sao lưu Images, bạn phải sử dụng 2 dấu chấm : imgBox.ImageLocation = "../Images/my.gif";.
vapcguy

1

Tôi đã thử tất cả các cách trên, nhưng mỗi người đều có sự ngắn gọn của mình, và nhờ tất cả các bạn, tôi đã tìm ra GifImage của riêng mình:

    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
            /// <summary>
            /// Defines whether the animation starts on it's own
            /// </summary>
            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));
            }

            /// <summary>
            /// Starts the animation
            /// </summary>
            public void StartAnimation()
            {
                    if (!_isInitialized)
                            this.Initialize();


             //   Console.WriteLine("Start: " + GifSource);

                    System.Drawing.ImageAnimator.Animate(_bitmap, OnFrameChanged);
            }

            /// <summary>
            /// Stops the animation
            /// </summary>
            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);
            }
    }
}

Sử dụng:

<localComponents:GifImage x:Name="gifImage" IsAutoStart="True" GifSource="{Binding Path=value}" />

Vì nó sẽ không gây rò rỉ bộ nhớ và nó hoạt hình dòng thời gian của hình ảnh gif, bạn có thể thử nó.


Mẫu tuyệt vời. Cần Khởi tạo cập nhật để kiểm tra IsAutoStart, nhưng nếu không, hoạt động như một nhà vô địch!
Steve Danner

1
Việc gọi một cách rõ ràng là GC.Collect () có tác động khủng khiếp đến hiệu suất.
Kędrzu

0

Trước đây, tôi gặp phải một vấn đề tương tự, tôi cần chơi .giffile trong dự án của bạn. Tôi có hai lựa chọn:

  • sử dụng PictureBox từ WinForms

  • sử dụng thư viện của bên thứ ba, chẳng hạn như WPFAnimatedGif từ codeplex.com .

Phiên bản PictureBoxkhông hoạt động với tôi và dự án không thể sử dụng các thư viện bên ngoài cho nó. Vì vậy, tôi đã làm cho chính mình thông qua Bitmapvới sự giúp đỡ ImageAnimator. Bởi vì, tiêu chuẩn BitmapImagekhông hỗ trợ phát lại các .giftập tin.

Ví dụ đầy đủ:

XAML

<Window x:Class="PlayGifHelp.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" Loaded="MainWindow_Loaded">

    <Grid>
        <Image x:Name="SampleImage" />
    </Grid>
</Window>

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));
    }
}

Bitmapkhông hỗ trợ chỉ thị URI , vì vậy tôi tải .giftệp từ thư mục hiện tại.


0

Cải tiến nhỏ của GifImage.Initialize()phương pháp, đọc thời gian khung thích hợp từ siêu dữ liệu GIF.

    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;
    }

0

Tôi không chắc chắn nếu điều này đã được giải quyết nhưng cách tốt nhất là sử dụng thư viện WpfAnimatedGid . Nó rất dễ dàng, đơn giản và dễ dàng để sử dụng. Nó chỉ yêu cầu 2 dòng mã XAML và khoảng 5 dòng Mã C # trong mã phía sau.

Bạn sẽ thấy tất cả các chi tiết cần thiết về cách này có thể được sử dụng ở đó. Đây là những gì tôi cũng đã sử dụng thay vì phát minh lại bánh xe


0

Thêm vào phản hồi chính khuyến nghị sử dụng WpfAnimatedGif , cuối cùng bạn phải thêm các dòng sau nếu bạn hoán đổi hình ảnh với Gif để đảm bảo hoạt ảnh thực sự thực thi:

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

Vì vậy, mã của bạn sẽ trông như:

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);

0

Kiểm tra mã của tôi, tôi hy vọng điều này đã giúp bạn :)

         public async Task GIF_Animation_Pro(string FileName,int speed,bool _Repeat)
                    {
    int ab=0;
                        var gif = GifBitmapDecoder.Create(new Uri(FileName), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                        var getFrames = gif.Frames;
                        BitmapFrame[] frames = getFrames.ToArray();
                        await Task.Run(() =>
                        {


                            while (ab < getFrames.Count())
                            {
                                Thread.Sleep(speed);
try
{
                                Dispatcher.Invoke(() =>
                                {
                                    gifImage.Source = frames[ab];
                                });
                                if (ab == getFrames.Count - 1&&_Repeat)
                                {
                                    ab = 0;

                                }
                                ab++;
            }
 catch
{
}

                            }
                        });
                    }

hoặc là

     public async Task GIF_Animation_Pro(Stream stream, int speed,bool _Repeat)
            {
 int ab = 0;   
                var gif = GifBitmapDecoder.Create(stream , BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                var getFrames = gif.Frames;
                BitmapFrame[] frames = getFrames.ToArray();
                await Task.Run(() =>
                {


                    while (ab < getFrames.Count())
                    {
                        Thread.Sleep(speed);
    try
    {


                     Dispatcher.Invoke(() =>
                        {
                            gifImage.Source = frames[ab];
                        });
                        if (ab == getFrames.Count - 1&&_Repeat)
                        {
                            ab = 0;

                        }
                        ab++;
    }
     catch{} 



                    }
                });
            }

0

Một thay thế cho hoạt hình chờ trong WPF là:

 <ProgressBar Height="20" Width="100" IsIndeterminate="True"/>

Nó sẽ hiển thị một thanh tiến trình hoạt hình.


1
Câu hỏi không nhất thiết phải hỏi về hoạt hình chờ đợi mà nói chung là hỏi về GIF hoạt hình nói chung. Rõ ràng, đó có thể là cho một hình ảnh động chờ đợi, trong trường hợp này có thể là một sự thay thế thích hợp. Nhưng nó có thể dễ dàng cho bất kỳ số lượng các nhu cầu truyền thông khác.
Jeremy Caney
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.