使用线程C#

Rek*_*kar 6 c# parallel-processing multithreading listbox winforms

我需要一些帮助来试图弄清楚我做错了什么.我正在尝试从单独的线程中获取系统日志中的项集合,以防止表单在收集过程中被冻结.我可以让后台工作者抓住它们,但我有一些问题将它们添加到ListBox表单上.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{

  foreach (System.Diagnostics.EventLogEntry entry in eventLog1.Entries)
  {
     listBox1.Items.Add(
        entry.EntryType.ToString() + " - " + 
        entry.TimeWritten + "     - " + 
        entry.Source);
  }
}
Run Code Online (Sandbox Code Playgroud)

显然这不会按预期工作,因为有2个单独的线程,你不能像我发现的那样更改不同线程上的对象.所以,如果有人能指导我朝着正确的方向前进,我会感激不尽.

Ale*_*Aza 4

您不应从非 UI 线程访问 UI 元素。Run ReportProgress,它将与 UI 线程同步。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    foreach (System.Diagnostics.EventLogEntry entry in eventLog1.Entries)
    {
        var newEntry = entry.EntryType + " - " + entry.TimeWritten + "     - " + entry.Source;
        backgroundWorker1.ReportProgress(0, newEntry);
    }
}

void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    var newEntry = (string)e.UserState;
    listBox1.Items.Add(newEntry);
}
Run Code Online (Sandbox Code Playgroud)

确保您启用WorkerReportsProgress.

backgroundWorker1.WorkerReportsProgress = true;
Run Code Online (Sandbox Code Playgroud)

并订阅了ProgressChanged

backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
Run Code Online (Sandbox Code Playgroud)

Control.Invoke另一种方法是内部调用

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    foreach (System.Diagnostics.EventLogEntry entry in eventLog1.Entries)
    {
        var newEntry = entry.EntryType.ToString() + " - " + entry.TimeWritten + "     - " + entry.Source;
        Action action = () => listBox1.Items.Add(newEntry);
        Invoke(action);
    }
}
Run Code Online (Sandbox Code Playgroud)

但通过这种方法,您不需要BackgroundWorker使用ProgressChangedRunWorkerCompletedUI 线程同步的事件处理程序。