我想在我的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。
答案 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();
答案 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
}
你也可以实现线程让你的逻辑在一个单独的线程上运行。