替代 UI 线程上的 BitmapImage 操作?

Alternative to BitmapImage operations on the UI thread?

我想创建一个 worker class 可以检索滞后资源(例如从数据库或通过网络),并为以后在 UI 上零滞后显示做好准备. worker class 不应绑定到 UI 或 UI 线程,即它应该能够 运行 任何地方。完成后,它的输出将是一些图像容器 class 的填充数组,UI 可以轻松使用。

我的第一个想法是使用 BitmapImage class 作为图像容器;然而,它继承自 DependencyObject class,它将限制来自任何非 UI 线程的访问。正如@Filip 在这个问题的早期形式中指出的那样,这本质上并不是一个问题,但它会限制我的工作人员 class 的普遍性。

有没有更好的Windows class可以作为图像容器的基础,然后在绑定时在UI线程上转换成BitmapImage? 或者更好的方法? 这是一些伪代码来指示我正在尝试做什么,使用源图像的 URI 数组。

在工人中class

ImageContainerClass[] prepImages(Uri[] uriSet)
{
    ImageContainerClass[] iccSet = new ImageContainerClass[uriSet.Length];
    for (int i = 0; i < iccSet.Length; i++)
        iccSet[i] = new ImageContainerClass.retrieveImage(uriSet[i]); 
    return iccSet;
} 

在 UI 线程上(稍后):

BitmapImage bmi = new BitmapImage();
var image = iccSet[i].getImage();
<<some operation to set the source of bmi to the image>>
someImage.Source = bmi;

我认为将图像加载到 BitmapImage 是在平台的后台线程上进行的,因此您不需要这样做。如果需要,您可以在后台线程上使用 BitmapDecoder,然后将像素缓冲区推入 WriteableBitmap,但您不会从中获益太多。如果你真的想将所有代码强制到后台线程,那么你可以使用 DirectX 互操作,并为你的东西提供一个完全独立的后台渲染线程。

好的,这是一个似乎有效的解决方案。

以下代码将 运行 在非 UI 线程上愉快地运行:

    internal async Task<InMemoryRandomAccessStream> getImage(Uri uri)
    {
        try {
            var httpClient = new HttpClient();
            IBuffer iBuffer = await httpClient.GetBufferAsync(uri);
            byte[] bytes = iBuffer.ToArray();
            InMemoryRandomAccessStream ims = new InMemoryRandomAccessStream();
            DataWriter dataWriter = new DataWriter(ims);
            dataWriter.WriteBytes(bytes);
            await dataWriter.StoreAsync();
            ims.Seek(0);
            return ims;
        } catch (Exception e) { return null; }
    }

那么,当需要显示图片时,可以在UI线程上执行如下代码:

BitmapImage bmi = new BitmapImage();
bmi.SetSource(ims);
someImage.Source = bmi;

我相信更熟悉相关框架的人可以解决这个问题,但希望这对其他人有所帮助。感谢@Filip 让我走上正轨。