【发布时间】:2018-09-15 13:47:35
【问题描述】:
我很难在我的 UWP 应用中显示图像。 我的图片位于图片库中。
问题是: 如何在 UWP 的 Image Xaml 控件中显示不在项目“资产”中的 jpg?
到目前为止,我已经使用了 Binding
尝试将 Image.Source 设置为完整路径但没有成功,图像控件保持空白。 (对于文件访问限制的猜测)
尝试使用将 BitMapImage 设置为 Image.Source 属性没有成功,图像控件保持空白。 (对于文件访问限制的猜测)
尝试将 FileStorage 类分配给 Image.Source 属性没有成功,图像控件保持空白。
尝试在流中加载图像文件并在 BitmapImage 中加载流,但是我遇到了线程问题。更多信息请参见下文。
关于线程问题,我现在遇到了两个问题。 加载文件/流时:
var file = File.ReadAllBytes(_currentImagePath);
我明白了
System.InvalidOperationException: '不应在 UI 线程上执行同步操作。考虑将此方法包装在 Task.Run 中。'
以任何方式使用 Task.Run 时,我在尝试设置位图源时遇到异常
应用程序调用了一个为不同线程编组的接口。 (来自 HRESULT 的异常:0x8001010E (RPC_E_WRONG_THREAD))
var bitmap = new BitmapImage();
return await Task.Run(async () =>
{
var file = File.ReadAllBytes(_currentImagePath);
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(file.AsBuffer());
stream.Seek(0);
await bitmap.SetSourceAsync(stream); // **Exception here**
return bitmap;
}
});
这里是完整的源代码:
namespace App1.Images
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
using App1.Annotations;
public class ImagesLibrairies : INotifyPropertyChanged
{
private readonly HashSet<Image> _images;
private readonly string _fileTypes;
private readonly HashSet<Image> _preferrednessFiles;
private readonly DispatcherTimer _timer;
private ulong _minFileSize = 5 * 1024; // 5k in bytes
private ulong _maxFileSize = 1024 * 1024 * 20; //20 MBytes
private int _imageIndex = 0;
public ImagesLibrairies()
{
_preferrednessFiles = new HashSet<Image>();
_fileTypes = "*.jpg;*.jpeg;*.bmp;*.tif"; // ignore *.ico;*.png;*.svg;*.gif
_images = new HashSet<Image>();
_timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 5) };
_timer.Tick += _timer_Tick;
}
private Uri _currentImage;
public Uri CurrentImage
{
get => _currentImage;
private set
{
_currentImage = value;
OnPropertyChanged(nameof(CurrentImage));
OnPropertyChanged(nameof(Image));
}
}
public async Task<BitmapImage> GetBitmapImage()
{
var bitmap = new BitmapImage();
return await Task.Run(async () =>
{
var file = File.ReadAllBytes(_currentImagePath);
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(file.AsBuffer());
stream.Seek(0);
await bitmap.SetSourceAsync(stream);
return bitmap;
}
});
}
public BitmapImage Image
{
get
{
if (!string.IsNullOrEmpty(_currentImagePath))
return GetBitmapImage().Result;
return null;
}
}
private string _currentImagePath;
public string CurrentImagePath
{
get => _currentImagePath;
set
{
_currentImagePath = value;
OnPropertyChanged(nameof(CurrentImagePath));
CurrentImage = new Uri(value);
}
}
public object CurrentStorageFile { get; set; }
private void _timer_Tick(object sender, object e)
{
SetNext();
}
public async Task ScanLibrairies()
{
var picturesFolder = KnownFolders.PicturesLibrary;
var files = await picturesFolder.GetFilesAsync();
foreach (var file in files)
{
Debug.WriteLine(file.Name + ", " + file.DateCreated);
if (_images.Count >= int.MaxValue)
return;
var prop = await file.GetBasicPropertiesAsync();
var imageLocation = new Image
{
StorageFile = file,
Properties = prop
};
if (imageLocation.Properties.Size < _minFileSize || imageLocation.Properties.Size > _maxFileSize)
continue;
if (_preferrednessFiles.Any(o => o.Equals(imageLocation) && o.Preferredness == Preferredness.No))
continue;
_images.Add(imageLocation);
}
}
public void SetNext()
{
if (_images == null || !_images.Any())
{
return;
}
_imageIndex++;
var image = _images.Skip(_imageIndex).FirstOrDefault();
if (image != null)
{
Debug.WriteLine($"Displaying: {image.StorageFile.Path}");
}
CurrentImagePath = image?.StorageFile.Path;
CurrentImage = new Uri(CurrentImagePath);
}
public void SetPrevious()
{
if (_images == null || !_images.Any())
return;
_imageIndex--;
var image = _images.Skip(_imageIndex).FirstOrDefault();
CurrentImagePath = image?.StorageFile.Path;
}
public void LikeThisPicture(Image picture)
{
var pic = _preferrednessFiles.FirstOrDefault(o => o.Equals(picture));
if (pic == null)
{
picture.Preferredness = Preferredness.Very;
_preferrednessFiles.Add(picture);
return;
}
pic.Preferredness = Preferredness.Very;
}
public void DislikeThisPicture(Image picture)
{
var pic = _preferrednessFiles.FirstOrDefault(o => o.Equals(picture));
if (pic == null)
{
picture.Preferredness = Preferredness.No;
_preferrednessFiles.Add(picture);
return;
}
pic.Preferredness = Preferredness.No;
}
public void StartAsync()
{
ScanLibrairies();
_timer.Start();
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
这里是 xaml 标记
<Page.DataContext>
<images:ImagesLibrairies/>
</Page.DataContext>
<Grid >
<!--Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">-->
<Image Stretch="UniformToFill" Margin="15">
<Image.Source>
<BitmapImage UriSource="{Binding Image}"></BitmapImage>
<!--<BitmapImage UriSource="{Binding CurrentImagePath}"></BitmapImage>-->
<!--<BitmapImage UriSource="D:\Utilisateurs\hugod\OneDrive\Images\jouets\20180106_132041.jpg"></BitmapImage>-->
<!--<BitmapImage UriSource="Assets/Black-And-White-Wall-Brick-Texture-Shadow-WallpapersByte-com-3840x2160.jpg"></BitmapImage>-->
<!--<BitmapImage UriSource="{Binding CurrentStorageFile}"></BitmapImage>-->
</Image.Source>
</Image>
</Grid>
【问题讨论】:
-
是
_currentImagePath图像的绝对路径吗?是不是类似于“D:\somefolder\someimage.jpg”?如果是,您需要将该文件夹添加到future access list,因为 UWP 应用程序无法直接访问用户未明确提供访问权限的任何文件夹(当然 ApplicationData 除外)。此答案可能对您有所帮助 stackoverflow.com/questions/47344292/… -
您的代码似乎不完整。
Image不是 UWP 中的通用类型。请上传minimal reproducible example,我可以帮你诊断这个问题。 -
在我所做的测试中,是的,您提到了绝对路径。但这不是必需品,我早就可以在图像控件中显示图像了。事实上,我想为我的旧 WinRT 选项卡创建自己的相框应用程序,也许把它放在 Ms Store
-
不要使用
System.IO.File;使用Windows.Storage。bitmap.SetSourceAsync(await storageFile.OpenAsync(FileAccessMode.Read)).
标签: c# image uwp visual-studio-2017