将许多图像下载到列表框

时间:2012-09-01 07:37:42

标签: c# windows-phone-7

我正在编写Windows Phone应用程序,无法理解模拟器崩溃的原因。它说:“XDE.exe中0x773415de处的未处理异常:0xC0000005:访问违规读取位置0x05190000。”仅当我开始快速滚动列表框时才会出现此问题。我将每20个项目加载到列表框(所有项目的数量为200)。问题在于我的下载图像类。我为服务器创建了每个映像的Webclient请求,或者最好创建一个线程池吗?

在XAML中:

<Image Name="userPic" Margin="0,8,1,2"
                            DelayFix:LowProfileImageLoader.UriSource="{Binding photoUrl}" Stretch="Fill"
                            Width="60"
                            Height="60"/>

downloadImage类:

using System;
using System.Net;
using System.Windows.Resources;
using System.Windows.Media.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone;
using System.Diagnostics;

namespace PhoneApp
{
    public class downloadImage
    {
        public int ImageIndex;

        public string ImageURL;

        public Boolean Downloaded;


        public BitmapImage Bitmap;

        public Image destinationImage; 

        private WebClient client;

        public delegate void FileCompleteHandler(object sender);
        public event FileCompleteHandler FileCompleteEvent;

        private static readonly object _syncBlock = new object();

        public downloadImage(int index, string imageURL, Image destinationImage = null)
        {
            this.ImageIndex = index;
            this.ImageURL = imageURL;
            this.destinationImage = destinationImage;
        }

        public void Download()
        {
            client = new WebClient();
            client.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
            client.OpenReadAsync(new Uri(this.ImageURL, UriKind.Absolute));
        }

        private void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
                if (e.Error == null && e.Result != null)
                {
                    Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        StreamResourceInfo sri = new StreamResourceInfo(e.Result as Stream, null);


                        if (destinationImage == null)
                        {
                            this.Bitmap = new BitmapImage();
                            this.Bitmap.SetSource(sri.Stream);
                        }
                        else
                        {
                            this.destinationImage.Source = PictureDecoder.DecodeJpeg(e.Result);
                        }

                        this.Downloaded = true;

                        if (FileCompleteEvent != null)
                            FileCompleteEvent(this);      
                    }));
                }
        }
    }
}

我班上的代码:

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Diagnostics;
using System.ComponentModel;
using Microsoft.Phone;
using Microsoft.Phone.Info;

namespace DelayFix
{
    /// <summary>
    /// Provides access to the Image.UriSource attached property which allows
    /// Images to be loaded by Windows Phone with less impact to the UI thread.
    /// </summary>
    public static class LowProfileImageLoader
    {
        private static readonly object _syncBlock = new object();
        private static bool _exiting;

        /// <summary>
        /// Gets the value of the Uri to use for providing the contents of the Image's Source property.
        /// </summary>
        /// <param name="obj">Image needing its Source property set.</param>
        /// <returns>Uri to use for providing the contents of the Source property.</returns>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "UriSource is applicable only to Image elements.")]
        public static Uri GetUriSource(Image obj)
        {
            if (null == obj)
            {
                throw new ArgumentNullException("obj");
            }
            return (Uri)obj.GetValue(UriSourceProperty);
        }

        /// <summary>
        /// Sets the value of the Uri to use for providing the contents of the Image's Source property.
        /// </summary>
        /// <param name="obj">Image needing its Source property set.</param>
        /// <param name="value">Uri to use for providing the contents of the Source property.</param>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "UriSource is applicable only to Image elements.")]
        public static void SetUriSource(Image obj, Uri value)
        {
            if (null == obj)
            {
                throw new ArgumentNullException("obj");
            }
            obj.SetValue(UriSourceProperty, value);
        }

        /// <summary>
        /// Identifies the UriSource attached DependencyProperty.
        /// </summary>
        public static readonly DependencyProperty UriSourceProperty = DependencyProperty.RegisterAttached(
            "UriSource", typeof(Uri), typeof(LowProfileImageLoader), new PropertyMetadata(OnUriSourceChanged));

        /// <summary>
        /// Gets or sets a value indicating whether low-profile image loading is enabled.
        /// </summary>
        public static bool IsEnabled { get; set; }

        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline", Justification = "Static constructor performs additional tasks.")]
        static LowProfileImageLoader()
        {
            Debug.WriteLine("Limit Memory:" + DeviceStatus.ApplicationMemoryUsageLimit / 1024 / 1024);
        }

        private static void HandleApplicationExit(object sender, EventArgs e)
        {
            Debug.WriteLine("Exit!");
        }



        private static void OnUriSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            lock (_syncBlock)
            {
                var image = (Image)o;
                var uri = (Uri)e.NewValue;

                Debug.WriteLine("Memory:" + DeviceStatus.ApplicationCurrentMemoryUsage / 1024 / 1024);

                if (DesignerProperties.IsInDesignTool || !uri.IsAbsoluteUri)
                {
                    image.Source = PhoneAppVKContest.ImageUtils.getJpegImage(uri.OriginalString);
                }
                else
                {
                    PhoneAppVKContest.downloadImage di = new PhoneAppVKContest.downloadImage(0, uri.AbsoluteUri);
                    di.destinationImage = image;
                    di.FileCompleteEvent += new PhoneAppVKContest.downloadImage.FileCompleteHandler(di_FileCompleteEvent);
                    di.Download();
                }
            }
        }

        static void di_FileCompleteEvent(object sender)
        {
            Debug.WriteLine("Download success!");
        }
    }
}

1 个答案:

答案 0 :(得分:0)

当您为每个图像创建webClient请求时,当webClient受到所有请求的轰炸时,可能会发生冲突。您需要通过队列顺序排序请求。如果队列的第一个元素中的图像已经在缓存或IS中,请将其链接,否则检查webclient是否繁忙。如果忙,则将其发送到队列的末尾。并检查下一张图片。如果不忙,请提交下载请求。这是我遵循的方法。您还可以考虑为每个图像绑定Imagesource,以防止在页面重新加载时自动重新加载或由于滚动缓存中的问题。我希望这个答案可以帮助你。