如何在TableView的ViewCell中绑定从磁盘加载的图像?

时间:2017-05-18 14:11:18

标签: c# xamarin.android xamarin.forms

这就是我正在做的事情:

我将占位符图片设置为我的ViewCell的子类Image。

然后,从磁盘加载图片替换占位符

这适用于占位符,但是,从磁盘设置图像(正确显示)后,如果我滚出视图然后返回我得到了这个错误:

Cannot access a disposed object.
Object name: 'Stream has been closed'.

StackTrace:

at System.IO.FileStream.Read (System.Byte[] array, System.Int32 offset, System.Int32 count) [0x0000d] in <d18287e1d683419a8ec3216fd78947b9>:0 
at Android.Runtime.InputStreamAdapter.Read (System.Byte[] bytes, System.Int32 offset, System.Int32 length) [0x00006] in <33e6e739ac344166b157e323586f11a1>:0 
at Java.IO.InputStream.n_Read_arrayBII (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_b, System.Int32 off, System.Int32 len) [0x00019] in <33e6e739ac344166b157e323586f11a1>:0 
at (wrapper dynamic-method) System.Object:c31b04e7-d4e0-4108-9aaf-784714d6a934 (intptr,intptr,intptr,int,int)

我的ViewModel:

ImageSource profilePhoto = ImageSource.FromFile(FileNames.ProfilePlaceholderPNG);
public ImageSource ProfilePhoto
{
    get { return profilePhoto; }
    set {  profilePhoto = value; OnPropertyChanged(); }
}


public async Task LoadProfilePhoto()
{
    // Set placeholder first
    ProfilePhoto = ImageSource.FromFile(FileNames.ProfilePlaceholderPNG);

    // Attemp to load existing photo
    var photo = await Storage.Current.GetPhoto(FileNames.ProfilePictureJPG);
    if (photo != null)
    {
        ProfilePhoto = photo;
    }

}

Page.xaml.cs

private async Task SetTableView()
{

    var profileCell = new UserProfileCell();
    profileCell.Photo.BindingContext = viewModel;
    profileCell.Photo.SetBinding(Image.SourceProperty, new Binding("ProfilePhoto", BindingMode.OneWay));

    var tableSections = new List<TableSection>();

    tableSections.Add(new TableSection()
    {
        profileCell
    });

    Content = new TableView
    {
        HasUnevenRows = true,
        Intent = TableIntent.Menu,
        Root = new TableRoot()
        {
            tableSections
        }

    };

    await viewModel.LoadProfilePhoto();

}

从磁盘读取照片的代码:

public async Task<ImageSource> GetPhoto(string fileName)
{
    var localStorage = FileSystem.Current.LocalStorage;
    var folderExists = await localStorage.CheckExistsAsync(PhotosFolder);

    if (!folderExists.Equals(ExistenceCheckResult.FolderExists))
        return null;

    var localStorageFolder = await localStorage.GetFolderAsync(PhotosFolder);
    var fileExists = await localStorageFolder.CheckExistsAsync(fileName);

    if (!fileExists.Equals(ExistenceCheckResult.FileExists))
        return null;

    IFile file = await localStorageFolder.GetFileAsync(fileName);

    if (file == null)
        return null;

    var stream = await file.OpenAsync(FileAccess.Read);
    var imageSource = ImageSource.FromStream(() => stream);
    return imageSource;

}

现在它只发生在Android中。我在iOS上遇到了这个问题,但在使用占位符后问题就消失了。

现在仅在Android 中发生。我正在使用Xamarin.Forms。

我在这里做错了什么?

由于

1 个答案:

答案 0 :(得分:0)

根据我能够收集到的信息, Xamarin将尝试处理不再使用的流

为了解决这个问题,建议here

我将上述代码从 GetPhoto 修改为 GetPhotoBytes

public async Task<byte[]> GetPhotoBytes(string fileName)
{
    var localStorage = FileSystem.Current.LocalStorage;
    var folderExists = await localStorage.CheckExistsAsync(PhotosFolder);

    if (!folderExists.Equals(ExistenceCheckResult.FolderExists))
    {
        return null;
    }

    var localStorageFolder = await localStorage.GetFolderAsync(PhotosFolder);
    var fileExists = await localStorageFolder.CheckExistsAsync(fileName);

    if (!fileExists.Equals(ExistenceCheckResult.FileExists))
    {
        return null;
    }

    IFile file = await localStorageFolder.GetFileAsync(fileName);

    if (file == null)
    {
        return null;
    }

    var stream = await file.OpenAsync(FileAccess.Read);

    byte[] bytes = null;
    using (var memoryStream = new System.IO.MemoryStream())
    {
        stream.CopyTo(memoryStream);
        stream.Dispose();
        bytes = memoryStream.ToArray();
    }

    return bytes;

}

现在,LoadProfilePhoto构建了一个来自字节的流:

public async Task LoadProfilePhoto()
{
    // Set placeholder first
    ProfilePhoto = ImageSource.FromFile(FileNames.ProfilePlaceholderPNG);

    // Attemp to load existing photo
    var photoBytes = await Storage.Current.GetPhotoBytes(FileNames.ProfilePictureJPG);
    if (photoBytes != null)
    {
        var photo = ImageSource.FromStream(() => new System.IO.MemoryStream(photoBytes));
        if (photo != null)
        {
            ProfilePhoto = photo;
        }

    }

}

现在不是使用文件中的流,而是从Photo字节创建一个新的。我还没有理解为什么这条小溪也没有处理掉。但是,就目前而言,它似乎正常运作。