我将如何从 backgroundworker 中填充 ListBox?

How would I fill a ListBox from backgroundworker?

我在从后台工作线程填充列表框时遇到问题。我目前有以下代码:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        var lockedUsers = new List<UserPrincipal>();
        using (var context = new PrincipalContext(ContextType.Domain, "domain", smtu, smtp))
        {
            GroupPrincipal grp = GroupPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "Domain Users");
            foreach (var userPrincipal in grp.GetMembers(false))
            {

                var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, userPrincipal.SamAccountName);
                if (user != null)
                {
                    if (user.IsAccountLockedOut())
                    {
                        listBox1.Items.Add(@"domain\ " + user);
                    }
                }
            }
        }
    }

这个 returns 异常说我不能写主 UI,这是正确的。但我一直无法找到解决方法。我已经尝试了以下方法,虽然它没有给出任何错误,但它没有填充列表框。

    List<string> listusers = new List<string>();


    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        var lockedUsers = new List<UserPrincipal>();
        using (var context = new PrincipalContext(ContextType.Domain, "domain", smtu, smtp))
        {
            GroupPrincipal grp = GroupPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "Domain Users");
            foreach (var userPrincipal in grp.GetMembers(false))
            {

                var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, userPrincipal.SamAccountName);
                if (user != null)
                {
                    if (user.IsAccountLockedOut())
                    {
                        listusers.Add(@"domain\" + user);
                    }
                }
            }
        }
    }

    private async void timerlocked_Tick(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
        listBox1.DataSource = listusers;
    }

有什么想法吗?

要从后台工作者访问 UI 线程,您可以在 RunWorkerCompleted event of the BackgroundWorker or - if you want to access the UI while the worker is running, have a look at Control.Invoke 中完成工作。

后者可能是这样的:

if (user.IsAccountLockedOut())
{
    listBox1.Invoke(() => listBox1.Items.Add(@"domain\ " + user));
}

传递给 DoWorkEventHandler 委托的 DoWorkEventArgs 有一个 Result property

Gets or sets a value that represents the result of an asynchronous operation.

您设置的 Result 将通过传递给该委托的 RunWorkerCompletedEventArgs 一起发送到 RunWorkerCompleted 事件。

所以,要解决这个问题,您可以在 DoWork 事件中构建一个 List<string>,将 Result 属性 设置为该列表,处理 RunWorkerCompleted 事件并从 RunWorkerCompletedEventArgs.Result.

访问列表
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var result = new List<string>();
    var lockedUsers = new List<UserPrincipal>();
    using (var context = new PrincipalContext(ContextType.Domain, "domain", smtu, smtp))
    {
        GroupPrincipal grp = GroupPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "Domain Users");
        foreach (var userPrincipal in grp.GetMembers(false))
        {

            var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, userPrincipal.SamAccountName);
            if (user != null)
            {
                if (user.IsAccountLockedOut())
                {
                    result.Add(@"domain\ " + user);
                }
            }
        }
    }
    e.Result = result;
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // Error handling.
    }
    if (e.Cancelled)
    {
       // If you support cancellation...
    }
    listBox1.Items.Clear();
    listBox1.Items.AddRange((e.Result as List<string>).ToArray());
}