2

画像の読み込みで UI スレッドがブロックされるという問題が発生しているため、Windows ストア アプリでグリッドビューが応答しません。

私がやろうとしているのは、グリッドビューの画像がビューモデルの画像プロパティにバインドされるようにすることです。image プロパティの値は async メソッドによって設定されます。アプリが起動すると、すべてのオブジェクトが読み込まれますが、実際の画像データは読み込まれません。画像データは、UI 仮想化が開始され、xaml の画像コントロールにバインドされた画像プロパティを介して画像データを要求するときに読み込まれます。

これはすべて、観察可能なコレクションで行われます。

ここにいくつかのコードがあります:

    private ImageSource _image = null;
    private String _imagePath = null;
    public ImageSource Image
    {
        get
        {
            SetImageFromStorageFile().ContinueWith(OnAsyncFail, TaskContinuationOptions.OnlyOnFaulted);
            return this._image;
        }
    }

    private async Task SetImageFromStorageFile()
    {
        this.IsLoading = true;
        if (this._image == null && this._imagePath != null)
        {
                this._image = await BitmapLoader.GetPreviewImageFromStorageFile(this.StorageFile); //getting the actual data here
                this.OnPropertyChanged("Image");
        }
        this.IsLoading = false;
    }

これは、画像データにアクセスするときに UI が応答しなくなることを除いて、すべて正常に機能しています。

ご覧のとおり、プロパティから非同期メソッドを呼び出しています。他の場所から呼び出したコードを再利用しているだけです。他の場所から呼び出された場合、await を使用でき、UI はレスポンシブです。問題は、gridviews UI 仮想化を使用する場合、UI をブロックせずにこの非同期メソッドを実行する方法がわからないことです (私が知る限り) プロパティを非同期で実行することはできません。

したがって、グリッドビューでこのプロパティ(またはメソッド)を同期ではなく非同期で実行したいだけですが、その方法がわかりません。

助けてください :)

4

2 に答える 2

1
private ImageSource _image = null;
private String _imagePath = null;
public ImageSource Image
{
    get
    {
        if (_image != null)
          return _image;
        if (_imagePath != null && !IsLoading)
          SetImageFromStorageFile();
        return null;
    }
}

private async void SetImageFromStorageFile()
{
    if (this.IsLoading || this._image != null || this._imagePath == null)
      return;
    this.IsLoading = true;
    try
    {
      this._image = await BitmapLoader.GetPreviewImageFromStorageFile(this.StorageFile); //getting the actual data here
      this.IsLoading = false;
      this.OnPropertyChanged("Image");
    }
    catch 
    {
      OnAsyncFail();
    }
}
于 2013-11-13T02:54:11.420 に答える
0

Whatever strategy you choose, you need to return something first and fill it later. This is a sample which has been tested in a vanilla WinRT page; you can duplicate it by dropping it onto a page with an Image named image and a TextBlock named status. This can go in OnNavigatedTo, or another appropriate place.

BitmapImage imgsrc = new BitmapImage();
Task.Run(async () =>
    {
        await Task.Delay(10000);
        await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
            new Windows.UI.Core.DispatchedHandler(() =>
                {
                    imgsrc.UriSource = new Uri("http://www.gratuit-en-ligne.com/telecharger-gratuit-en-ligne/telecharger-image-wallpaper-gratuit/image-wallpaper-animaux/img/images/image-wallpaper-animaux-autruche.jpg");
                }));
    });
image.Source = imgsrc;
status.Text = "Done";

The thing I am "returning" is a BitmapImage, which is a subclass of ImageSource, so it's close to what you will want to use. The Task.Delay() is just to introduce obvious lag between startup and image population, so that you can see that the status text is set well before the image is loaded.

To make this work with your sample, you will need to create (or access) an ImageSource in your property and return it immediately, without waiting for it to be filled. Then you start off a background task that assigns the actual source data.

The actual chain of causation could be different than what I show here. You could, for instance, access the ImageSources from a pre-created collection of them. This would allow you to start loading the images before the property is ever called. But it sounds like this will be a start to get you moving in the right direction.

于 2013-11-13T02:16:07.960 に答える