8

我有一个实现 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 引用发送到业务对象以便我以后能够使用这些引用调用调用不是一种选择。

4

3 回答 3

14

我在一个有效的论坛中找到了这门课。只需使用它而不是 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);
        }
    } 
}
于 2009-01-18T19:52:43.707 回答
1

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

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);
    }
  }
}
于 2009-04-09T09:40:49.973 回答
0

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

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);
  }
}

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

于 2014-10-14T03:41:08.860 回答