0

Windows Phone アプリケーションを作成していますが、エミュレーターがクラッシュする理由がわかりません。0x773415de「 XDE.exeで未処理の例外: 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"/>

ダウンロード画像クラス:

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!");
        }
    }
}
4

1 に答える 1

0

画像ごとに webClient リクエストを作成している場合、webClient にすべてのリクエストが殺到すると、競合が発生する可能性があります。キューを介してリクエストを順番に並べる必要があります。キューの最初の要素の画像が既にキャッシュまたは IS にある場合は、それをリンクします。そうでない場合は、webclient がビジーかどうかを確認します。ビジーの場合は、キューの最後に送信します。そして、次の画像を確認します。ビジーでない場合は、ダウンロード リクエストを送信します。これは私が従った方法です。ページのリロード時またはスクロール キャッシュの問題による自動リロードを防ぐために、各画像の Imagesource をバインドすることも検討してください。この回答がお役に立てば幸いです。

于 2012-09-01T21:03:29.680 に答える