简体   繁体   中英

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

I want to display an image from a URL to the cell.ImageView.Image variable in UITableView controller's GetCell method. For some reason, the image is displayed only when I click on the cell. It's fetching the image, but the cell is not being updated. The data is an ObservableCollection , so I'm not sure what I am missing. Do I need to call any method explicitly?

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
}

When I debug it, I can see that the image is being set in the BeginDownloadingImage function. What am I missing? Why is the cell not being updated until the cell is clicked?

Note: I was using this from Xamarin Employee Directory Sample.

I am not sure you can do it that way. I would overwrite your placeholder Image on the Person object and then call ReloadRows from your tableview.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM