मैं क्या नियंत्रण प्रकार का उपयोग करना चाहिए - Image
, MediaElement
आदि?
मैं क्या नियंत्रण प्रकार का उपयोग करना चाहिए - Image
, MediaElement
आदि?
जवाबों:
मुझे इस सवाल का सबसे लोकप्रिय जवाब (डारियो द्वारा ऊपर) ठीक से काम करने के लिए नहीं मिला। परिणाम अजीब कलाकृतियों के साथ अजीब, तड़का हुआ एनीमेशन था। अब तक मुझे मिला सबसे अच्छा समाधान: https://github.com/XamlAnimatedGif/WpfAnimatedGif
आप इसे NuGet के साथ इंस्टॉल कर सकते हैं
PM> Install-Package WpfAnimatedGif
और इसका उपयोग करने के लिए, विंडो में एक नए नामस्थान पर जहाँ आप gif छवि जोड़ना चाहते हैं और नीचे के रूप में उपयोग करना चाहते हैं
<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" />
पैकेज वास्तव में साफ-सुथरा है, आप नीचे कुछ विशेषताओं को सेट कर सकते हैं
<Image gif:ImageBehavior.RepeatBehavior="3x"
gif:ImageBehavior.AnimatedSource="Images/animated.gif" />
और आप इसे अपने कोड में भी उपयोग कर सकते हैं:
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(fileName);
image.EndInit();
ImageBehavior.SetAnimatedSource(img, image);
EDIT: सिल्वरलाइट समर्थन
Josh2112 की टिप्पणी के अनुसार यदि आप अपने सिल्वरलाइट प्रोजेक्ट में एनिमेटेड GIF सपोर्ट जोड़ना चाहते हैं तो github.com/XamlAnimatedGif/XamlAnimatedGif का उपयोग करें
img
यहाँ क्या है ?
मैं छवि नियंत्रण का विस्तार और Gif विकोडक का उपयोग कर एक समाधान पोस्ट करता हूं। जिफ़ डिकोडर में एक फ्रेम प्रॉपर्टी होती है। मैं FrameIndex
संपत्ति को चेतन करता हूं । ईवेंट ChangingFrameIndex
स्रोत संपत्ति को फ्रेम के अनुरूप बदलता है FrameIndex
(जो कि डिकोडर में है)। मुझे लगता है कि gif में प्रति सेकंड 10 फ्रेम हैं।
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);
}
}
उपयोग उदाहरण (XAML):
<controls:GifImage x:Name="gifImage" Stretch="None" GifSource="/SomeImage.gif" AutoStart="True" />
Int32AnimationUsingKeyFrames
gf.Frames[0].MetaData.GetQuery("/grctlext/Delay")
फ्रैमरेट निरंतर है, इसलिए आपको सब के बाद कीफ्रेम की आवश्यकता नहीं है ... आप फ्रैमरेट को (दूसरी बार सैकड़ों की संख्या में फ्रेम की अवधि जो ushort देता है) के साथ पढ़ सकते हैं
मैंने भी, एक खोज की और पुराने MSDN मंचों पर सिर्फ एक धागे में कई अलग-अलग समाधान पाए। (लिंक अब काम नहीं किया इसलिए मैंने इसे हटा दिया)
निष्पादित करने के लिए सबसे सरल एक WinForms PictureBox
नियंत्रण का उपयोग करना प्रतीत होता है , और इस तरह से चला गया (थ्रेड से कुछ चीजों को बदल दिया, इसमें से अधिकांश वही)।
पहले अपनी परियोजना के लिए , और System.Windows.Forms
, के लिए एक संदर्भ जोड़ें ।WindowsFormsIntegration
System.Drawing
<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 >
फिर Window_Loaded
हैंडलर में, आप pictureBoxLoading.ImageLocation
संपत्ति को उस छवि फ़ाइल पथ पर सेट करेंगे, जिसे आप दिखाना चाहते हैं।
private void Window_Loaded(object sender, RoutedEventArgs e)
{
pictureBoxLoading.ImageLocation = "../Images/mygif.gif";
}
MediaElement
नियंत्रण है कि सूत्र में उल्लेख किया गया था, लेकिन यह भी उल्लेख किया गया है कि यह एक नहीं बल्कि भारी नियंत्रण है तो वहाँ कम से कम 2 किन्वासबित के आधार पर नियंत्रण सहित विकल्प पैदा हो गए थे, Image
, नियंत्रण तो यह सबसे सरल है।
AllowTransparency="True"
। मन में आपके लिए जो परिणाम हैं, वह एक और मामला है या नहीं। मैंने इसे स्वयं नहीं आजमाया है, लेकिन मैं शर्त लगाऊंगा कि WindowsFormsHost
यह बिल्कुल भी पारदर्शी नहीं होगा। बाकी की Window
ताकत। आपको बस यह कोशिश करनी होगी, मुझे लगता है।
इस छोटे ऐप के बारे में कैसे: पीछे कोड:
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>
<MediaElement LoadedBehavior="Play" Source="{Binding MyGifFile}" >
- MyGifFile मेरे एनिमेटेड जिफ की फ़ाइल नाम (और पथ) है।
ListBox
या बाँधने की जहमत क्यों ? मैंने इसे बिना किसी बंधन के आज़माया, स्रोत में केवल फ़ाइल पथ रखा और यह प्रकट हुआ, लेकिन चेतन नहीं हुआ। यदि मैं बाइंडिंग का उपयोग करता हूं, तो भी ListBox
, यह मेरे लिए बिल्कुल नहीं आता है - यह मुझे एक अपवाद देगा कि मेरा फ़ाइल पथ गलत है, भले ही यह वही है जिसका मैं उपयोग करते समय प्रकट होता हूं।
इसका बहुत ही सरल अगर आप उपयोग करते हैं <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" />
public string SpinnerLogoPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Assets\images\mso_spinninglogo_blue_2.gif");
:। फ़ाइल को Build = Content पर सेट करना और आउटपुट डायरेक्टरी में कॉपी करना सुनिश्चित करें।
यहाँ एनिमेटेड इमेज कंट्रोल का मेरा संस्करण है। आप छवि स्रोत निर्दिष्ट करने के लिए मानक संपत्ति स्रोत का उपयोग कर सकते हैं। मैंने इसमें और सुधार किया। मैं एक रूसी हूँ, परियोजना रूसी है इसलिए टिप्पणियाँ भी रूसी में हैं। लेकिन वैसे भी आपको टिप्पणियों के बिना सब कुछ समझने में सक्षम होना चाहिए। :)
/// <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
}
मैं इस लाइब्रेरी का उपयोग करता हूं: https://github.com/XamlAnimatedGif/WpfAnimatedGif
सबसे पहले, अपनी परियोजना में लाइब्रेरी स्थापित करें (पैकेज मैनेजर कंसोल का उपयोग करके):
PM > Install-Package WpfAnimatedGif
फिर, इस स्निपेट को 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" />
...
मुझे आशा है कि मदद मिलेगी।
मूल रूप से ऊपर एक ही PictureBox समाधान है, लेकिन इस बार कोड के साथ पीछे अपनी परियोजना में एक एंबेडेड संसाधन का उपयोग करने के लिए:
XAML में:
<WindowsFormsHost x:Name="_loadingHost">
<Forms:PictureBox x:Name="_loadingPictureBox"/>
</WindowsFormsHost>
कोड-पीछे में:
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;
}
}
मैंने माइक एशवा के कोड को संशोधित किया, और मैंने इसे बेहतर ढंग से काम किया। आप इसे 1 बार के साथ उपयोग कर सकते हैं। jpg png bmp या mutil-फ़्रेम gif। यदि आप नियंत्रण के लिए एक uri बाँधना चाहते हैं, UriSourceer को बांधें या आप किसी भी में बाइंड करना चाहते हैं मेमोरी स्ट्रीम जिसे आप सोर्स प्रॉपर बाँधते हैं जो कि एक बिटमैप है।
/// <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
}
यह एक कस्टम नियंत्रण है। आपको इसे WPF App Project में बनाने की आवश्यकता है, और स्टाइल में टेम्पलेट ओवरराइड को हटा दें।
मेरे पास यह मुद्दा था, जब तक कि मुझे पता नहीं था कि WPF4 में, आप अपने स्वयं के कीफ्रेम छवि एनिमेशन का अनुकरण कर सकते हैं। सबसे पहले, अपने एनीमेशन को छवियों की एक श्रृंखला में विभाजित करें, उन्हें "Image1.gif", "Image2, gif", और इसी तरह कुछ शीर्षक दें। अपने समाधान संसाधनों में उन छवियों को आयात करें। मैं मान रहा हूँ कि आप उन्हें चित्रों के लिए डिफ़ॉल्ट संसाधन स्थान पर रखें।
आप छवि नियंत्रण का उपयोग करने जा रहे हैं। निम्नलिखित XAML कोड का उपयोग करें। मैंने गैर-जरूरी चीजों को हटा दिया है।
<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>
आपके पोस्ट जोएल के लिए धन्यवाद, इसने मुझे एनिमेटेड GIF के लिए WPF के समर्थन की अनुपस्थिति को हल करने में मदद की। बस थोड़ा सा कोड जोड़ने के बाद से मेरे पास WinBox की स्थापना के साथ पिक्चरबॉक्सऑडिंग.मैज प्रॉपर्टी सेट करने के साथ एक समय की एक बिल्ली थी।
मुझे अपनी एनिमेटेड जिफ इमेज के बिल्ड एक्शन को "कंटेंट" के रूप में सेट करना था और आउटपुट डायरेक्टरी को कॉपी "नए" या "हमेशा" कॉपी करना था। तब मेनविंडो () में मैंने इस विधि को बुलाया। केवल मुद्दा यह है कि जब मैंने धारा को हटाने की कोशिश की, तो इसने मुझे मेरी छवि के बजाय लाल लिफाफा ग्राफिक दिया। मुझे उस समस्या को हल करना होगा। इसने एक BitmapImage को लोड करने और इसे एक बिटमैप में बदलने का दर्द दूर कर दिया (जिसने जाहिर तौर पर मेरे एनीमेशन को मार दिया क्योंकि यह अब 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);
}
}
.ImageLocation
इसके बजाय सेट करने के लिए कहने की आवश्यकता थी .Image
। उसके पास गलत तरीका था। .ImageLocation
विजुअल स्टूडियो प्रोजेक्ट की जड़ से काम करता है, इसलिए कहते हैं कि आपके पास एक Images
फ़ोल्डर है, आपका रास्ता तब है imgBox.ImageLocation = "/Images/my.gif";
। आप एक फ़ोल्डर बुलाया है, तो Views
जहाँ आप एक दृश्य है कि छवि प्रदर्शित करेगा है, अप करने के लिए वापस पाने के लिए Images
, आप 2 डॉट्स का उपयोग करना होगा: imgBox.ImageLocation = "../Images/my.gif";
।
मैंने ऊपर सभी तरह से कोशिश की है, लेकिन हर एक की अपनी कमी है, और आप सभी को धन्यवाद, मैं अपना खुद का गिफ्ट्स वर्कआउट करता हूं:
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);
}
}
}
उपयोग:
<localComponents:GifImage x:Name="gifImage" IsAutoStart="True" GifSource="{Binding Path=value}" />
के रूप में यह स्मृति रिसाव का कारण नहीं होगा और यह gif छवि को अपनी समय रेखा को एनिमेटेड करता है, आप इसे आज़मा सकते हैं।
IsAutoStart
, लेकिन अन्यथा, एक विजेता की तरह काम किया!
पहले, मुझे एक समान समस्या का सामना करना पड़ा, मुझे .gif
आपके प्रोजेक्ट में फ़ाइल चलाने की आवश्यकता थी । मेरे पास दो विकल्प थे:
WinForms से PictureBox का उपयोग करना
एक तृतीय-पक्ष लायब्रेरी का उपयोग करना, जैसे कि codeplex.com से WPFAnimatedGif ।
संस्करण PictureBox
मेरे लिए काम नहीं करता था, और परियोजना इसके लिए बाहरी पुस्तकालयों का उपयोग नहीं कर सकती थी। इसलिए मैंने इसकी Bitmap
मदद से खुद के लिए इसे बनाया ImageAnimator
। क्योंकि, मानक फ़ाइलों के BitmapImage
प्लेबैक का समर्थन नहीं करता है .gif
।
पूर्ण उदाहरण:
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));
}
}
Bitmap
URI के निर्देश का समर्थन नहीं करता है , इसलिए मैं .gif
वर्तमान निर्देशिका से फ़ाइल लोड करता हूं ।
GifImage.Initialize()
विधि का छोटा सुधार , जो जीआईएफ मेटाडेटा से उचित फ्रेम टाइमिंग पढ़ता है।
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;
}
मुझे यकीन नहीं है कि यह हल हो गया है लेकिन सबसे अच्छा तरीका WpfAnimatedGid लाइब्रेरी का उपयोग करना है । यह उपयोग करने के लिए बहुत आसान, सरल और सीधे आगे है। इसके लिए केवल XAML कोड की 2 लाइनों और पीछे कोड में C # कोड की लगभग 5 पंक्तियों की आवश्यकता होती है।
आप सभी आवश्यक विवरण देखेंगे कि यह वहां कैसे उपयोग किया जा सकता है। यह वही है जो मैंने पहिये को फिर से आविष्कार करने के बजाय इस्तेमाल किया
WpfAnimatedGif के उपयोग की अनुशंसा करने वाली मुख्य प्रतिक्रिया में जोड़ते हुए , आपको अंत में निम्नलिखित पंक्तियों को जोड़ना होगा यदि आप एनीमेशन को वास्तव में निष्पादित करने के लिए Gif के साथ एक छवि स्वैप कर रहे हैं :
ImageBehavior.SetRepeatBehavior(img, new RepeatBehavior(0));
ImageBehavior.SetRepeatBehavior(img, RepeatBehavior.Forever);
तो आपका कोड दिखेगा:
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);
मेरा कोड जांचें, मुझे आशा है कि इससे आपको मदद मिली :)
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
{
}
}
});
}
या
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{}
}
});
}
WPF में प्रतीक्षारत एनीमेशन का एक विकल्प है:
<ProgressBar Height="20" Width="100" IsIndeterminate="True"/>
यह एक एनिमेटेड प्रगति बार दिखाएगा।