Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么foreach循环中的OpenReadAsync会挂起UI线程?_C#_Win Universal App - Fatal编程技术网

C# 为什么foreach循环中的OpenReadAsync会挂起UI线程?

C# 为什么foreach循环中的OpenReadAsync会挂起UI线程?,c#,win-universal-app,C#,Win Universal App,我正在为UWP开发一个应用程序 我需要加载一个包含大约700张小图片的文件夹。这是我用来将图片加载到内存中的方法: 专用异步任务LoadPicturesAsync() { var pictureList=新的可观察集合{}; ForEach(异步文件=> { var img=新的位图图像(); 图片列表添加(img); var stream=await file.OpenReadAsync(); 等待img.SetSourceAsync(流); }); 返回图片列表; } 当我的视图模型的构造

我正在为UWP开发一个应用程序

我需要加载一个包含大约700张小图片的文件夹。这是我用来将图片加载到内存中的方法:

专用异步任务LoadPicturesAsync()
{
var pictureList=新的可观察集合{};
ForEach(异步文件=>
{
var img=新的位图图像();
图片列表添加(img);
var stream=await file.OpenReadAsync();
等待img.SetSourceAsync(流);
});
返回图片列表;
}
当我的视图模型的构造函数调用此方法时,视图似乎被阻塞(无响应)约6秒钟

这很奇怪,因为所有IO操作都是异步完成的,UI线程中唯一运行的是在foreach循环中创建BitmapImage对象。这是如此之快,它不应该阻止UI线程

我的问题是:为什么UI线程在知道我异步运行所有IO操作的情况下阻塞了6秒钟?如何解决这个问题,使UI线程不被阻塞

我就是这样称呼这个方法的:

private async Task Init()
{
PictureList=等待加载PicturesAsync();
}
//建造师
公共维护模型(){
Init();
}
为什么会这样

因为您在使用列表的ForEach方法并向其中传递异步操作,所以尝试并发运行这么多线程。用for-each替换ForEach,你会没事的

private async Task<ObservableCollection<ImageSource>> LoadPicturesAsync() {        
    foreach (var file in pictureFiles) {
       var stream = await file.OpenReadAsync();
       var image = new BitmapImage(); 
       await image.SetSourceAsync(stream);
       pictureList.Add(image );
    }
}       

private async Task Init() {
    PictureList = await LoadPicturesAsync();
}
由于Init返回一个任务,您需要注意,在构造完成时,PictureList属性/字段可能不会设置,因此如果您在实例化后立即尝试访问它,则可能会遇到NullReferenceException

MainViewModel viewModel = new MainViewModel();
var pics = viewModel.PictureList;
var count = pics.Count; // High chance of NullReferenceException

为了避免这种情况,可以考虑为视图模型定义静态CreateAsync方法。可以找到更多信息

为什么会这样

因为您在使用列表的ForEach方法并向其中传递异步操作,所以尝试并发运行这么多线程。用for-each替换ForEach,你会没事的

private async Task<ObservableCollection<ImageSource>> LoadPicturesAsync() {        
    foreach (var file in pictureFiles) {
       var stream = await file.OpenReadAsync();
       var image = new BitmapImage(); 
       await image.SetSourceAsync(stream);
       pictureList.Add(image );
    }
}       

private async Task Init() {
    PictureList = await LoadPicturesAsync();
}
由于Init返回一个任务,您需要注意,在构造完成时,PictureList属性/字段可能不会设置,因此如果您在实例化后立即尝试访问它,则可能会遇到NullReferenceException

MainViewModel viewModel = new MainViewModel();
var pics = viewModel.PictureList;
var count = pics.Count; // High chance of NullReferenceException

为了避免这种情况,可以考虑为视图模型定义静态CreateAsync方法。可以找到更多信息。

如何/在何处调用Init()?视图模型construcor在哪里?您是否尝试在构造函数中仅创建新集合:
PictureList=new ObservableCollection()…等待img.SetSourceAsync(stream);PictureList.Add(img);
-更改顺序)pictureFiles是什么类型的
图片文件,它来自哪里?@Romasz查看我更新的问题。@GediminasMasaitis这是存储文件的列表objects@Romasz看不到任何更新?如何/在何处调用Init()?视图模型construcor在哪里?您是否尝试在构造函数中仅创建新集合:
PictureList=new ObservableCollection()…等待img.SetSourceAsync(stream);PictureList.Add(img);
-更改顺序)pictureFiles是什么类型的
图片文件,它来自哪里?@Romasz查看我更新的问题。@GediminasMasaitis这是存储文件的列表objects@Romasz看不到任何更新?我的init方法正在ui线程中运行,但它会立即返回,其余的工作(将文件读取到流)是异步的,所以它不应该阻止UI,对吗?创建700个BitmapSource对象速度很快,不会阻塞UI。是文件的加载导致了这个问题。剩下的工作在ui上运行,但速度足够快,不会阻塞6秒钟。它只是创建空对象并将它们添加到列表中。从文件读取和加载图像不会在UI线程上运行。另外,关于您的答案,在我的代码版本中,创建BitmapImage对象已在UI线程上运行。在UI中创建对象和在后台加载对象之间的分离是我的代码已经在做的。我的init方法在UI线程中运行,但它会立即返回,其余工作(将文件读取到流)是异步的,所以它不应该阻止UI,对吗?创建700个BitmapSource对象速度很快,不会阻塞UI。是文件的加载导致了这个问题。剩下的工作在ui上运行,但速度足够快,不会阻塞6秒钟。它只是创建空对象并将它们添加到列表中。从文件读取和加载图像不会在UI线程上运行。另外,关于您的答案,在我的代码版本中,创建BitmapImage对象已在UI线程上运行。在UI中创建对象和在后台加载对象之间的分离是我的代码已经在做的事情。