xamarinxamarin.iosmvvmcrossui-threadmvxbind

Execute MVVMCross value converter logic on UI thread


I am working on a Xamarin.iOS project, and have a MVVMCross value converter that takes a file extension string and returns the corresponding file icon as an UIImage.

This converter is used in a file list. I found that when I'm scrolling the list, as soon as the MvxTableViewCell is recycled, the UI converter is often invoked in the background thread for the recycled cell, making my code to throw an error complaining calling a UIKit method from a background thread.

It looks like in the latest version of MVVMCross, the old IMvxMainThreadDispatcher.RequestMainThreadAction method is obsolete. The documentation recommends to use IMvxMainThreadAsyncDispatcher.ExecuteOnMainThreadAsync method.

However, this method returns a Task with no generic type. This obviously can't work with the Convert method of the value converter which expects the UIImage.

Is there a way to configure MVVMCross to always invoke the converter on UI thread?

Update:

Take the following code example:

public class FileIconConverter : MvxValueConverter<string, UIImage>
{
    protected override UIImage Convert(string fileExtension, Type targetType, object parameter, CultureInfo culture)
    {
        // When this is called, it could be in a background thread.
        // Since UIDocumentInteractionController.FromUrl requires to be called
        // on the UI thread, it would throw the UIKitThreadAccessException.
        return UIDocumentInteractionController.FromUrl(NSUrl.FromFilename("/tmp/generic" + fileExtension)).Icons[0];
    }
}

Solution

  • Since you have not added any code here all I can do is give you a bit of speculative advice.

    What you can do is use the InvokeOnMainThread method of Xamarin.iOS

    When you check the Xamarin.iOS documentation on Working with the UI Thread in Xamarin.iOS

    You can see that you use this method to make the changes that are supposed to be made on the UI

    InvokeOnMainThread ( () => {
    // manipulate UI controls
    });
    

    Update

    First of all, if you check the code for IMvxMainThreadDispatcher.RequestMainThreadAction at the MvvmCross's Git it is internally calling the same API!

    So what you can do to your existing code is something like

    public class FileIconConverter : MvxValueConverter<string, UIImage>
    {
    protected override UIImage Convert(string fileExtension, Type targetType, object parameter, CultureInfo culture)
      {
        UIImage image;
        IMvxMainThreadAsyncDispatcher.ExecuteOnMainThreadAsync(()=>{
    
        image=UIDocumentInteractionController.FromUrl
                   (NSUrl.FromFilename("/tmp/generic" + fileExtension)).Icons[0];
    
    
      });
        return image;
     }
    }