在UI中显示繁忙指示器控件
本文关键字:指示器 控件 显示 UI | 更新日期: 2023-09-27 18:27:32
我修改了代码,但现在我遇到了另一个问题。在验证用户信息的if语句中发生InvalidOperation异常。它说调用线程不能访问这个对象,因为另一个线程拥有它。有什么建议吗?
private void finishConfigButton_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
bool validated = false;
errorLabel.Visibility = System.Windows.Visibility.Collapsed;
validationProfile.IsBusy = true;
finishConfigButton.IsEnabled = false;
backToLoginHyperlink.IsEnabled = false;
worker.DoWork += (o, ea) =>
{
if (newUser.ValidateNewUserInformation(newNameTextBox.Text, newEmailTextBox.Text, newUsernameTextBox.Text, newPasswordPasswordBox.Password, ref errorLabel))
{
validated = true;
string activeDir = Environment.SystemDirectory.Substring(0, 1) + @":'Users'" + Environment.UserName + @"'My Documents'SSK'Users";
string newPath = System.IO.Path.Combine(activeDir, newUser.Username);
Directory.CreateDirectory(newPath);
newUser.SaveUserData(newUser);
newPath = System.IO.Path.Combine(activeDir, newUser.Username + @"'Settings");
Directory.CreateDirectory(newPath);
newUserSettings.SetDefaultValues();
newUserSettings.SaveSettings(newUser, newUserSettings);
}
else
validated = false;
if (worker.CancellationPending)
{
ea.Cancel = true;
return;
}
};
worker.RunWorkerCompleted += (o, ea) =>
{
validationProfile.IsBusy = false;
finishConfigButton.IsEnabled = true;
backToLoginHyperlink.IsEnabled = true;
};
worker.RunWorkerAsync(this);
if (validated)
{
IntelliMonitorWindow intelliMonitor = new IntelliMonitorWindow(newUser, newUserSettings);
intelliMonitor.Show();
this.Close();
}
else
errorLabel.Visibility = System.Windows.Visibility.Visible;
}
您在这里所做的是在UI线程上运行所有内容。这意味着,当重代码正在运行时,您会阻止UI重新绘制,因此validationProfile直到方法结束时才会更新,其中IsBusy设置为false。
您需要做的是将繁重的代码处理到一个新的线程中,该线程可以同时更新UI。
看看扩展工具包的创建者Brian Lagunas写的这篇博客文章:http://elegantcode.com/2011/10/07/extended-wpf-toolkitusing-the-busyindicator/
他解释了如何在BackgroundWorker中使用BusyIndicator。
XAML代码中的繁忙指示符没有任何内容。放入一些控件:
<wpfet:BusyIndicator Name="validationProfile" IsBusy="False" BusyContent="Working...Please wait" DisplayAfter="0" Background="DimGray">
<Grid>
...
</Grid>
</wpfet:BusyIndicator>
如果您更改为忙,这些控件将被禁用,并且BusyIndicator将显示在它们的上方。
我想你想用BusyIndicator包装整个<Grid Background="LightGray">
。
使用后台工作线程或新线程来运行繁重的进程并释放UI线程。这可以帮助您更新UI,即使后台进程正在运行
例如:
public void finishConfigButton_Click()
{
worker = new BackgroundWorker();
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
//Do the heavy work here
};
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
//Things to do after the execution of heavy work
validationProfile.IsBusy = false;
};
validationProfile.IsBusy= true;
worker.RunWorkerAsync();
}
}
我终于弄明白了。不能在worker内部使用UI对象。DoWork块。我稍微修改了代码,现在它可以工作了。
private void finishConfigButton_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
errorLabel.Visibility = System.Windows.Visibility.Collapsed;
validationProfile.IsBusy = true;
finishConfigButton.IsEnabled = false;
backToLoginHyperlink.IsEnabled = false;
bool validated = false;
string newName = newNameTextBox.Text;
string newEmail = newEmailTextBox.Text;
string newUsername = newUsernameTextBox.Text;
string newPassword = newPasswordPasswordBox.Password;
string errorMessage = "Unknown error.";
worker.DoWork += (o, ea) =>
{
if (newUser.ValidateNewUserInformation(newName, newEmail, newUsername, newPassword, ref errorMessage))
{
string activeDir = Environment.SystemDirectory.Substring(0, 1) + @":'Users'" + Environment.UserName + @"'My Documents'SSK'Users";
string newPath = System.IO.Path.Combine(activeDir, newUser.Username);
Directory.CreateDirectory(newPath);
newUser.SaveUserData(newUser);
newPath = System.IO.Path.Combine(activeDir, newUser.Username + @"'Settings");
Directory.CreateDirectory(newPath);
newUserSettings.SetDefaultValues();
newUserSettings.SaveSettings(newUser, newUserSettings);
validated = true;
}
else
ea.Cancel = true;
};
worker.RunWorkerCompleted += (o, ea) =>
{
if (validated)
{
IntelliMonitorWindow intelliMonitor = new IntelliMonitorWindow(newUser, newUserSettings);
intelliMonitor.Show();
this.Close();
}
validationProfile.IsBusy = false;
finishConfigButton.IsEnabled = true;
backToLoginHyperlink.IsEnabled = true;
errorLabel.Visibility = System.Windows.Visibility.Visible;
errorLabel.Content = errorMessage;
};
worker.RunWorkerAsync();
}