【问题标题】:Display images in UWA that is not from App Assets在 UWA 中显示不是来自 App Assets 的图像
【发布时间】: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.Storagebitmap.SetSourceAsync(await storageFile.OpenAsync(FileAccessMode.Read)).

标签: c# image uwp visual-studio-2017


【解决方案1】:

雷蒙德是对的!

CurrentImage = new BitmapImage();
await CurrentImage.SetSourceAsync(await image.StorageFile.OpenAsync(FileAccessMode.Read));

雷蒙德的好东西!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-12
    • 1970-01-01
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    相关资源
    最近更新 更多