BackgroundWorker在foreach循环期间从DAL返回值

时间:2017-01-13 18:33:13

标签: c# mysql foreach backgroundworker

我的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执行期间返回。

有什么想法吗?

2 个答案:

答案 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方法。

https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.reportprogress(v=vs.110).aspx