Reputation: 1190
I got a tricky thing here. I am developing an iOS App with Xamarin at the moment. (I think if you don't know about xamarin but c# you might know the answer as well - its an issue with threading basically!) I have a table with several entries, and when the user clicks one of the entries, it is required that i load data from a web service. This data is then displayed in the second table shown another view i push to. The problem is: In the exact moment the user clicks the table entry, the push segue to another view is triggered, the viewDidLoad() there is also triggered, in which i set the tables entries. But now sometimes it occurs that the async networking task from the previous view didn't finish, which leaves the table empty. To sum it up: I need to trigger a Table.Reload() on the View i push to, after the asynchronous networking request has done its work. How do i do that? I am really stuck here. Here are some details of my Code:
First View Controller
public async override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
//Sends the titles, subtitles, and the Headline to the DetailView
base.PrepareForSegue (segue, sender);
...
Task<String[,]> getJsonDataTask = SearchRequest.searchRequest (text, "Calendar");
arrayContent = await getJsonDataTask;
...
for (int i = 0; i < 50; i++) {
tableItems.Add(arrayContent [1, i]);
tableSubtitles.Add( arrayContent [5,i]);
Dates.Add(tableItems[i]);
Descriptions.Add (tableSubtitles [i]);
}
var calendarDetailController = segue.DestinationViewController as CalendarDetailVController;
if (calendarDetailController != null) {
Console.WriteLine ("preparesegue"+Dates.Count);
calendarDetailController.Dates = Dates;
calendarDetailController.Descriptions = Descriptions;
calendarDetailController.TableTitle = text;
calendarDetailController.id = id;
}
So here i am starting an async Thread (it needs to by ansync. cause its a network request) And i am transferring the data to the view controller i push to. In the
Secound View Controller
I just fetch the given data like
public List<String> Dates { get; set; }
public CalendarViewController (IntPtr handle) : base (handle)
{
Dates = new List<String> ();
}
And then i reload the tables data in ViewDidLoad();
public override async void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
//as the resource loading is async. whe need to refresh table here
TableView.ReloadData ();
}
Sometimes, if this ViewDidLoad() gets triggered, AFTER the async task finished, this works. But i need to trigger the Reload when the Data has fully arrived. Do you understand my problem? Thanks for your help.
Upvotes: 2
Views: 4850
Reputation: 3338
How about you pass your task instead of the result of the task?
Change:
public List<String> Dates { get; set; }
To:
public Task<String[,]> DatesTask{get;set;}
And you execute the task in the viewDidAppaer of your second viewcontroller:
public override async void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
//as the resource loading is async. whe need to refresh table here
Task.Run (async delegate {
await DatesTask().ContinueWith(() => {
InvokeOnMainThread (delegate {
TableView.ReloadData ();
});
});
});
}
I would not recommend to make a method like ViewDidAppaer wait, instead i would let a task handle the execution of your method, and once it is done, make your tableview refresh. That way you will not freeze your userinterface while executing your task!
Or if you really want to execute your task in your first viewcontroller, you should execute your task BEFORE performing PrepareForSegue
.
Upvotes: 3
Reputation: 6181
If I understood your question correctly it seems that you only need to pass the async Task
from the view that initiated the call to your second view that needs to await
it to finish, nothing fancy here.
Upvotes: 1