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);
}
});
我想在 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);
}
});