FrozenKiwi
FrozenKiwi

Reputation: 1513

Xamarin: How to let UI redraw while performing long-running operation on UI thread (without the use of async/await)

I am (for reasons) forced to perform a long-running operation on the UI thread of my xamarin forms (NetStandard) application. During this operation, I would like to update the UI to give the user feedback on progress. I can make changes to the UI, but the UI will not redraw as I cannot return the instruction pointer to the OS by using await/async.

Is there any way I can process messages on the UI thread without using async/await. In the old Win32 days I think Translate/DispatchMessage could be used to keep the message pump going in long-running operations, and this is similar to what I need.

Background: I have a interface defined and called by the android OS that runs on my UI thread. It is important that we return the result of this long-running operation from this service. Because the interface is not defined as async I cannot use await to let the IP return to the OS. If I did the function would immediately return (without the results being fetched) and continue executing (ie, it would fail). I can't change these circumstances.

// The following class is called directly by the AndroidOS
class CloudHostCardService : HostApduService
{
    // The following method is called by the AndroidOS on the UI thread
    public override byte[] ProcessCommandApdu(byte[] commandApdu, Bundle extras)
    {
        ViewModels.MainPageViewModel.SetStatus("Processing Cmd");  // <-- updates UI
        return processor.ProcessCommand(commandApdu); // <-- Long running operation
    }
}

Is there any other way to trigger a redraw (pump messages in Win32 speak)?

Upvotes: 0

Views: 771

Answers (1)

SushiHangover
SushiHangover

Reputation: 74209

HostApduService allows you to return null from ProcessCommandApdu and then later use SendResponseApdu to supply the ResponseApdu.

This method is running on the main thread of your application. If you cannot return a response APDU immediately, return null and use the sendResponseApdu(byte[]) method later.

Example:

public class SampleHostApduService : HostApduService
{
    public override void OnDeactivated([GeneratedEnum] DeactivationReason reason)
    {
    }

    public override byte[] ProcessCommandApdu(byte[] commandApdu, Bundle extras)
    {
        // Update your UI via your viewmodel.

        // Fire and forget
        Task.Run(() => {
            this.SendResponseApdu(processor.ProcessCommand(commandApdu));
         });

        // Return null as we handle this using SendResponseApdu
        return null;
    }
}

Upvotes: 1

Related Questions