我的View中有一个backgroundworker,它在我的DAL中运行一个sql查询。
在我看来,我还有一个进度条,它一直在旋转,因此用户知道正在完成工作。
SQL查询作为条件之一接收List<string>
,我在其中一个where条件中填充,所以代码是这样的:
using (SqlConnection conn = new SqlConnection(_myHost))
{
conn.Open();
foreach (string item in myList)
{
query = "select * from ( " +
"//big query with inner joins here" +
") a "
using (SqlCommand cmd = new SqlCommand(query, conn))
{
SqlDataReader reader = cmd.ExecuteReader();
dt.Load(reader);
}
}
因此,正如您在上面注意到的那样,我遍历列表中的所有项目,分别在where子句(上面省略)上查询它们,并将输出(如果有的话)添加到数据表中,一旦foreach完成,它将是返回到我的视图层,成为gridview的数据源。
我想到虽然我无法查询服务器告诉我查询的哪个百分点已经完成,但也许我能够提供foreach循环的完成百分比,这对用户来说是一些信息。
我想弄清楚的是:
回到我的视图,循环的当前迭代,我可以通过简单地添加int i
计数器并在每个foreach上递增它来检测,或者在开头可能是string item
来通知什么正在被质疑。
事情是,我不知道如何在代码执行时将该值返回到我的视图中。我考虑过C#4 Tuple,但它不起作用,因为只有在方法完成后才返回,而不是在foreach
执行期间返回。
有什么想法吗?
答案 0 :(得分:2)
在WinForms应用程序中,最简单的方法是在BackgroundWorker内部向您的应用程序传达事务状态,提升调用ReportProgress method的ProgressChanged事件并在适当的代码中捕获它。
此事件在表单所在的线程(UI线程)中引发,因此trying to access UI components from a non UI thread没有问题。
所以例如你可以写这样的东西
// this code is the DoWork event of the BackgroundWorker
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bkw = sender as BackgroundWorker;
.....
using (SqlConnection conn = new SqlConnection(_myHost))
{
conn.Open();
int counter = 1;
int total = myList.Count;
foreach (string item in myList)
{
.....
WorkerItem item = new WorkerItem() { Counter = counter, Item = item};
int progress = (100 * counter / total);
bkw.ReportProgress(progress, item);
counter++;
}
}
}
public class WorkerItem
{
public int Counter {get;set;}
public string Item {get;set;}
... add other properties if you like .....
}
然后你的winform代码可以启动BackgroundWorker并以这种方式处理ReportProgress事件
BackgroundWorker bkw = new BackgroundWorker();
bkw.WorkerReportsProgress = true;
bkw.WorkerSupportsCancellation = true;
bkw.ProgressChanged += bgw_ProgressChanged;
bkw.DoWork += bgw_DoWork;
bkw.RunWorkerAsync();
...
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
WorkerItem item = e.UserState as WorkerItem;
... update a progress bar, show the current item in a label etc...
Console.WriteLine($"Completed: {e.ProgressPercentage}% {WorkerItem.Counter} {WorkerItem.Item}");
}
答案 1 :(得分:-1)
这是一种方法 - 将委托传递给在后台线程上运行的方法。
public void Run(Action<int> update)
{
using (SqlConnection conn = new SqlConnection(_myHost))
{
conn.Open();
int index = 0;
foreach (string item in myList)
{
//Perform query
//Notify the caller of progress
update(index);
index++
}
}
}
请注意,回调将在后台线程上执行。
我忘记了BackgroundWorker中内置的ReportProgress方法。