wpf 如何在BitmapImage下载完成时获得通知?

o75abkj4  于 2023-06-24  发布在  其他
关注(0)|答案(2)|浏览(164)

我正在编写一个类,它可以从本地文件或Web链接异步加载BitmapImage。我使用DownloadCompleted和DownloadFailed事件等待BitmapImage结束下载,然后冻结它并将其从工作线程传递到UI线程。但是我的代码不起作用,如果我将Web链接设置为BitmapImage的UriSource,这些事件处理程序将永远不会被调用。然而,我注意到WPF Image控件可以在其源代码(BitmapImage)完全下载并显示它时得到通知,所以我猜一定有一些我不知道的方式来获得通知时,BitmapImage完成加载。有人知道吗?下面是我的代码:

BitmapImage image = await Task.Run(async () =>
{
    BitmapImage image = new BitmapImage();
    image.BeginInit();
    image.CacheOption = BitmapCacheOption.OnLoad;
    image.UriSource = uri;
    image.EndInit();

    if (image.IsDownloading)
    {
        using EventWaitHandle handle = new EventWaitHandle(
            false, EventResetMode.ManualReset);

        void RemoveEventHandler()
        {
            image.DownloadCompleted -= OnDownloadCompleted;
            image.DownloadFailed -= OnDownloadFailed;
        }

        void OnDownloadCompleted(object? sender, EventArgs args)
        {
            handle.Set();
            RemoveEventHandler();
        }

        void OnDownloadFailed(object? sender, EventArgs args)
        {
            handle.Set();
            RemoveEventHandler();
        }

        image.DownloadCompleted += OnDownloadCompleted;
        image.DownloadFailed += OnDownloadFailed;
        await Task.Run(handle.WaitOne);
    }

    image.Freeze();
    return image;
});
eqqqjvef

eqqqjvef1#

您应该在设置UriSource和下载开始之前连接事件处理程序。这对我很有效:

BitmapImage image = new BitmapImage();
image.DownloadCompleted += OnDownloadCompleted;
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new System.Uri("https://someurl/pic.jpg");
image.EndInit();

void OnDownloadCompleted(object? sender, EventArgs args)
{
    BitmapImage image = (BitmapImage)sender;
    image.DownloadCompleted -= OnDownloadCompleted;
    //...
}
sqougxex

sqougxex2#

看起来DownloadCompletedDownloadFailed事件是are not fired in a background thread,因此您不能轻松地将代码 Package 在Task.Run调用中。
除此之外,您可以在这样的方法中使用TaskCompletionSource,而不是等待EventWaitHandle

private async Task<BitmapImage> LoadBitmapImageAsync(Uri uri)
{
    var image = new BitmapImage();
    image.BeginInit();
    image.CacheOption = BitmapCacheOption.OnLoad;
    image.UriSource = uri;
    image.EndInit();

    if (image.IsDownloading)
    {
        var tcs = new TaskCompletionSource();

        void OnDownloadCompleted(object sender, EventArgs args)
        {
            tcs.TrySetResult();
            RemoveEventHandlers();
        }

        void OnDownloadFailed(object sender, ExceptionEventArgs args)
        {
            tcs.TrySetException(args.ErrorException);
            RemoveEventHandlers();
        }

        void RemoveEventHandlers()
        {
            image.DownloadCompleted -= OnDownloadCompleted;
            image.DownloadFailed -= OnDownloadFailed;
        }

        image.DownloadCompleted += OnDownloadCompleted;
        image.DownloadFailed += OnDownloadFailed;

        await tcs.Task;
    }

    image.Freeze();
    return image;
}

但是,您可以手动下载图像,如下所示:

private Task<BitmapImage> LoadBitmapImageAsync(Uri uri)
{
    return Task.Run(async () =>
    {
        var httpClient = new HttpClient();
        var responseStream = await httpClient.GetStreamAsync(uri);
        var image = new BitmapImage();

        using (var memoryStream = new MemoryStream())
        {
            await responseStream.CopyToAsync(memoryStream);

            image.BeginInit();
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.StreamSource = memoryStream;
            image.EndInit();
            image.Freeze();
        }

        return image;
    });
}

相关问题