You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF异步修改Image.Source触发InvalidOperationException异常求助

WPF修改Image.Source触发InvalidOperationException的解决方法

问题核心原因

你遇到的异常本质是:BitmapFromPath方法在非UI线程创建了BitmapImage对象,WPF的Freezable类型(包括BitmapImage)自带线程亲和性——创建它的线程会持有对象所有权。即便后续通过Dispatcher.Invoke给UI元素赋值,依然会因跨线程访问被持有的对象触发异常。

另外你代码里有个小错误:调用ChangeImage时传入的路径字符串格式有误,外层多余的引号会导致路径无效,需要修正写法。

解决方案

方案1:将BitmapImage的创建与赋值都放到UI线程执行

修改Sprite类的ChangeImage方法,把Bitmap的创建逻辑也移入Dispatcher.Invoke代码块,确保整个对象在UI线程生成:

// In "Sprite" class
public void ChangeImage(string imagePath)
{
    Application.Current.Dispatcher.Invoke(() => 
    {
        var bitmap = BitmapFromPath(imagePath);
        image.Source = bitmap;
    });
}

方案2:设置BitmapImage的CacheOption为OnLoad

修改BitmapFromPath方法,添加CacheOption = BitmapCacheOption.OnLoad配置,让BitmapImage加载完成后脱离创建线程的依赖:

private BitmapImage BitmapFromPath(string path)
{
    var bitmap = new BitmapImage();
    bitmap.BeginInit();
    bitmap.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
    // 关键配置:加载完成后不再依赖创建线程
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.EndInit();
    return bitmap;
}

修正路径字符串的写法

修改LocalKill方法中调用ChangeImage的参数,去掉多余的引号:

public async void LocalKill()
{
    for (int i = 0; i < 12; i++)
    {
        sprite.ChangeImage($@"Resources\Images\Player\PlayerDeath{i % 2 + 1}.png");
        await Task.Delay(1000 / 10);
    }
}

额外说明

如果选择方案2,也可以调用bitmap.Freeze()方法冻结对象——冻结后的Freezable对象不再具有线程亲和性,可安全跨线程访问,但冻结后对象无法再修改。

内容的提问来源于stack exchange,提问作者YonatanZiv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 04:53:26