同步调用异步,“为不同的线程编组”消息

时间:2013-12-29 18:37:54

标签: c# windows-runtime async-await synchronous

我在XAML中有一个Windows 8商店应用程序。我有一个绑定到属性的Image控件,但由于我想要显示的URL需要身份验证,我必须创建一个webresponse并以这种方式生成位图,而不是仅仅为我的图像控件提供一个URL。

问题是,内存流操作是异步的,对象的属性必须是同步的,而不是异步的。所以我有一个非常简单的设置:

public ImageSource ImageSource
{
    get { return Task.Run(() => BitmapImageUtils.ToImage(this.Upload.ThumbFile)).Result; }

并且Image控件将ImageSource属性作为其绑定。问题是,我收到以下异常。 ListView中有多个Image控件,它们都是以这种方式绑定的,我的猜测是调用它的UI线程以某种方式将控制交给一个线程然后尝试以某种方式返回。我对此有点新鲜。

该应用程序调用了一个为不同线程编组的接口。 (来自HRESULT的异常:0x8001010E(RPC_E_WRONG_THREAD))

感谢任何帮助。

---编辑 ToImage方法

public static async Task<BitmapImage> ToImage(byte[] byteArray)
    {
        var bitmapImage = new BitmapImage();

        var stream = new InMemoryRandomAccessStream();
        await stream.WriteAsync(byteArray.AsBuffer());
        stream.Seek(0);

        await bitmapImage.SetSourceAsync(stream);
        return bitmapImage;
    }

异常(注意异常是聚合异常的内部异常,我认为这是异步/等待异常的标准

at Windows.UI.Xaml.Media.Imaging.BitmapImage..ctor()
at Campfire.Utils.BitmapImageUtils.<ToImage>d__0.MoveNext()

2 个答案:

答案 0 :(得分:4)

核心问题是许多UI类型(包括BitmapImage)具有UI线程关联,并且您当前的代码正在尝试在后台线程上创建它们(在Task.Run中)。

我建议你重新设计你的财产;你不应该在I / O操作上阻塞它。我的type中有一个AsyncEx library,可让您基本上数据绑定到Task<T>的结果。

您的财产变为:

public INotifyTaskCompletion<ImageSource> ImageSource { get; private set; }

如果您想开始下载,请执行以下操作:

ImageSource = NotifyTaskCompletion.Create(BitmapImageUtils.ToImage(Upload.ThumbFile)));

然后,您的数据绑定会从ImageSource更改为ImageSource.Result。还有其他属性(例如,ImageSource.IsFaultedImageSource.ErrorMessage)允许您使用数据绑定处理其他结果。请注意,INotifyTaskCompletion<T>.Result 阻止;它将只返回默认值,直到任务完成。

P.S。 AggregateException / asyncawait不正常。你看到它的唯一原因是你使用Task<T>.Result;如果您await执行相同的任务,则会在AggregateException中收到 not 的异常。

答案 1 :(得分:0)

为什么不在具有属性的对象上添加LoadImage,并以异步方式进行加载。一旦完成加载,它就可以正常设置ImageSource属性。