背景工作者在windows窗体应用中填充组合框

时间:2014-10-20 06:17:24

标签: c# winforms active-directory backgroundworker

我想在我的Windows应用程序中实现后台工作程序。 目前我正在使用按钮事件处理程序来加载带有数据的组合框。当查询挂起用户界面时,我想实现后台工作程序,因为查询在不同的线程中运行。在我的任何应用程序中,我从未使用过这个后台工作程序。我对此做了一些研究,仍然无法实现这一点。任何帮助或建议将不胜感激。

这是我的按钮事件处理程序的样子

private void button6_Click(object sender, EventArgs e)
        {
            if (comboBox1.SelectedItem.ToString() == "All")
            {

               findAllUser();

            }

            else
            {
                //Do Something!!!

            }
        }     

findAllUser()将从活动目录中获取所有用户,这通常需要时间并使UI无响应。 findAllUser()的代码如下所示。

public void findAllUser()
    {
        System.DirectoryServices.DirectoryEntry entry = new System.DirectoryServices.DirectoryEntry("LDAP://DC=xyz, DC=com");
        System.DirectoryServices.DirectorySearcher mySearcher = new System.DirectoryServices.DirectorySearcher(entry);
        mySearcher.Filter = "(&(objectClass=user))";

        foreach (System.DirectoryServices.SearchResult resEnt in mySearcher.FindAll())
        {
            try
            {
                System.DirectoryServices.DirectoryEntry de = resEnt.GetDirectoryEntry();
                comboBox2.Items.Add(de.Properties["GivenName"].Value.ToString() + " " + de.Properties["sn"].Value.ToString() + " " + "[" + de.Properties["sAMAccountName"].Value.ToString() + "]");
            }

            catch (Exception)
            {
                // MessageBox.Show(e.ToString());
            }
        }

    }

以下是后台工作人员现在的样子......所有空

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {


        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {


        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

        }

任何建议我如何实现上面的代码,以便后台工作者将使用活动目录用户列表填充combobox2。

enter image description here

4 个答案:

答案 0 :(得分:2)

最简单的方法是让您的findAllUser方法构建一个需要添加到组合框的项目列表,然后使用RunWorkerCompleted方法填充组合框。例如,像这样修改findAllUser

private List<string> items;
public void findAllUser()
{
    items = new List<string>();

    System.DirectoryServices.DirectoryEntry entry =
        new System.DirectoryServices.DirectoryEntry("LDAP://DC=xyz, DC=com");
    System.DirectoryServices.DirectorySearcher mySearcher =
        new System.DirectoryServices.DirectorySearcher(entry);
    mySearcher.Filter = "(&(objectClass=user))";

    foreach (System.DirectoryServices.SearchResult resEnt in mySearcher.FindAll())
    {
        try
        {
            System.DirectoryServices.DirectoryEntry de = resEnt.GetDirectoryEntry();
            items.Add(de.Properties["GivenName"].Value.ToString() + " " +
                de.Properties["sn"].Value.ToString() + " " + "[" +
                de.Properties["sAMAccountName"].Value.ToString() + "]");
        }

        catch (Exception)
        {
            // MessageBox.Show(e.ToString());
        }
    }
}

然后,让DoWork来电findAllUser来完成实际工作。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    findAllUser();
}

最后,让你的RunWorkerCompleted填充组合框:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    foreach (var item in items)
    {
        comboBox2.Items.Add(item);
    }
}

如果您想显示进度,那么您需要在工作人员开展业务时不时致电ReportProgress。由于您不确切知道该过程需要多长时间,或者确切知道它将找到多少用户,因此您无法准确报告准确的进度。在那种情况下,你必须猜测。既然你说它需要30秒,&#34;然后你可以使用它作为100%标记。所以当工人开始处理时你开始StopWatch,并且每半秒左右更新一次。修改您的findAllUser功能,如下所示:

public void findAllUser()
{
    const int ExpectedTime = 30000; // 30,000 milliseconds
    // stopwatch keeps track of elapsed time
    Stopwatch sw = Stopwatch.StartNew();
    // Create a timer that reports progress at 500 ms intervals
    System.Timers.Timer UpdateTimer;
    UpdateTimer = new System.Threading.Timer(
        null,
        {
            var percentComplete = (100 * sw.ElapsedMilliseconds) / ExpectedTime;
            if (percentComplete > 100) percentComplete = 100;

            ReportProgress(percentComplete);

            // Update again in 500 ms if not already at max
            if (percentComplete < 100)
                UpdateTimer.Change(500, Timeout.Infinite);
        }, 500, Timeout.Infinite);
    items = new List<string>();

    // rest of findAllUser here

    // dispose of the timer.
    UpdateTimer.Dispose();
}

然后,在ProgressChanged事件处理程序中,更新进度条。

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // Update the progress bar with the value from e.ProgressPercentage

    }

同样,因为你不确切地知道要花多长时间,所以你要做出估计。在上面,我估计30秒,并且代码盲目地假设如果15秒已经过去,那么它完成了一半。

请注意,我将计时器创建为一次性,并在每次打勾后重新初始化。我这样做是因为我想阻止并发更新。计时器在单独的线程上触发,ReportProgress方法将对ProgressChanged事件的调用封送到UI线程。如果UI线程忙于其他事情,那么可能会有另一个计时器事件进入,你最终可能会遇到一堆线程,它们都试图封锁对UI的调用。在这种情况下可能不是问题,因为我们只说最多60个电话(每秒两次电话30秒),但一般情况下,防止这类事情发生是一个好主意。< / p>

答案 1 :(得分:1)

将您的代码放在 backgroundWorker1_DoWork 上。但我建议你使用线程任务并行库

如果您使用的是.NET 4.0,请使用TPL。

你可以这样做:

    Task runner = new Task(() =>
    {
        // do process here
    });
    runner.Start();

如果您使用旧框架,请使用此类线程。

    Thread thread = new Thread(() =>
    {
        // do process here
    });
    thread.IsBackground = true;
    thread.Start();

详细了解TPLThread

答案 2 :(得分:1)

使用BackgroundWorker非常方便,因为它可以在UI线程中自动调用ProgressChanged和RunworkerCompleted事件处理程序。您可以像下面一样使用它。

    private void AddItem(DirectoryEntry de)
    {
        comboBox2.Items.Add(de.Properties["GivenName"].Value.ToString() + " " + de.Properties["sn"].Value.ToString() + " " + "[" + de.Properties["sAMAccountName"].Value.ToString() + "]");
    }

    private void button6_Click(object sender, EventArgs e)
    {
        if (comboBox1.SelectedItem.ToString() == "All")
        {

            this.backgroundWorker1.RunWorkerAsync();

        }

        else
        {
            //Do Something!!!

        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        // Bind to the users container.
        DirectoryEntry entry = new DirectoryEntry("LDAP://CN=xyz,DC=com");
        // Create a DirectorySearcher object.
        DirectorySearcher mySearcher = new DirectorySearcher(entry);

        try
        {
            // Create a SearchResultCollection object to hold a collection of SearchResults
            // returned by the FindAll method.
            SearchResultCollection result = mySearcher.FindAll();
            int count = result.Count;

            for(int i = 0; i < count; i++)
            {
                SearchResult resEnt = result[i];

                try
                {
                    DirectoryEntry de = resEnt.GetDirectoryEntry();

                    BeginInvoke(new Action<DirectoryEntry>(AddItem), de);
                }
                catch (Exception)
                {
                    // MessageBox.Show(e.ToString());
                }

                this.backgroundWorker1.ReportProgress(i / count);
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Value = e.ProgressPercentage;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.progressBar1.Value = 100;
    }

答案 3 :(得分:0)

您可以使用以下逻辑为您的代码实现后台工作程序。

var startListenerWorker = new BackgroundWorker();
                startListenerWorker.DoWork += new DoWorkEventHandler(this.StartListenerDoWork);
                startListenerWorker.RunWorkerAsync();


private void StartListenerDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
        {

// Your logic to load comboBox will go here for running your query
}

你也可以实现线程让你的逻辑在一个单独的线程上运行。