Falco Winkler
Falco Winkler

Reputation: 1190

Waiting for a thread to finish in c# / Xamarin

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

Answers (2)

Chris
Chris

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

Alex.F
Alex.F

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

Related Questions