Animated GIF works in Design view of VS2010, but has a runtime error?
I have been trying to get Mike Eshva's code from his answer about Animated Gifs to work, from here:
How do I get an animated gif to work in WPF?
Restated here (including translated comments):
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.Windows.Media.Animation;
using System.Windows.Media;
using System.Diagnostics;
namespace WpfBrowserApplication1 {
/// <summary>
/// Control of the "Images", which supports animated GIF.
/// </summary>
public class AnimatedImage : Image {
public AnimatedImage() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimatedImage), new FrameworkPropertyMetadata(typeof(AnimatedImage)));
}
#region Public properties
/// <summary>
/// Gets/sets the number of current frame.
/// </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();
开发者_StackOverflow中文版 } 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
}
}
Here's the XAML for my page just trying to show one animated GIF:
<Page x:Class="WpfBrowserApplication1.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:my="clr-namespace:WpfBrowserApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Grid>
<my:AnimatedImage x:Name="Wait" Source="arrows.gif" Width="16" Height="16" />
</Grid>
</Page>
In the design view of Page1, I see the animated gif happily doing what it's supposed to do, no build errors, no design errors, it just works the way it's supposed to. As soon as I start the page to make sure it works in the browser, I get the following error pointed at the line: <my:AnimatedImage x:Name="Wait" Source="arrows.gif" Width="16" Height="16" />
'Set property 'WpfBrowserApplication1.AnimatedImage.Source' threw an exception.' Line number '11' and line position '21'.
I've been trying to get this to work for awhile. What can I do to get the image to animate when the project runs?
EDIT:
You can download the whole project from my blog (Click on Steve)
This one works fine:
XAML:
<controls:GifImage x:Name="gifImage" Stretch="None" GifSource="/SomeImage.gif" AutoStart="True" />
Note:
If AutoStart is set to false, you need to call either Show() or StartAnimation() manually from your code.
C#:
public class GifImage : Image
{
#region Memmbers
private GifBitmapDecoder _gifDecoder;
private Int32Animation _animation;
private bool _isInitialized;
#endregion Memmbers
#region Properties
private int FrameIndex
{
get { return (int)GetValue(FrameIndexProperty); }
set { SetValue(FrameIndexProperty, value); }
}
private static readonly DependencyProperty FrameIndexProperty =
DependencyProperty.Register("FrameIndex", typeof(int), typeof(GifImage), new FrameworkPropertyMetadata(0, new PropertyChangedCallback(ChangingFrameIndex)));
private static void ChangingFrameIndex(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
GifImage image = obj as GifImage;
image.Source = image._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)
{
// CARLO 20100622: Reinitialize animation everytime image is changed
(sender as GifImage).Initialize();
}
#endregion Properties
#region Private Instance Methods
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;
}
#endregion Private Instance Methods
#region Public Instance Methods
/// <summary>
/// Shows and starts the gif animation
/// </summary>
public void Show()
{
this.Visibility = Visibility.Visible;
this.StartAnimation();
}
/// <summary>
/// Hides and stops the gif animation
/// </summary>
public void Hide()
{
this.Visibility = Visibility.Collapsed;
this.StopAnimation();
}
/// <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);
}
#endregion Public Instance Methods
}
精彩评论