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
相关产品推荐
相关产品推荐

