【问题标题】:How do you correctly update a databound datagridview from a background thread如何从后台线程正确更新数据绑定 datagridview
【发布时间】:2010-10-02 03:06:54
【问题描述】:

我有一个实现 INotifyPropertyChanged 的​​自定义对象。我有这些对象的集合,其中集合基于 BindingList 我已经为集合创建了一个绑定源,并设置了bindingsource和datagridview的数据源。

一切都很好,除了我需要从后台线程更新自定义对象的属性。当我这样做时,我收到以下错误:

BindingSource 不能是它自己的数据源。不要将 DataSource 和 DataMember 属性设置为引用回 BindingSource 的值

我发现以下帖子似乎有我的确切问题(和解决方案?),但我无法弄清楚。

http://social.msdn.microsoft.com/forums/en-US/winformsdatacontrols/thread/3566f7c7-eb47-422e-ab09-9549a18da360/

我在我的业务对象中创建并初始化每个帖子的操作变量,然后我将这两个事件函数放入我的集合类中。这编译正确,但运行时无异常挂起。

我看到很多帖子说要使用 Invoke/Begin Invoke,但我没有调用 UI 上的任何函数,只是更新业务对象,所以我不确定将调用调用放在哪里。

一个限制:我希望业务对象不知道是谁在显示它(因为有多个消费者),因此将 GUI 引用发送到业务对象以便我以后能够使用这些引用调用调用不是选项。

【问题讨论】:

    标签: c# multithreading data-binding datagridview inotifypropertychanged


    【解决方案1】:

    不是完全线程安全的,但是如果您的后台线程修改对象属性的速度超过了它们的显示速度,那么对上述答案的这个小改动可能会产生很大的影响;

    protected override void OnListChanged(ListChangedEventArgs e)
    {
      // SynchronizationContext ctx = SynchronizationContext.Current;
      if (ctx == null)
      {
        BaseListChanged(e);
      }
      else if(e.ListChangedType == ListChangedType.ItemChanged)
      {
        ctx.Post(delegate { BaseListChanged(e); }, null);
      }
      else
      {
        ctx.Send(delegate { BaseListChanged(e); }, null);
      }
    }
    

    如果同一对象被多次修改,欢迎提出任何减少发布调用数量的建议,并确保在处理完所有发布调用之前,任何以后的发送调用都会阻塞。

    【讨论】:

      【解决方案2】:

      我在一个有效的论坛中找到了这个课程。只需使用它而不是 BindingList

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      
      using System.ComponentModel;
      using System.Threading;
      
      namespace Utility
      {
          public class ThreadedBindingList<T> : BindingList<T>
          {
              SynchronizationContext ctx = SynchronizationContext.Current;
      
              protected override void OnAddingNew(AddingNewEventArgs e)
              {
      
                  if (ctx == null)
                  {
                      BaseAddingNew(e);
                  }
                  else
                  {
                      ctx.Send(delegate
                      {
                          BaseAddingNew(e);
                      }, null);
                  }
              }
              void BaseAddingNew(AddingNewEventArgs e)
              {
                  base.OnAddingNew(e);
              }
              protected override void OnListChanged(ListChangedEventArgs e)
              {
                 // SynchronizationContext ctx = SynchronizationContext.Current;
                  if (ctx == null)
                  {
                      BaseListChanged(e);
                  }
                  else
                  {
                      ctx.Send(delegate
                      {
                          BaseListChanged(e);
                      }, null);
                  }
              }
              void BaseListChanged(ListChangedEventArgs e)
              {
                  base.OnListChanged(e);
              }
          } 
      }
      

      【讨论】:

      • @Marc Gravell [我知道帖子很旧,但是..当从另一个列表 ThreadedBindingList(my Ilist) 实例化时-没有办法。该方法不应该存在以使其“完整”还是存在线程问题?
      【解决方案3】:

      由于我花时间为我的需要格式化示例,我不妨将其发布在此处作为可读参考。除了格式没有任何变化。

      using System.ComponentModel; 
      using System.Threading;
      
      namespace Utility 
      {
        public class ThreadedBindingList : BindingList 
        {
          SynchronizationContext ctx = SynchronizationContext.Current;
          protected override void OnAddingNew(AddingNewEventArgs e)
          {
            if (ctx == null)
            {
              BaseAddingNew(e);
            }
            else
            {
              ctx.Send(delegate { BaseAddingNew(e); }, null);
            }
          }
      
          void BaseAddingNew(AddingNewEventArgs e)
          {
            base.OnAddingNew(e);
          }
      
          protected override void OnListChanged(ListChangedEventArgs e)
          {
            // SynchronizationContext ctx = SynchronizationContext.Current;
            if (ctx == null)
            {
              BaseListChanged(e);
            }
            else
            {
              ctx.Send(delegate { BaseListChanged(e); }, null);
            }
          }
      
          void BaseListChanged(ListChangedEventArgs e)
          {
            base.OnListChanged(e);
          }
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-16
        • 2012-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多