簡體   English   中英

C#需要等待線程完成而不阻塞UI線程

[英]C# Need to wait for thread to finish without blocking UI thread

我在UI線程上顯示一個ProgressBar,然后在另一個線程上啟動登錄過程。 這完美無瑕,我得到了ProgressBar“圓圈”,它使用戶知道發生了什么事情。 問題是我需要通過UI向用戶返回任何登錄錯誤,例如無效的用戶名/密碼。 我將ProgressBar類更改為包含ErrorMessage屬性,將其實例化並將其作為參數傳遞給登錄過程。 對於任何錯誤,我都設置ErrorMessage屬性。 如果不為空,則顯示錯誤。 問題是登錄線程在我檢查if是否為null之前沒有完成。 這都是在按鈕單擊事件上完成的。 我的代碼:

MyButton_Submit.Click += async (sender, e) =>
{
        ManualResetEvent resetEvent = new ManualResetEvent(false);
        ProgressBarHandler myprogressbar = new ProgressBarHandler(this);
        myprogressbar.show();

        var thread = new System.Threading.Thread(new ThreadStart(async delegate
        {
            await SignOn(myprogressbar);
            resetEvent.Set();
        }));
        thread.Start();
        // based on @Giorgi Chkhikvadze comment below I changed: resetEvent.WaitOne(); to:

        await Task.Run(() => resetEvent.WaitOne());
        // works perfectly 


        while (thread.ThreadState == ThreadState.Running)
        {
            await Task.Delay(100);
        }
        myprogressbar.hide();

        if (myprogressbar.ErrorMesage != null)
        {
            Context context = Application.Context;
            string text = myprogressbar.ErrorMesage ;
            ToastLength duration = ToastLength.Short;
            var toast = Toast.MakeText(context, text, duration);
            toast.Show();
        }
    };
}

resetEvent.WaitOne(); 顯然阻止了UI,因為當我注釋掉它時,進度條會顯示出來,而當我執行它時,它不會顯示出來。 我怎樣才能解決這個問題?

*編輯-添加了登錄代碼*

    private async Task SignOn(ProgressBarHandler MyProgress)
    {
        Boolean error = false;

        // Hide the keyboard ...
        InputMethodManager imm = (InputMethodManager)GetSystemService(Context.InputMethodService);
        imm.HideSoftInputFromWindow(aTextboxPassword.WindowToken, 0);

        // Check permissions
        var mypermission = ApplicationContext.CheckCallingOrSelfPermission(Android.Manifest.Permission.Internet);

        if (ApplicationContext.CheckCallingOrSelfPermission(Android.Manifest.Permission.Internet) != Android.Content.PM.Permission.Granted)
        {

            int MY_REQUEST_CODE = 0;
            //int x = 0;
            RequestPermissions(new String[] { Android.Manifest.Permission.Internet },
                    MY_REQUEST_CODE);
            //x = 1;
        }

        mypermission = ApplicationContext.CheckCallingOrSelfPermission(Android.Manifest.Permission.Internet);

        if (ApplicationContext.CheckCallingOrSelfPermission(Android.Manifest.Permission.AccessNetworkState) != Android.Content.PM.Permission.Granted)
        {

            int MY_REQUEST_CODE = 0;
            RequestPermissions(new String[] { Android.Manifest.Permission.AccessNetworkState },
                    MY_REQUEST_CODE);
        }

        MyUser.Username = aTextboxUsername.Text.Trim();
        MyUser.Password = aTextboxPassword.Text.Trim();
        try
        {

            ConnectivityManager connectivityManager = (ConnectivityManager)GetSystemService(ConnectivityService);

            NetworkInfo activeConnection = connectivityManager.ActiveNetworkInfo;
            bool isOnline = (activeConnection != null) && activeConnection.IsConnected;

            if (isOnline)
            {
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                OMLDataInterfaceWeb.OMLDataInterface myService = new OMLDataInterfaceWeb.DataInterface();

                try
                {
                    result = myService.Logon(MyUser.Username, MyUser.Password);

                }
                catch (Exception ex)
                {
                    MyProgress.ErrorMesage = "Logon attempt failed due to error: " + ex.Message;
                }
            }
            else
            {
                MyProgress.ErrorMesage = "There is no internet connection or cell phone connection.  Connect to a network or connect to a cellular network.";
            };
        }
        catch (Exception ex)
        {
            MyProgress.ErrorMesage = "Connectivity Manager failed to create a connection due to error: " + ex.Message;
        };

        if (result == "CONNECTED")
        {
            PopulateMyUser();
            StoreUsernamePassword();


            var usertype = MyUser.Usertype.ToUpper();
            if (usertype == "ADMIN")
            {
                Intent intent = new Intent(this, typeof(Drawer));
                Bundle bundlee = new Bundle();
                bundlee.PutParcelable("MyUser", MyUser); // Persist user class to next activity
                intent.PutExtra("TheBundle", bundlee);
                StartActivity(intent);
            }

        }
        else
        {
            try
            {
                error = true;
                errormsg = "Logon Error: Invalid Username or Password.";
            }
            catch (Exception ex)
            {
                MyProgress.ErrorMesage = "An error occured while attempting to set the error message, the error is: " + ex.Message;
            }
        };
        try
        {
            if (error)
            {
                MyProgress.ErrorMesage = "An error occured during the logon process (2), The error is: " + errormsg;
            }
        }
        catch (Exception ex)
        {
            MyProgress.ErrorMesage = "An error occured during the logon process (2), The error is: " + ex.Message;
        }
    }

*注意:*發布此代碼后,我看到我需要對權限進行更多處理,該線程上的用戶不太可能顯示權限對話框,因此需要將其移出此過程。

您不需要單獨的線程; await本身就可以正常工作。 您也不需要ManualResetEvent作為完成工作的“信號”。 為此,在Task上使用await可以正常工作。

等效的簡化代碼:

MyButton_Submit.Click += async (sender, e) =>
{
  ProgressBarHandler myprogressbar = new ProgressBarHandler(this);
  myprogressbar.show();

  await SignOn(myprogressbar);
  myprogressbar.hide();

  if (myprogressbar.ErrorMesage != null)
  {
    ...
  }
};

永遠不應該的Thread在Xamarin的應用程序類型。 有一種更簡單,更好的方法。 Thread類型通常是“強黃色”標志,但在Xamarin中是紅色標志。

等待Task.Run(() => resetEvent.WaitOne()); 應該可以。 ManualResetEvent不可等待,不能直接在其上使用await關鍵字,因此您需要將其包裝在task中

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM