我在UI线程上显示一个ProgressBar,然后在另一个线程上启动登录过程。这完美无瑕,我得到了ProgressBar“圆圈”,它使用户知道发生了什么事情。问题是我需要通过UI向用户返回任何登录错误,例如无效的用户名/密码。我将ProgressBar类更改为包含一个ErrorMessage
属性,实例化该属性并将其作为参数传递给登录过程。对于任何错误,我都设置ErrorMessage
属性。如果不为空,则显示错误。问题是登录线程未完成,然后我进入if
检查是否为空。这都是在按钮单击事件上完成的。我的代码:
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;
}
}
*注意:* 发布此代码后,我看到我需要对权限做更多的工作,该线程上的用户不太可能出现权限对话框,因此我需要将其移出该过程。
答案 0 :(得分:1)
您不需要单独的线程; await
可以正常工作。您也不需要ManualResetEvent
作为完成工作的“信号”;为此,在await
上使用Task
很好。
等效的简化代码:
MyButton_Submit.Click += async (sender, e) =>
{
ProgressBarHandler myprogressbar = new ProgressBarHandler(this);
myprogressbar.show();
await SignOn(myprogressbar);
myprogressbar.hide();
if (myprogressbar.ErrorMesage != null)
{
...
}
};
您不应从不在Xamarin应用中键入Thread
。 总是是一种更简单,更好的方法。 Thread
类型通常是“强黄色”标志,但在Xamarin中是红色标志。
答案 1 :(得分:0)
等待Task.Run(() => resetEvent.WaitOne());
应该可以解决问题。 ManualResetEvent
不可等待,不能直接在其上使用await关键字,因此您需要将其包装在任务中