jobrien9
jobrien9

Reputation: 147

Touchscreen Functionality Crashing in .NET Maui Hybrid App

I have a .NET MAUI Blazor application that I'm deploying on a single-board Windows 10 Computer with a touchscreen. On occasion, the app stops responding to my touch input. The touchscreen itself remains functional for other apps on the computer. If I remotely connect to the computer or plug in a keyboard/mouse, the Maui app responds to those sources of input, but the touchscreen functionality remains broken until I restart the app. This has happened on multiple computers where I've deployed this app, so I know it's not an issue with one specific machine.

It's not clear what action is triggering the event. I can sometimes partially reproduce the issue by spamming a particularly resource-intensive button in the app. However, this action seems to crash more than just the touchscreen input. The app also stops responding to keyboard/mouse input when I crash it this way.

My team and I use a remote access tool (VNC Server/VNC Viewer) on these machines with a fair amount of frequency. When we see this issue appear organically, it seems to happen after remotely connecting to the computer. However, it doesn't happen every time we connect. It doesn't even happen half of the time we connect, so I'm not completely sure this is the culprit, but I am suspicious of it.

Has anyone else encountered this with their MAUI Blazor app? If not, are there any ideas what could cause this? My guess would be that the remote access tool is consuming enough system resources that something in the app is crashing and causing the touchscreen input to die. I don't know what specifically is responsible for the touch input in a Blazor app, though, so I'm not sure where to begin debugging. I understand the Maui Blazor uses Microsoft Edge WebView2. Would this be where the touchscreen input handler lives?

EDIT: I was able to catch some exceptions related to this today. First, It looks like I see a flurry of this exception:

System.Threading.SynchronizationLockException: The lock is being disposed while still being used. It either is being held by a thread and/or has active waiters waiting to acquire the lock. at System.Threading.ReaderWriterLockSlim.Dispose(Boolean disposing)

Next, I see this:

System.InvalidOperationException: Operation is not valid due to the current state of the object. at System.Reflection.MemberInfo.get_MetadataToken()

Finally, I get this:

Microsoft.JSInterop.JSException: Unable to focus an invalid element. Error: Unable to focus an invalid element. at Object.focus (https://0.0.0.0/_framework/blazor.webview.js:1:32448) at https://0.0.0.0/_framework/blazor.webview.js:1:3050 at new Promise () at g.beginInvokeJSFromDotNet (https://0.0.0.0/_framework/blazor.webview.js:1:3007) at https://0.0.0.0/_framework/blazor.webview.js:1:48020 at EventTarget. (:7:62) at EmbeddedBrowserWebView. (:1:40770) at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()

I get that a thread is deadlocked somewhere. Presumably there's threads that are kicked off internally that deal with the click/tap handler events that precipitate this. Since much of this is dealt with in internal libraries that are outside of my control, what actions can I take to mitigate this?

EDIT 2:

As requested, here's an example piece of code that is effected by this bug. The example is with an HTML video tag, but this behavior seems to occur throughout my app in a variety of components (buttons, divs, images, etc) where @onclick occurs.

<video class="my-class" autoplay loop @onclick="MyMethod">
    ....
</video> 

Additionally, I use MudBlazor, and the bug effects their components, such as:

<MudButton OnClick="AddRemove" Variant="Variant.Filled" Color="Color.Secondary" ...

EDIT 3:

To clarify how I caught the above three exceptions, I followed the example in the discussion seen here.

Instead of a static class, though, I created my "GlobalExceptionHandlers" class as follows:

  ...  public GlobalExceptionHandlers()
{
    AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
    {
        Logger.Error("Unhandled Exception");
        UnhandledException?.Invoke(sender, args);
    };

#if WINDOWS

    AppDomain.CurrentDomain.FirstChanceException += (_, args) =>
    {
        if (IsTouchScreenBug(args.Exception.Message)){
            Logger.Fatal(args.Exception, "Suspected Touch Screen Bug! Exception details: {0}");
        } else if (IsIgnoreable(args.Exception.Message))
        {
            ...

        _lastFirstChanceException = args.Exception;
    };

The IsTouchScreenBug and IsIgnoreable methods are optional but help me filter out stuff that I've determined isn't related to the issue. In App.xaml.cs, I create a new GlobalExceptionHandlers();.

Upvotes: 0

Views: 406

Answers (1)

jobrien9
jobrien9

Reputation: 147

I'm still not 100% sure of why these symptoms occurred in the first place, but I did figure out that we can mitigate their effects by adding @ontouchstart. Apparently, whatever causes @onclick to fail does not cause @ontouchstart to fail. For example, the following block would fail when this crash occurs. In other words, "MyMethod" would not be called:

<video class="my-class" autoplay loop @onclick="MyMethod">
    ....
</video>

However, this code block would succeed:

<video class="my-class" autoplay loop @ontouchstart="MyMethod">
    ....
</video>

Note that the @onclick typically responds to touch input. It's only after the bug I described in my initial question that @onclick fails.

Hopefully this helps others who may run into this problem.

Upvotes: 0

Related Questions