How to Dismiss UserDialogs' AlertAsync()

DFoulkDFoulk Derek FoulkUSMember ✭✭

I am trying to figure out how to "dismiss" an AsyncAlert(), but I run into fatal exception(s) when .Cancel() is called. I have never worked with CancellationTokens before, so I'm likely doing something wrong...

I have been searching for a solution to this issue for hours and I have hit that awesome Friday @ 4:30pm wall of defeat... Any help would be greatly appreciated!

Here is the class that contains the AlertAsync() call:

using Acr.UserDialogs;
using Plugin.Connectivity;
using System;
using System.Threading;

namespace AC_Status.Helpers
{
    public class Network
    {
        private static readonly Lazy<Network> _instance = new Lazy<Network>(() => new Network());

        private CancellationTokenSource _ctx;

        private Network()
        {
            _ctx = new CancellationTokenSource();
        }

        public static Network Current => _instance.Value;

        public bool ConnectivityAlertIsDisplayed { get; set; }

        public bool IsConnected
        {
            get
            {
                if (!CrossConnectivity.IsSupported)
                    return true;

                return CrossConnectivity.Current.IsConnected;
            }
        }

        public async void TestConnectivity()
        {
            if (!ConnectivityAlertIsDisplayed)
            {
                if (!IsConnected)
                {
                    ConnectivityAlertIsDisplayed = true;

                    await UserDialogs.Instance.AlertAsync("Internet Connection Required", "Please establish an internet connection and try again!", "Okay", _ctx?.Token);

                    ConnectivityAlertIsDisplayed = false;
                }
            }
            else if (IsConnected)
            {
                _ctx?.Cancel();
            }
        }
    }
}

The above helper's TestConnectivity() method is called like so:

using System;
using FreshMvvm;
using AC_Status.Helpers;

namespace AC_Status.PageModels
{
    public class BasePageModel : FreshBasePageModel
    {
        public string Title { get; set; }

        public bool IsBusy { get; set; }

        public bool IsInitialized { get; set; }

        protected override void ViewIsAppearing(object sender, EventArgs e)
        {
            base.ViewIsAppearing(sender, e);

            Network.Current.TestConnectivity();
        }
    }
}

Here is the stack trace:

09-08 16:20:10.096 I/MonoDroid(29324): UNHANDLED EXCEPTION:
09-08 16:20:10.103 I/MonoDroid(29324): System.Threading.Tasks.TaskCanceledException: A task was canceled.
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00026] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at Acr.UserDialogs.AbstractUserDialogs+<AlertAsync>d__21.MoveNext () [0x000bb] in C:\dev\acr\userdialogs\src\Acr.UserDialogs.Interface\AbstractUserDialogs.cs:133 
09-08 16:20:10.103 I/MonoDroid(29324): --- End of stack trace from previous location where exception was thrown ---
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0001a] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at AC_Status.Helpers.Network+<TestConnectivity>d__11.MoveNext () [0x0008f] in C:\Users\dfoulk\Repos\AC-Status\AC-Status\AC_Status\Helpers\Network.cs:43 
09-08 16:20:10.103 I/MonoDroid(29324): --- End of stack trace from previous location where exception was thrown ---
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in <d278c06ad5684d6882c743a94a93ebc2>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <d278c06ad5684d6882c743a94a93ebc2>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <d278c06ad5684d6882c743a94a93ebc2>:0 
09-08 16:20:10.103 I/MonoDroid(29324):   at (wrapper dynamic-method) System.Object:20a5f4cd-fc9c-4220-baa8-b833dbf24fb8 (intptr,intptr)
09-08 16:20:10.127 W/art     (29324): JNI RegisterNativeMethods: attempt to register 0 native methods for android.runtime.JavaProxyThrowable
An unhandled exception occured.

09-08 16:20:10.868 E/mono    (29324): 
09-08 16:20:10.868 E/mono    (29324): Unhandled Exception:
09-08 16:20:10.868 E/mono    (29324): System.Threading.Tasks.TaskCanceledException: A task was canceled.
09-08 16:20:10.869 E/mono-rt (29324): [ERROR] FATAL UNHANDLED EXCEPTION: System.Threading.Tasks.TaskCanceledException: A task was canceled.
09-08 16:20:10.893 I/TMSDISP (29324): AcsAndroidVirtualDisplayIntfImpl::~AcsAndroidVirtualDisplayIntfImpl - Enter
09-08 16:20:10.893 I/TMSDISP (29324): AcsAndroidVirtualDisplayIntfImpl::~AcsAndroidVirtualDisplayIntfImpl - Enter2
09-08 16:20:10.893 I/TMSDISP (29324): AcsAndroidVirtualDisplayIntfImpl::~AcsAndroidVirtualDisplayIntfImpl - mSource2
09-08 16:20:10.893 I/TMSDISP (29324): AcsAndroidVirtualDisplayIntfImpl::~AcsAndroidVirtualDisplayIntfImpl - Exit

Thank you in advance! @AllanRitchie

Answers

  • MarcMeier.1870MarcMeier.1870 Marc Meier USMember ✭✭

    Not very sure what you are trying to do exactly but if you try to check network state why don't you use ConnectivityManager ?

  • MarcMeier.1870MarcMeier.1870 Marc Meier USMember ✭✭

    It would give something like this (fired any time network state changes) (I used an alert dialog instead).

    public class MyNetworkStateReceiver :BroadcastReceiver
    {
    public static bool bHasNetwork = false;

        public override void OnReceive(Context context, Intent intent)
        {            
    
            ConnectivityManager conmgr = (ConnectivityManager)context.GetSystemService(Context.ConnectivityService);
            bool bNetWorkFound = conmgr.ActiveNetwork != null;
    
            var network = conmgr.ActiveNetwork;
            bNetWorkFound = network != null;
            }
    
        if(!bNetWorkFound)
    

    {
    var alert = new AlertDialog.Builder(activity);
    alert.SetTitle("Internet Connection Required");
    alert.SetMessage("Please establish an internet connection and try again!");

                        alert.SetPositiveButton("OKay", (sender, args) => { DoWhateverYouWant(); });
                        alert.SetNegativeButton("Cancel", (sender, args) => { YourCancelation(); });
    

    }

    }

    Let me know...

  • DFoulkDFoulk Derek Foulk USMember ✭✭

    @MarcMeier.1870 - I am trying to programatically close an alert :) I apologize for leaving my internet connectivity test in the code, but I did so to provide context.

    Essentially, I show an alert when the internet connectivity test fails and I would like to close that alert when the internet connectivity succeeds (these checks occur OnAppearing).

  • MarcMeier.1870MarcMeier.1870 Marc Meier USMember ✭✭

    I personally use alert only when I need a decision from the user or for a warning (in this case I want a confirmation that the user is informed, so I need an answer as well). If no interaction is needed I prefer to use progress dialog.
    So in order to keep a simple code I would use a progress dialog while you are trying to establish a connection.
    Dismiss it if you get it or if it fails and you need the user to decide to try again or cancel include an alert only at that time.

    Something like this (just change the code in order to make a loop when user want to try again. this is just to give you an idea...):

    ProgressDialog progress = ProgressDialog.Show(activity,"Internet Connection Required" , "Trying to establish an internet connection", true);

            new Thread(new ThreadStart(() =>
            {
                bool bError = GetYourConnectionTestResult();
                activity.RunOnUiThread(() =>
                {
                    if (bError)
                    {
                        var alert = new AlertDialog.Builder(activity);
                        alert.SetTitle("Internet Connection Required");
                            alert.SetMessage("Please establish an internet connection and try again!");
                        alert.SetPositiveButton("Try again", (senderAlert, args) => {  TryAgainToGetAConnection(); });
                        alert.SetNegativeButton("Cancel", (senderAlert, args) => {  progress.Dismiss(); });
                        activity.RunOnUiThread(() => { alert.Show(); });
                    }
                    else
                        progress.Dismiss();
                });
            })).Start();
    

    Hoping this would help you...

  • DFoulkDFoulk Derek Foulk USMember ✭✭

    @MarcMeier.1870 said:
    I personally use alert only when I need a decision from the user or for a warning (in this case I want a confirmation that the user is informed, so I need an answer as well). If no interaction is needed I prefer to use progress dialog.
    So in order to keep a simple code I would use a progress dialog while you are trying to establish a connection.
    Dismiss it if you get it or if it fails and you need the user to decide to try again or cancel include an alert only at that time.

    Something like this (just change the code in order to make a loop when user want to try again. this is just to give you an idea...):

    ProgressDialog progress = ProgressDialog.Show(activity,"Internet Connection Required" , "Trying to establish an internet connection", true);

    new Thread(new ThreadStart(() =>
    {
    bool bError = GetYourConnectionTestResult();
    activity.RunOnUiThread(() =>
    {
    if (bError)
    {
    var alert = new AlertDialog.Builder(activity);
    alert.SetTitle("Internet Connection Required");
    alert.SetMessage("Please establish an internet connection and try again!");
    alert.SetPositiveButton("Try again", (senderAlert, args) => { TryAgainToGetAConnection(); });
    alert.SetNegativeButton("Cancel", (senderAlert, args) => { progress.Dismiss(); });
    activity.RunOnUiThread(() => { alert.Show(); });
    }
    else
    progress.Dismiss();
    });
    })).Start();

    Hoping this would help you...

    That's a valid approach. This is pretty much what I'm trying to accomplish, but there is no Dismiss() method on the Xamarin.Forms alert... I suppose I can try using a DependencyService and implement something native on each platform.

    My only hesitation in doing so is that there is a Dismiss() equivalent for Acr.UserDialogs.AlertAsync() (Xamarin.Forms compatible).

    I did find something regarding CancellationTokens and awaitable methods (that I can't find now/can't remember) that is probably the cause of the error I'm encountering. I'm gonna start with a fresh palette and try to eliminate the need for the asynchronous alert, then I can use something different (i.e. Acr.UserDialogs > Alert, which implements IDisposable).

    Thank you for the assistance!

Sign In or Register to comment.