【问题标题】:Multi-thread C# application with BindingList<T> and DataGridView具有 BindingList<T> 和 DataGridView 的多线程 C# 应用程序
【发布时间】:2013-09-16 13:13:45
【问题描述】:

我有 public static class MyGlobals 用于我的应用程序范围的变量以及多线程处理和更改这些变量。

public static class MyGlobals
{
    public static BindingList<Device> devicesList;
    public static BindingList<Device> availableList;
    public static object listLock = new object();
}

我有一个 Timer 线程,它更新列表的一部分(例如 Device.status 字段)和 UI 线程,这些列表绑定到 DataGridView 表和一些字段(例如 Device.description 字段) 可以在那里手动编辑。

我的问题是当 Timer 线程想要更​​新绑定列表内容时,我得到InvalidOperationException:

Additional information: Cross-thread operation not valid: Control 'gridView1' accessed from a thread other than the thread it was created on.

我在修改MyGlogals 列表的每个代码块周围使用lock(listLock) 语句,但我无法控制DataGridView 如何处理列表。如何让这个应用线程安全?

【问题讨论】:

    标签: c# multithreading winforms datagridview


    【解决方案1】:

    您无法从其他线程更新 UI 线程。

    您可以使用this post 来帮助您解决它: 比如做

         foreach (Device device in MyGlobals.devicesList)
         {
            Invoke(new MethodInvoker(delegate {
                 device.text = "newText";
            }));
         }
    

    或使用background worker:

         BackgroundWorker bg = new BackgroundWorker();
         bg.DoWork += new DoWorkEventHandler(bg_DoWork);
         bg.RunWorkerAsync();
    

    在 bg_DoWork 中:

      void bg_DoWork(object sender, DoWorkEventArgs e)
      {
         foreach (Device device in MyGlobals.devicesList)
         {
               device.text = "newText";
         }
      }
    

    【讨论】:

    • 没有办法告诉 DataGridView DataSource 处理程序使用我的 Timer 线程使用的相同锁吗?性能不会成为问题。
    • @ainla 不太确定如何回答这个问题……我认为这不相关。 c# 不允许您从不同的线程更改 UI,这就是您收到异常的原因...
    • 所以一种方法......将在 UI 线程中为 DataGridView DataSource 设置单独的 BindingLists,然后让 UI 线程使用 lock(MyGlobals) 定期将其列表内容与 MyGlobals.devicesList 内容同步.listLock) 语句同时执行吗?
    • @ainla 是的,但您不必... Invoke 和 BackgroundWorker 的全部意义在于,如果某些事情发生了变化,您不必每 500 次左右检查一次。你可以告诉 UI “嘿,我改变了一些东西,接受它”
    • 异常。您不能在 doWork 中执行 UI 操作(即 bindinglist.add)。将 RunWorkerCompleted 用于 UI 操作。
    【解决方案2】:

    GUI 本身需要从 GUI 线程(主线程)更新。 .NET 提供BackgroundWorker 类就是为了这个目的。与 GUI 的通信可以通过 ProgressChangedRunWorkerCompleted 事件中的任意一个来完成,您可以在其中传递选择的对象(例如要显示的对象)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-02
      • 1970-01-01
      • 2010-12-04
      • 2021-11-04
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多