BackgroundWorker.RunWorkerAsync() 不进入后台
BackgroundWorker.RunWorkerAsync() doesn't go background
我有与数据库一起工作的 WPF 应用程序。我有 Connect to DB
按钮。当用户单击该按钮时,我想在应用程序尝试连接到数据库时显示一些进度动画。
这是我的按钮和进度动画:
<Button Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="2" Name="btnLogin" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnLogin_Click" Margin="5">
<StackPanel Orientation="Horizontal">
<Image x:Name="btnLoginIcon" Source="pack://application:,,,/Content/Images/Connect_Icon.png" Width="20" Height="20"/>
<TextBlock x:Name="btnLoginText" Text="Connect" VerticalAlignment="Center" />
</StackPanel>
</Button>
<mui:ModernProgressRing Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="2" x:Name="ConnectProgressRing" Width="40" Height="40" Visibility="Hidden" IsActive="True" Style="{StaticResource ThreeBounceProgressRingStyle}" />
这是我的后台工作代码:
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWorkConnect);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerConnectCompleted);
ConnectProgressRing.Visibility = Visibility.Visible;
btnLogin.Visibility = Visibility.Hidden;
bw.RunWorkerAsync();
}
private void LoginToDB()
{
string ServerPath = Server.Text;
string Database = Schema.Text;
dbStr = "Server=" + ServerPath + ";Database=" + Database + ";Trusted_Connection=True;";
try
{
using (SqlConnection conn = new SqlConnection(dbStr))
{
conn.Open();
conn.Close();
}
}
catch (Exception ex)
{
if (ex.Message != null)
{
MessageBoxButton btn = MessageBoxButton.OK;
ModernDialog.ShowMessage(ex.Message, "Failure to connect", btn);
}
}
}
void bw_DoWorkConnect(object sender, DoWorkEventArgs e)
{
Dispatcher.Invoke(new Action(() => {
LoginToDB();
}), DispatcherPriority.ContextIdle);
}
void bw_RunWorkerConnectCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConnectProgressRing.Visibility = Visibility.Hidden;
btnLogin.Visibility = Visibility.Visible;
}), DispatcherPriority.ContextIdle);
}
出于某种原因,当我单击“连接”按钮时出现错误的服务器和数据库时,我的 window 冻结并且在收到错误消息之前我无法执行任何操作。你知道为什么我的 LoginToDB()
没有进入后台吗?
我不确定 bw_RunWorkerConnectCompleted
如何与所有内容联系在一起,但 WPF 可以使用 async/await 模式。这允许在不同的线程上继续执行,并且 UI 线程被释放,因此您的 windows 不会 freeze/hang。这是您重构的代码以使用该模式。同样,我不知道 bw_RunWorkerConnectCompleted
所以我暂时删除了它。
private async Task LoginToDBAsync() // notice the async keyword in the method signature
{
string ServerPath = Server.Text;
string Database = Schema.Text;
dbStr = "Server=" + ServerPath + ";Database=" + Database + ";Trusted_Connection=True;";
try
{
using (SqlConnection conn = new SqlConnection(dbStr))
{
await conn.OpenAsync(); // will release the thread back to the WPF app and connection continues on new thread until it completes
conn.Close();
}
}
catch (Exception ex)
{
if (ex.Message != null)
{
MessageBoxButton btn = MessageBoxButton.OK;
ModernDialog.ShowMessage(ex.Message, "Failure to connect", btn);
}
}
}
// previous name was async void bw_DoWorkConnect(object sender, DoWorkEventArgs e)
async void btnLogin_Click(object sender, RoutedEventArgs e) // notice the async keyword in the method signature. Because its a WPF event callback it returns void and not Task like the above method
{
ConnectProgressRing.Visibility = Visibility.Visible;
btnLogin.Visibility = Visibility.Hidden;
await LoginToDBAsync(); // await db call
// ui code to be executed after the previous call completes.
// the continuation is executed on the UI thread
ConnectProgressRing.Visibility = Visibility.Hidden;
btnLogin.Visibility = Visibility.Visible;
}
这是因为您的异步代码调用了对调度程序线程的调用
Dispatcher.Invoke(new Action(() => {
LoginToDB();
}), DispatcherPriority.ContextIdle);
调度程序将使用与 UI 相同的线程,您的 UI 将冻结。您需要删除 Dispatcher.Invoke 以允许您的代码异步 运行,尽管我猜您已经把它放在那里是因为 LoginToDB 引用了一些 UI 元素?
void bw_DoWorkConnect(object sender, DoWorkEventArgs e)
{
LoginToDB();
}
如果你想更新 UI 那么不要在 DoWork 事件处理程序中捕获异常并让 RunWorkerCompleted 事件处理程序检查 RunWorkerCompletedEventArgs 的错误以更新按钮和显示消息等
private void LoginToDB()
{
string ServerPath = Server.Text;
string Database = Schema.Text;
dbStr = "Server=" + ServerPath + ";Database=" + Database + ";Trusted_Connection=True;";
using (SqlConnection conn = new SqlConnection(dbStr))
{
conn.Open();
conn.Close();
}
}
您不需要在 RunWorkerCompleted 事件处理程序中使用 Dispatcher.Invoke,因为该方法将在 UI 线程上执行。
void bw_RunWorkerConnectCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBoxButton btn = MessageBoxButton.OK;
ModernDialog.ShowMessage(e.Error.Message, "Failure to connect", btn);
return;
}
ConnectProgressRing.Visibility = Visibility.Hidden;
btnLogin.Visibility = Visibility.Visible;
}
我有与数据库一起工作的 WPF 应用程序。我有 Connect to DB
按钮。当用户单击该按钮时,我想在应用程序尝试连接到数据库时显示一些进度动画。
这是我的按钮和进度动画:
<Button Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="2" Name="btnLogin" HorizontalAlignment="Center" VerticalAlignment="Center" Click="btnLogin_Click" Margin="5">
<StackPanel Orientation="Horizontal">
<Image x:Name="btnLoginIcon" Source="pack://application:,,,/Content/Images/Connect_Icon.png" Width="20" Height="20"/>
<TextBlock x:Name="btnLoginText" Text="Connect" VerticalAlignment="Center" />
</StackPanel>
</Button>
<mui:ModernProgressRing Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="2" x:Name="ConnectProgressRing" Width="40" Height="40" Visibility="Hidden" IsActive="True" Style="{StaticResource ThreeBounceProgressRingStyle}" />
这是我的后台工作代码:
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWorkConnect);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerConnectCompleted);
ConnectProgressRing.Visibility = Visibility.Visible;
btnLogin.Visibility = Visibility.Hidden;
bw.RunWorkerAsync();
}
private void LoginToDB()
{
string ServerPath = Server.Text;
string Database = Schema.Text;
dbStr = "Server=" + ServerPath + ";Database=" + Database + ";Trusted_Connection=True;";
try
{
using (SqlConnection conn = new SqlConnection(dbStr))
{
conn.Open();
conn.Close();
}
}
catch (Exception ex)
{
if (ex.Message != null)
{
MessageBoxButton btn = MessageBoxButton.OK;
ModernDialog.ShowMessage(ex.Message, "Failure to connect", btn);
}
}
}
void bw_DoWorkConnect(object sender, DoWorkEventArgs e)
{
Dispatcher.Invoke(new Action(() => {
LoginToDB();
}), DispatcherPriority.ContextIdle);
}
void bw_RunWorkerConnectCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConnectProgressRing.Visibility = Visibility.Hidden;
btnLogin.Visibility = Visibility.Visible;
}), DispatcherPriority.ContextIdle);
}
出于某种原因,当我单击“连接”按钮时出现错误的服务器和数据库时,我的 window 冻结并且在收到错误消息之前我无法执行任何操作。你知道为什么我的 LoginToDB()
没有进入后台吗?
我不确定 bw_RunWorkerConnectCompleted
如何与所有内容联系在一起,但 WPF 可以使用 async/await 模式。这允许在不同的线程上继续执行,并且 UI 线程被释放,因此您的 windows 不会 freeze/hang。这是您重构的代码以使用该模式。同样,我不知道 bw_RunWorkerConnectCompleted
所以我暂时删除了它。
private async Task LoginToDBAsync() // notice the async keyword in the method signature
{
string ServerPath = Server.Text;
string Database = Schema.Text;
dbStr = "Server=" + ServerPath + ";Database=" + Database + ";Trusted_Connection=True;";
try
{
using (SqlConnection conn = new SqlConnection(dbStr))
{
await conn.OpenAsync(); // will release the thread back to the WPF app and connection continues on new thread until it completes
conn.Close();
}
}
catch (Exception ex)
{
if (ex.Message != null)
{
MessageBoxButton btn = MessageBoxButton.OK;
ModernDialog.ShowMessage(ex.Message, "Failure to connect", btn);
}
}
}
// previous name was async void bw_DoWorkConnect(object sender, DoWorkEventArgs e)
async void btnLogin_Click(object sender, RoutedEventArgs e) // notice the async keyword in the method signature. Because its a WPF event callback it returns void and not Task like the above method
{
ConnectProgressRing.Visibility = Visibility.Visible;
btnLogin.Visibility = Visibility.Hidden;
await LoginToDBAsync(); // await db call
// ui code to be executed after the previous call completes.
// the continuation is executed on the UI thread
ConnectProgressRing.Visibility = Visibility.Hidden;
btnLogin.Visibility = Visibility.Visible;
}
这是因为您的异步代码调用了对调度程序线程的调用
Dispatcher.Invoke(new Action(() => {
LoginToDB();
}), DispatcherPriority.ContextIdle);
调度程序将使用与 UI 相同的线程,您的 UI 将冻结。您需要删除 Dispatcher.Invoke 以允许您的代码异步 运行,尽管我猜您已经把它放在那里是因为 LoginToDB 引用了一些 UI 元素?
void bw_DoWorkConnect(object sender, DoWorkEventArgs e)
{
LoginToDB();
}
如果你想更新 UI 那么不要在 DoWork 事件处理程序中捕获异常并让 RunWorkerCompleted 事件处理程序检查 RunWorkerCompletedEventArgs 的错误以更新按钮和显示消息等
private void LoginToDB()
{
string ServerPath = Server.Text;
string Database = Schema.Text;
dbStr = "Server=" + ServerPath + ";Database=" + Database + ";Trusted_Connection=True;";
using (SqlConnection conn = new SqlConnection(dbStr))
{
conn.Open();
conn.Close();
}
}
您不需要在 RunWorkerCompleted 事件处理程序中使用 Dispatcher.Invoke,因为该方法将在 UI 线程上执行。
void bw_RunWorkerConnectCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBoxButton btn = MessageBoxButton.OK;
ModernDialog.ShowMessage(e.Error.Message, "Failure to connect", btn);
return;
}
ConnectProgressRing.Visibility = Visibility.Hidden;
btnLogin.Visibility = Visibility.Visible;
}