【问题标题】:Calling Async synchronously, 'marshalled for a different thread' message同步调用异步,“为不同线程编组”消息
【发布时间】:2013-12-30 19:50:36
【问题描述】:

我有一个 XAML 格式的 Windows 8 商店应用程序。我有一个绑定到属性的图像控件,但是因为我要显示的 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()

【问题讨论】:

  • 旁注:执行网络操作的属性感觉很不对劲……万一它被调用的频率比你想象的要多呢?
  • 同意,这并不理想。但是当图像位于身份验证障碍后面时,我想不出一种方法来按需显示图像控件。 (需要在 Web 请求中使用带有身份验证令牌的特殊标头)。另外,在列表视图中,直到项目在视图中才会加载图像,这在我的情况下表现得很好。
  • 旁注:看看这个问题,因为它可能有用 - Make WPF Image load async
  • 似乎 isasync 在 Windows RT 中不起作用
  • 异常的堆栈跟踪是什么? ToImage 上的代码也可能有用。

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


【解决方案1】:

核心问题是许多 UI 类型(包括BitmapImage)都具有 UI 线程亲和性,而您当前的代码正试图在后台线程(Task.Run)上创建它们。

我建议您重新设计您的财产;无论如何,您都不应该让它阻塞 I/O 操作。我的AsyncEx library 中有一个type,它允许您将数据绑定到Task&lt;T&gt; 的结果。

您的财产变为:

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

当你想开始下载时,你可以这样做:

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

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

附: AggregateExceptionasync/await 中不正常。您看到它的唯一原因是因为您使用的是Task&lt;T&gt;.Result;如果您await 执行相同的任务,您将得到一个包裹在AggregateException 中的异常。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 我不确定你在说什么。 'LoadImage' 是您示例中的一种方法吗?如果是这样,这并不能解决问题,因为封装在另一种方法中仍然会产生此错误。
    • 我认为不会。当我试图破解类似的东西时,我就遇到过这种情况。我倾向于在我的 Windows 8 VM 上使用一个 init 方法来为我完成所有这些加载。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 2012-06-13
    • 1970-01-01
    相关资源
    最近更新 更多