RyeGuy
RyeGuy

Reputation: 4483

Updating the UI with Xamarin

I am having difficulty updating the UI using Xamarin. The objective is to make reactive UI so the user knows that application is thinking. Below are my attempts.

Attempt 1

private void BeginProcess(string fileName)
{
     Device.BeginInvokeOnMainThread(() => {
         iContent.Text = "UI Successfully updated.";
     });

     Device.BeginInvokeOnMainThread(() => {
         ProccessFolder testMethod = new ProccessFolder.Initialize(fileName);
     });
}

Attempt 2

private void UpdateUI () {
    iContent.Text = "UI Successfully updated.";
}

private void BeginProcess(string fileName)
{
     System.Threading.Thread t = new System.Threading.Thread(UpdateUI);
     t.Priority = System.Threading.ThreadPriority.Highest;
     t.IsBackground = false;
     t.Start();

     Device.BeginInvokeOnMainThread(() => {
         ProccessFolder testMethod = new ProccessFolder.Initialize(fileName);
     });
}

Attempt 3

private void BeginProcess(string fileName)
{
     Device.BeginInvokeOnMainThread(() => {
         iContent.Text = "UI Successfully updated.";
     });

     Task.Delay(5000);

     Device.BeginInvokeOnMainThread(() => {
         ProccessFolder testMethod = new ProccessFolder.Initialize(fileName);
     });
}

Unfortunately none of these work. What does work is if I place the ProcessFolder method in a background thread and invoke the UI changes on the main thread. However the completion time of the ProcessFolder method is slower.

Any suggestion on how I can update the UI while still executing ProcessFolder on the main thread?

Upvotes: 5

Views: 9829

Answers (3)

Bart Vanseer
Bart Vanseer

Reputation: 548

Why not use:

RunOnUiThread(() =>
{
    iContent.Text = "UI Successfully updated.";
});

Clean and simple

Upvotes: 0

Constantin Iliescu
Constantin Iliescu

Reputation: 111

First of all, all the UI updates must be done in the main thread.

For your particular problem maybe you could use async/await (https://msdn.microsoft.com/library/hh191443(vs.110).aspx)

You could do something like in the main thread:

ProccessFolder testMethod = await ProccessFolder.Initialize(fileName);
iContent.Text = "UI Successfully updated.";

You have to make the Initialize method async and to return a task

Upvotes: 1

JoeTomks
JoeTomks

Reputation: 3276

Sometimes when your try update something on the main ui from within a method, depending on the way you've written (and/or structured) it can mean that the main dispatcher waits for the method to complete before updating the main ui.

If you were to try the following example it would successfully complete a UI update after each foreach iteration because when it completes it's initial task it wants to return out of the for loop and hits our main thread invoke, which HAS to complete before the loop can iterate again.

private void BeginProcess()
{
    Task.Run(()=>{
        for (int i = 0; i < 100; i++)
        {
            // Perform a task

            BeginInvokeOnMainThread(() => {
                iContent.Text = "UI Successfully updated: " + i " times out of 100";
            });
        }
    })
}

You can sometimes replicate this kind of effect by using:

NSRunLoop.Current.RunUntil(1000);

to allow the UI to catch up when you call the 'BeginInvokeOnMainThread' delegate.

Upvotes: 9

Related Questions