Error in ui kit Consistency error
Asked Answered
O

3

6

I am having a issue accesing a text box in a view controller .cs file

 async partial void loginUser(UIButton sender)

{

    // Show the progressBar as the MainActivity is being loade


    Console.WriteLine("Entered email : " + txtEmail.Text);


        // Create user object from entered email
        mCurrentUser = mJsonHandler.DeserialiseUser(txtEmail.Text);
        try
        {

            Console.WriteLine("Starting network check");
            // Calls email check to see if a registered email address has been entered
            if (EmailCheck(txtEmail.Text) == true)
            {
                await  CheckPassword();
            }
            else
            {
                UIAlertView alert = new UIAlertView()
                {
                    Title = "Login Alert",
                    Message = "Incorrect email or password entered"
                };
                alert.AddButton("OK");
                alert.Show();

            }


        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("An error has occured: '{0}'", ex);
        }

It is within this funciton that it complains it cannot access a text box which is on a aynsc method

    public Task CheckPassword()
    {

   return Task.Run(() =>
    {
            // Creates instance of password hash to compare plain text and encrypted passwords.
            PasswordHash hash = new PasswordHash();
            // Checks password with registered user password to confirm access to account.
            if (hash.ValidatePassword(txtPassword.Text ,mCurrentUser.password)==true)
            {
                Console.WriteLine("Password correct");


                UIAlertView alert = new UIAlertView()
                {
                    Title = "Login Alert",
                    Message = "Password Correct Loggin In"
                };
                alert.AddButton("OK");
                alert.Show();
                //insert intent call to successful login here.

            }
            else
            {
                UIAlertView alert = new UIAlertView()
                {
                    Title = "Login Alert",
                    Message = "Incorrect email or password entered"
                };
                alert.AddButton("OK");
                alert.Show();

            }
            Console.WriteLine("Finished check password");
        });
    }

Its this line the error occurs:

txtPassword.Text 

The error is as follows:

UIKit.UIKitThreadAccessException: UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread.

Also my Password Correct does not show even though if it is a correct password. Do i have to run the UI Alerts on a seperate thread?

Overshine answered 24/8, 2016 at 10:29 Comment(0)
A
29

Any UIKit methods must be called from the UI thread (or Main thread, Main queue, etc.). This ensures consistency in the UI. Xamarin adds a check to all UIKit methods in debug mode and throws that exception if you try to use a background thread to change the UI.

The solution is simple: only modify the UI from the UI thread. That essentially means if you're using a class with "UI" in front it, you should probably do it from the UI thread. (That's a rule of thumb and there are other times to be on the UI thread).

How do I get my code on this mythical UI thread? I'm glad you asked. In iOS, you have a few options:

  • When in a subclass of NSObject, InvokeOnMainThread will do the trick.
  • From anywhere, CoreFoundation.DispatchQueue.MainQueue.DispatchAsync will always work.

Both of those methods just accept an Action, which can be a lambda or a method.

So in your code, if we add an InvokeOnMainThread (because I think this is in your UIViewController subclass)...

 public Task CheckPassword()
 {

     return Task.Run(() =>
     {
        // Creates instance of password hash to compare plain text and encrypted passwords.
        PasswordHash hash = new PasswordHash();
        // Checks password with registered user password to confirm access to account.
        InvokeOnMainThread(() => {
            if (hash.ValidatePassword(txtPassword.Text ,mCurrentUser.password)==true)
            {
                Console.WriteLine("Password correct");


                UIAlertView alert = new UIAlertView()
                {
                    Title = "Login Alert",
                    Message = "Password Correct Loggin In"
                };
                alert.AddButton("OK");
                alert.Show();
                //insert intent call to successful login here.

            }
            else
            {
                UIAlertView alert = new UIAlertView()
                {
                    Title = "Login Alert",
                    Message = "Incorrect email or password entered"
                };
                alert.AddButton("OK");
                alert.Show();

            }
        });
        Console.WriteLine("Finished check password");
    });
}
Aero answered 24/8, 2016 at 13:34 Comment(3)
great answer thank you i am also running into a small problem where I cant seem to push another view into that thread I want it to goto to storyboard id of contactInfo when login is sucesfullOvershine
I maangerd to solve pushing my view issue so thank you dylan for your assistanceOvershine
Thanks for the answer, the following worked for me. CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() => { // UI CODE HERE });Gillen
S
3

Maybe this helps someone. So I will add what solve my issue, that was the same of rogue. Follow the code that avoid this error of consistency in xamarin forms when used in iOS

 await Task.Run(async () =>
            {
                await Device.InvokeOnMainThreadAsync(async () =>
                {
                    await MaterialDialog.Instance.SnackbarAsync(message: "Bla bla bla",
                                           msDuration: MaterialSnackbar.DurationShort).ConfigureAwait(false);

                }).ConfigureAwait(false);

            }).ConfigureAwait(false);  
Schurman answered 30/3, 2021 at 20:5 Comment(2)
there was already an accepted answer chosen please dont create an answer because not even rep to comment its not the stack over flow way but thanks you basically copied what he posted.Overshine
works for me and respect both answerPuttergill
O
0

The highest marked answers unfortunately didn't resolve issue for me but I finally got my application to run by ignoring the issue. Not recommended but did work.

I just added the line UIApplication.CheckForIllegalCrossThreadCalls = false; to my FinishedLaunching override

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
     // code here
     UIApplication.CheckForIllegalCrossThreadCalls = false;    
     return base.FinishedLaunching(app, options);
}

code found here

Odelia answered 21/5 at 12:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.