c# - 成功运行BackgroundWorker() 后程序的其余部分不执行
问题描述
我正在使用 BackgroundWorker() 在后台执行长时间运行的查询,同时显示我的执行正在运行的弹出窗口。
这是我如何调用 bg_worker()
using System.Windows;
using System.ComponentModel;
using System.Threading;
using System;
using System.IO;
using System.Data.SqlClient;
using System.Windows.Input;
namespace TestEnvironment
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class ProgressBarTemplate : Window
{
private CreateProjectScreen _CreateProjectScreen;
private LoginScreen _LoginScreen;
public ProgressBarTemplate()
{
InitializeComponent();
}
public static int RunCalculationsMethod(string connectionstring, string foldername)
{
bool exists = Directory.Exists(foldername);
if (!exists)
{
Directory.CreateDirectory(foldername);
}
try
{
using (SqlConnection sqlConnection = new SqlConnection(connectionstring))
{
var calculations_query = "SELECT * FROM table1");
using SqlCommand sqlCommand = new SqlCommand(calculations_query, sqlConnection);
sqlConnection.Open();
sqlCommand.CommandTimeout = 60 * 10;
int NumbderOfRecords = sqlCommand.ExecuteNonQuery();
return NumbderOfRecords;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return -100;
}
}
private void Window_ContentRendered(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
int IsSuccessful = RunCalculationsMethod("Server=localhost;Database=DB_Name;Integrated Security=SSPI", String.Format("C:\\folder_path\\"));
}
void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// This is called on the UI thread when the DoWork method completes
// so it's a good place to hide busy indicators, or put clean up code
try
{
this.Close();
MessageBox.Show("DQ Calculations completed successfully", "Information", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}
上面的代码放在一个名为 ProgressBarTemplate() 的窗口中
而我想要的是在按钮单击时调用 background_worker 放置在我的 MainWindow 中的按钮
所以我的 MainWindow 有以下按钮点击
private void RunCalculationsButton_Click(object sender, RoutedEventArgs e)
{
//RunCalculationsMethod(SQLServerConnectionDetails(), String.Format("C:\\DQ_Findings_{0}", HomePageTab.Header.ToString().Split(" - ")[1]));
try
{
Application.Current.Dispatcher.Invoke((Action)delegate
{
ProgressBarTemplate win_progressbar = new ProgressBarTemplate();
win_progressbar.Show();
//RunCalculationsMethod(SQLServerConnectionDetails(), String.Format("C:\\DQ_folder_test\\Findings\\"));
}); // The code runs up to this point.
//The code below is not executed for a reason, which I am trying to solve with this question
List<SucessfulCompletion> reportsucessfulcompletion = new List<SucessfulCompletion>();
reportsucessfulcompletion = SuccessfulCalculationsTimestamp(SQLServerConnectionDetails());
if (reportsucessfulcompletion[0].Result==1)
{
//Enable is only if successfull
PreviewCalculationsButton.IsEnabled = true;
PreviewReportButton.IsEnabled = true;
//add textbox of sucess
TickButtonSymbolCalculations.Visibility = Visibility.Visible;
SQLSuccessfulTextCalculations.Visibility = Visibility.Visible;
XerrorSymbolCalculations.Visibility = Visibility.Hidden;
SQLFailedTextCalculations.Visibility = Visibility.Hidden;
SQLSuccessfulTextCalculations.Text = String.Format("Completed On: {0}", reportsucessfulcompletion[0].Timestampvalue);
}
else
{
//add textbox of fail
TickButtonSymbolCalculations.Visibility = Visibility.Hidden;
SQLSuccessfulTextCalculations.Visibility = Visibility.Hidden;
XerrorSymbolCalculations.Visibility = Visibility.Visible;
SQLFailedTextCalculations.Visibility = Visibility.Visible;
SQLFailedTextCalculations.Text = String.Format("Failed On: {0}", reportsucessfulcompletion[0].Timestampvalue);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
单击按钮时,我通过调用窗口 ProgressBarTemplate() 来启动 bg_worder。尽管在完成任务后代码生成一些文本并启用某些按钮的可见性,但它们并没有被执行。为什么会这样?我错过了什么吗?
解决方案
代码有点不清楚,所以我将发布它应该如何完成。
BGW 是自 2012 年以来完全被Progress< T>Task.Run
取代的过时类。无需使用 BGW 或何时可用。Invoke
async/await
您可以使用异步事件处理程序,在后台执行任何计算并在后台操作完成后更新 UI,而不是将计算放在进度窗口中。进度表似乎没有报告任何进度,所以只需要显示和隐藏它。代码可以很简单:
private async void RunCalculationsButton_Click(object sender, RoutedEventArgs e)
{
var win_progressbar = new ProgressBarTemplate();
win_progressbar.Show();
try
{
//Update the UI
var results=await Task.Run(()=> RunCalculationsMethod(...));
//Update the UI
}
finally
{
win_progressbar.Close();
}
}
try/finally
用于确保即使出现错误也关闭表单。
进度报告
进度报告可通过Progress类和IProgress接口获得。IProgress<T>
允许后台任务向实现接口的类发送强类型消息。该Progress<T>
实现确保消息在创建它的线程中处理,通常是 UI 线程。
假设这是消息类型:
class MyProgress
{
public int Percent{get;set;}
public string Message {get;set;}
}
RunCalculationsMethod
可以修改为接受和使用IProgress<MyProgress>
;
public static int RunCalculationsMethod(string connectionstring, string foldername,
IProgress<MyProgress> progress)
{
progress.Report(new MyProgress{Percent=0,Message="Starting"};
....
progress.Report(new MyProgress{Percent=100,Message="Finished"};
}
事件处理程序只需要创建一个Progress<MyProgress>
并提供一个更新 UI 的方法。假设ProgressBarTemplate
有这样一个方法,称为Update(string,int)
:
private async void RunCalculationsButton_Click(object sender, RoutedEventArgs e)
{
var win_progressbar = new ProgressBarTemplate();
IProgress<MyProgress> pg=new Progress<MyProgress>(pg=>
win_progressbar.Update(pg.Message,pg.Percent));
win_progressbar.Show();
try
{
//Update the UI
var results=await Task.Run(()=> RunCalculationsMethod(...,pg));
//Update the UI
}
finally
{
win_progressbar.Close();
}
}
您可以在 4.5 中的 Async 中找到更详尽的解释:在 Async API 中启用进度和取消
推荐阅读
- typescript - 使属性装饰器类型安全似乎只适用于简单的类?
- python - 从 Pandas 的索引中获取类
- reactjs - github action npm run build 不工作,但在本地工作
- javascript - 如何将一个 HTML 表单输入发送到两个不同的 API 并从中获取结果?
- javascript - channel.send 不是函数
- flutter - 以编程方式关闭 Flutter 上的 GPS
- html - 为什么 chrome 开发工具在正文中插入额外的 div
- django - Wagtail 设置仅使用 .dev
- linux - 在将文件中的日期与系统日期进行比较时出现错误:第 7 行:10#2020-12-09: value too great for base (error token is "09")
- javascript - 如何在图像单击时打开图像模式