Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.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# 使用MVVM在WPF中异步加载图像_C#_Wpf_Mvvm_Async Await - Fatal编程技术网

C# 使用MVVM在WPF中异步加载图像

C# 使用MVVM在WPF中异步加载图像,c#,wpf,mvvm,async-await,C#,Wpf,Mvvm,Async Await,我正在制作一个应用程序,从本地目录或文件名列表加载多个图像。我是WPF和MVVM的新手,在并发方面从来没有这么出色过。所以我的问题是,我的代码中缺少了什么使图像异步加载 public class ThumbnailGridViewModel : ViewModelBase { public ObservableCollection<Picture> Pictures { get { if (_filterOn)

我正在制作一个应用程序,从本地目录或文件名列表加载多个图像。我是WPF和MVVM的新手,在并发方面从来没有这么出色过。所以我的问题是,我的代码中缺少了什么使图像异步加载

public class ThumbnailGridViewModel : ViewModelBase
{
    public ObservableCollection<Picture> Pictures
    {
        get
        {
            if (_filterOn)
            {
                return new ObservableCollection<Picture>(
                    _pictures.Where(pic => pic.ImageName.Contains(_searchFilter)).ToList());
            }
            else
            {
                return _pictures;
            }
        }
        set
        {
            _pictures = value;
            NotifyPropertyChanged();
        }
    }

    public ThumbnailGridViewModel(IDialogService modalDialog)
    {
        //...

        Messenger.Default.Register<ObservableCollection<Picture>>(this, OnPicturesLoaded);
        //...
    }

    private void OnPicturesLoaded(ObservableCollection<Picture> pictures)
    {
        Pictures = pictures;
    }
}

public class VepixWindowViewModel : ViewModelBase
{
    private async void OnOpenFolder(SearchOption option)
        {
            FolderBrowserDialog folderDialog = new FolderBrowserDialog();
            if (folderDialog.ShowDialog() == DialogResult.OK)
            {
                List<Picture> pictures = await (_pictureRepo.GetPicturesFromFolderAsync(folderDialog.SelectedPath, option));
                Messenger.Default.Send(new ObservableCollection<Picture>(pictures));
            }
        }

    private async void OnOpenFiles()
    {
        OpenFileDialog fileDialog = new OpenFileDialog()
        {
            Multiselect = true,
            Filter = "Image Files|*.jpg;*.jpeg;*.png;*.gif"
        };
        if (fileDialog.ShowDialog() == DialogResult.OK)
        {
            List<Picture> pictures = await (_pictureRepo.GetPicturesAsync(fileDialog.FileNames));
            Messenger.Default.Send(new ObservableCollection<Picture>(pictures));
        }
    }
}

public class PictureRepository : IPictureRepository
{
    public PictureRepository()
    {
        _fileService = new FileService();
    }

    public async Task<List<Picture>> GetPicturesAsync(string[] files)
    {
        var fileBytes = await _fileService.ReadBytesFromFilesAsync(files.ToList());
        return await LoadPicturesAsync(fileBytes);
    }

    public async Task<List<Picture>> GetPicturesFromFolderAsync(string folderPath, SearchOption option)
    {
        var fileBytes = await _fileService.GetFilesAndBytesFromDirectoryAsync(folderPath, _supportedImagesFilterList, option);
        return await LoadPicturesAsync(fileBytes);
    }

    private Task<List<Picture>> LoadPicturesAsync(Dictionary<string, byte[]> fileBytes)
    {
        return Task.Factory.StartNew<List<Picture>>(() =>
        {
            List<Picture> pictures = new List<Picture>();
            Parallel.ForEach(fileBytes, file =>
            {
                 pictures.Add(new Picture(BitmapService.ConvertByteArrayToBitmapImage(file.Value), file.Key));
            });
            return pictures;
        });
    }
}

public class FileService : IFileService
{
    public async Task<Dictionary<string, byte[]>> GetFilesAndBytesFromDirectoryAsync(string path, List<string> searchPattern, SearchOption option)
    {
        var files = new List<string>();
        if (Directory.Exists(path))
        {
            await Task.Factory.StartNew(() =>
                searchPattern.ForEach( sp =>
                    files.AddRange(Directory.GetFiles(path, sp, option))));
        }

        return await ReadBytesFromFilesAsync(files);
    }

    public byte[] ReadBytesFromFile(string file)
        => File.ReadAllBytes(file);

    public async Task<Dictionary<string, byte[]>> ReadBytesFromFilesAsync(List<string> files)
    {
        //todo: i think i will change this return type to just List<byte[]>
        var bytes = new Dictionary<string, byte[]>();
        await Task.Factory.StartNew(() =>
            files.ForEach(file => bytes.Add(file, ReadBytesFromFile(file))));

        return bytes;
    }
}

public static class BitmapService
{
    public static BitmapImage ConvertByteArrayToBitmapImage(Byte[] bytes)
    {
        var image = new BitmapImage();
        using (var stream = new MemoryStream(bytes))
            {
                stream.Seek(0, SeekOrigin.Begin);
                image.BeginInit();
                image.StreamSource = stream;
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.EndInit();
                image.Freeze();
            }

        return image;
    }
}
公共类ThumbnailGridViewModel:ViewModelBase
{
公众可观察收集图片
{
得到
{
如果(_filterOn)
{
返回新的ObservableCollection(
_pictures.Where(pic=>pic.ImageName.Contains(_searchFilter)).ToList();
}
其他的
{
返回图片;
}
}
设置
{
_图片=价值;
NotifyPropertyChanged();
}
}
公共ThumbnailGridViewModel(IDialogService modalDialog)
{
//...
Messenger.Default.Register(此,OnPicturesLoaded);
//...
}
已加载图片上的私有void(可观察收集图片)
{
图片=图片;
}
}
公共类VepixWindowViewModel:ViewModelBase
{
专用异步void OnOpenFolder(SearchOption选项)
{
FolderBrowserDialog folderDialog=新建FolderBrowserDialog();
如果(folderDialog.ShowDialog()==DialogResult.OK)
{
List pictures=wait(_pictureRepo.GetPicturesFromFolderAsync(folderDialog.SelectedPath,option));
senger.Default.Send(新的ObservableCollection(图片));
}
}
私有异步void OnOpenFiles()
{
OpenFileDialog fileDialog=新建OpenFileDialog()
{
Multiselect=true,
Filter=“图像文件|*.jpg;*.jpeg;*.png;*.gif”
};
if(fileDialog.ShowDialog()==DialogResult.OK)
{
List pictures=wait(_pictureRepo.GetPicturesAsync(fileDialog.FileNames));
senger.Default.Send(新的ObservableCollection(图片));
}
}
}
公共类PictureRepository:IPictureRepository
{
公共图片存储
{
_fileService=newfileservice();
}
公共异步任务GetPicturesAsync(字符串[]文件)
{
var fileBytes=wait_fileService.readbytesfromfileasync(files.ToList());
返回等待加载图片同步(fileBytes);
}
公共异步任务GetPicturesFromFolderAsync(字符串folderPath,搜索选项)
{
var fileBytes=await _fileService.getfilesandbytesfromtirectoryasync(folderPath,_supportedImagesFilterList,option);
返回等待加载图片同步(fileBytes);
}
专用任务加载图片同步(字典文件字节)
{
返回Task.Factory.StartNew(()=>
{
列表图片=新列表();
Parallel.ForEach(fileBytes,file=>
{
添加(新图片(BitmapService.ConvertByteArrayToBitmapImage(file.Value),file.Key));
});
返回图片;
});
}
}
公共类文件服务:IFileService
{
公共异步任务GetFilesandBytesFromDirectorySync(字符串路径、列表搜索模式、搜索选项)
{
var files=新列表();
if(目录存在(路径))
{
等待任务。工厂。开始新建(()=>
searchPattern.ForEach(sp=>
files.AddRange(Directory.GetFiles(path、sp、option));
}
返回wait readbytesfromfileasync(文件);
}
公共字节[]ReadBytesFromFile(字符串文件)
=>File.ReadAllBytes(文件);
公共异步任务ReadBytesFromFileAsync(列出文件)
{
//todo:我想我会将此返回类型更改为仅列表
var bytes=新字典();
等待任务。工厂。开始新建(()=>
files.ForEach(file=>bytes.Add(file,ReadBytesFromFile(file)));
返回字节;
}
}
公共静态类位图服务
{
公共静态BitmapImage ConvertByteArrayToBitmapImage(字节[]字节)
{
var image=新的位图图像();
使用(变量流=新内存流(字节))
{
stream.Seek(0,SeekOrigin.Begin);
image.BeginInit();
image.StreamSource=流;
image.CacheOption=BitmapCacheOption.OnLoad;
image.EndInit();
image.Freeze();
}
返回图像;
}
}

在不检查所有代码的情况下,在
ConvertByteArrayToBitmapImage
方法中,您应该在调用
EndInit
之前设置
image.CacheOption=BitmapCacheOption.OnLoad
,并处理内存流(理想情况下使用
块将其放入
中)。@Clemens,感谢您的输入。我已经做了更改。您也可以调用
image.Freeze()
使其跨线程访问。然后您可以在
调度程序外部调用
convertbytearrayotobitmapimage
。调用
@Clemens,再次感谢。我认为我不再需要Dispatcher.Invoke()了,所以我去掉了它。我现在离实现异步越来越近了。似乎只有当集合添加到“图片收藏”属性时,UI才会冻结。我需要进一步调查。