嘿,我有一个应用程序,我想在检查用户登录并加载附加信息时显示启动屏幕。我遇到的问题是我无法让启动屏幕在不死锁应用程序的情况下保持可见。
public ProgramMain()
{
InitializeComponent();
LoadDataAsync().Wait();
_viewPageManager = new ViewPageManager(MainTabControl);
}
protected async Task LoadDataAsync()
{
StartUp.StartUpForm progressForm = new StartUp.StartUpForm();
progressForm.Show();
// 'await' long-running method by wrapping inside Task.Run
await Task.Run(() =>
{
AppSetting setting = new AppSetting();
SqlHelper helper = new SqlHelper(setting.GetConnectionString("cn"));
if(!helper.HandShake())
{
UserLogin userLogin = new UserLogin();
if(userLogin.ShowDialog() == DialogResult.OK)
{
MessageBox.Show("Logged In");
return Task.FromResult(true);
}
else
{
return Task.FromResult(false);
}
}
else
{
return Task.FromResult(true);
}
}
).ContinueWith(new Action<Task>(task =>
{
//if (this.IsHandleCreated)
// Close modal dialog
// No need to use BeginInvoke here
// because ContinueWith was called with TaskScheduler.FromCurrentSynchronizationContext()
progressForm.Close();
}), TaskScheduler.FromCurrentSynchronizationContext());
}
由于这一行,您陷入了僵局:
LoadDataAsync().Wait();
当您从 UI 线程执行
Task.Run
而没有使用 await
而是使用 .Wait()
时,将会产生死锁。新线程完成后,它会尝试与原始 UI 线程通信,表示它已完成,但 UI 线程被冻结.Wait()
以使其完成。
使用
await
可防止 UI 线程冻结,同时仍等待新线程完成。根据经验,从主 UI 线程调用异步代码时始终使用 await
。
只需将您的
ProgramMain
方法更改为异步任务并使用等待:
public async Task ProgramMain()
{
InitializeComponent();
await LoadDataAsync();
_viewPageManager = new ViewPageManager(MainTabControl);
}
您可能仍然会遇到问题,因为您从不同的线程创建了一个
new UserLogin
对话框。 UI 元素应始终从原始 UI 线程创建和访问。
这就是我编写您的
LoadDataAsync
代码的方式:
protected async Task LoadDataAsync()
{
StartUp.StartUpForm progressForm = new StartUp.StartUpForm();
progressForm.Show();
// 'await' long-running method by wrapping inside Task.Run
bool handshakeSuccessful = await Task.Run(() =>
{
AppSetting setting = new AppSetting();
SqlHelper helper = new SqlHelper(setting.GetConnectionString("cn"));
return helper.HandShake();
});
if (!handshakeSuccessful)
{
UserLogin userLogin = new UserLogin();
if(userLogin.ShowDialog() == DialogResult.OK)
{
MessageBox.Show("Logged In");
handshakeSuccessful = true;
}
}
progressForm.Close();
}
public class ProgramStartUp : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
SplashScreen = new StartUp.StartUpForm();
}
protected override void OnCreateMainForm()
{
var task = Task.Run(() => LoadDataAsync());
task.Wait();
MainForm = new ProgramMain();
}
protected async Task LoadDataAsync()
{
// 'await' long-running method by wrapping inside Task.Run
bool handshakeSuccessful = await Task.Run(() =>
{
AppSetting setting = new AppSetting();
SqlHelper helper = new SqlHelper(setting.GetConnectionString("cn"));
if (!helper.HandShake())
{
UserLogin userLogin = new UserLogin();
if (userLogin.ShowDialog() == DialogResult.OK)
{
return true;
}
}
return false;
});
}
}
我是使用线程的新手,所以请告诉我这是否正确。
protected override void OnCreateMainForm()
{
SystemUsers users = new SystemUsers();
var progress = new Progress<LoginStatus>();
LoginStatus status = new LoginStatus();
while (status != LoginStatus.Success || status == LoginStatus.Disconnected)
{
if (status != LoginStatus.Failure) { status = Task.Run(async () => await users.Login(progress)).GetAwaiter().GetResult(); }
string userName = "";
string password = "";
if (status == LoginStatus.Failure)
{
UserLogin userLogin = new UserLogin(users);
if (userLogin.ShowDialog() == DialogResult.Continue)
{
userName = userLogin.UserName;
password = userLogin.Password;
}
else
{
status = LoginStatus.Disconnected;
}
status = Task.Run(async () => await users.Login(progress, userName, password)).GetAwaiter().GetResult();
if (status == LoginStatus.Failure)
{
MessageBox.Show("Error Incorrect Username or Password Entered", "Invlaid User Information", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
MainForm = new StruHubMain(users);
}
public async Task<LoginStatus> Login(IProgress<LoginStatus> progress)
{
LoginStatus loginStatus = new LoginStatus();
loginStatus = LoginStatus.Attempt;
if (progress != null) { progress.Report(loginStatus); }
await Task.Run(() =>
{
AppSetting setting = new AppSetting();
SqlHelper helper = new SqlHelper(setting.GetConnectionString("cn"));
if (helper.HandShake())
{
setting.SaveConnectionString("conn", setting.GetConnectionString("conn"));
_currentUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
if (_users == null && fillUsers)
{
FillUsers();
}
loginStatus = LoginStatus.Success;
}
else
{
loginStatus = LoginStatus.Failure;
}
});
progress.Report(loginStatus);
return loginStatus;
}
public async Task<LoginStatus> Login(IProgress<LoginStatus> progress,string userName, string password)
{
LoginStatus loginStatus = new LoginStatus();
loginStatus = LoginStatus.Attempt;
if (progress != null) { progress.Report(loginStatus); }
await Task.Run(() =>
{
AppSetting setting = new AppSetting();
SqlHelper helper = new SqlHelper(setting.GetConnectionString("cn").Replace("Integrated Security=True", $"User ID={userName};pwd={password};Integrated Security=False"));
if (helper.HandShake())
{
setting.SaveConnectionString("conn", setting.GetConnectionString("cn").Replace("Integrated Security=True", $"User ID={userName};pwd={password};Integrated Security=False"));
helper = new SqlHelper(setting.GetConnectionString("conn"));
if (helper.HandShake())
{
_currentUser = userName;
if (_users == null && fillUsers)
{
FillUsers();
}
loginStatus = LoginStatus.Success;
}
else
{
loginStatus = LoginStatus.Failure;
}
}
else
{
loginStatus = LoginStatus.Failure;
}
});
progress.Report(loginStatus);
return loginStatus;
}