Xamarin:在单击单元格之前,从 Web 获取时 UITableView 单元格图像不显示在单元格中

Xamarin: UITableView cell images not showing in cell when fetched from the web until the cell is clicked

我想在 UITableView 控制器的 GetCell 方法中显示从 URL 到 cell.ImageView.Image 变量的图像。出于某种原因,图像仅在我单击单元格时显示。它正在获取图像,但未更新单元格。数据是 ObservableCollection,所以我不确定我遗漏了什么。我需要显式调用任何方法吗?

public class PasswordGroupsDataSource : UITableViewDataSource
{
    const string PlaceholderImagePath = "Placeholder.jpg";
    UIImage PlaceholderImage { get; set; }
    PasswordsViewController Controller { get; set; }
    List<Password> Apps;
    public ObservableCollection<PasswordGroup> Groups { get; set; }
    public PasswordGroupsDataSource(ObservableCollection<PasswordGroup> groups, PasswordsViewController controller, List<Password> passwords)
    {
        Controller = controller;
        Apps = passwords;
        PlaceholderImage = UIImage.FromFile("Images/Placeholder.png");

        if (groups == null)
        {
            throw new ArgumentNullException("groups");
        }
        Groups = groups;
        groups.CollectionChanged += HandleAppsCollectionChanged;

        // If either a download fails or the image we download is corrupt, ignore the problem.
        TaskScheduler.UnobservedTaskException += delegate(object sender, UnobservedTaskExceptionEventArgs e)
        {
            e.SetObserved();
        };
    }
    void HandleAppsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        // Whenever the Items change, reload the data.
        Controller.TableView.ReloadData();
    }

    public Password GetPerson(NSIndexPath indexPath)
    {
        try
        {
            var personGroup = Groups[indexPath.Section];
            return personGroup.People[indexPath.Row];
        }
        catch (Exception exc)
        {
            Console.WriteLine("Error in GetPerson: " + exc.Message);

            //Occasionally we get an index out of range here
            return null;
        }
    }

    public override string TitleForHeader(UITableView tableView, nint section)
    {
        return Groups[(int)section].Title;
    }

    public override string[] SectionIndexTitles(UITableView tableView)
    {
        return Groups.Select(x => x.Title).ToArray();
    }

    public override nint NumberOfSections(UITableView tableView)
    {
        return Groups.Count;
    }

    public override nint RowsInSection(UITableView tableView, nint section)
    {
        return Groups[(int)section].People.Count;
    }

    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
    {
        var cell = tableView.DequeueReusableCell("P") as PasswordCell;
        if (cell == null)
        {
            cell = new PasswordCell("P");
        }

        var person = GetPerson(indexPath);
        cell.Tag = indexPath.Row;
        if (person != null)
        {
            cell.Person = person;

            if (person.Image == null)
            {
                person.Image = PlaceholderImage;
                BeginDownloadingImage(person, indexPath);
            }
            cell.ImageView.Image = person.Image;
        }

        return cell;
    }

    #region Image Support

    readonly Dictionary<string, UIImage> images = new Dictionary<string, UIImage>();
    readonly List<string> imageDownloadsInProgress = new List<string>();
    readonly ImageDownloader imageDownloader = new UIKitImageDownloader();

    async void BeginDownloadingImage(Password app, NSIndexPath path)
    {
        // Queue the image to be downloaded. This task will execute
        // as soon as the existing ones have finished.
        byte[] data = null;

        data = await GetImageData(app.GravatarUrl.ToString());
        app.Image = UIImage.LoadFromData(NSData.FromArray(data));

        InvokeOnMainThread(() =>
        {
            if (Apps != null)
            {
                var cell = Controller.TableView.VisibleCells.Where(c => c.Tag == Apps.IndexOf(app)).FirstOrDefault();
                if (cell != null)
                    cell.ImageView.Image = app.Image;
            }
        });
    }

    async Task<byte[]> GetImageData(string ImageUrl)
    {
        byte[] data = null;
        try
        {
            UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
            using (var c = new GzipWebClient())
                data = await c.DownloadDataTaskAsync(ImageUrl);
        }
        finally
        {
            UIApplication.SharedApplication.NetworkActivityIndicatorVisible = false;
        }

        return data;
    }
    public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
    {
        return true;
    }
    public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
    {
        if (editingStyle == UITableViewCellEditingStyle.Delete)
        {
            Groups.RemoveAt(indexPath.Row);
        }
    }

    #endregion
}

当我调试它时,我可以看到图像正在 BeginDownloadingImage 函数中设置。我错过了什么?为什么在单击单元格之前不会更新单元格?

注意:我使用的是 Xamarin 员工目录示例中的这个。

我不确定你能不能那样做。我会在 Person 对象上覆盖您的占位符 Image,然后从您的 tableview 调用 ReloadRows。

InvokeOnMainThread(() =>
            {
                if (Apps != null)
                {
                    person.Image = app.Image;
                    Controller.TableView.ReloadRows (new NSIndexPath[]{ path }, UITableViewRowAnimation.Fade);
                }
            });