c# – BindingList不更新绑定的ListBox

我有一个绑定到BindingList的ListBox. BindingList是在第三方应用程序引发事件时构建的.我可以看到绑定列表正确绑定…但没有任何内容进入ListBox.我使用了与我自己的一些自定义类型完全相同的逻辑,它通常工作得很好.

表格类

private Facade.ControlFacade _controlFacade;        
public UavControlForm()
{
    InitializeComponent();  
    _controlFacade = new UavController.Facade.ControlFacade();      
    UpdateEntityListBox();
}
private void UpdateEntityListBox()
{
    lsbEntities.DataSource = _controlFacade.GetEntityTally();
    lsbEntities.DisplayMember = "InstanceName";
}

门面课

private Scenario _scenario;
public ControlFacade()
{
    _scenario = new Scenario();
}
public BindingList<AgStkObject> GetEntityTally()
{
    BindingList<AgStkObject> entityTally = _scenario.EntityTally;
    return entityTally;
}

场景类

private static BindingList<IAgStkObject> _entityTally = new BindingList<AgStkObject>();
public Scenario()
{
    if (UtilStk.CheckThatStkIsAvailable())
    {
        UtilStk.StkRoot.OnStkObjectAdded += new IAgStkObjectRootEvents_OnStkObjectAddedEventHandler(TallyScenarioObjects);
        UtilStk.StkRoot.OnStkObjectDeleted += new IAgStkObjectRootEvents_OnStkObjectDeletedEventHandler(TallyScenarioObjects);
    }          
}
private void TallyScenarioObjects(object sender)
{
    List<AgStkObject> tallyOfStkObjects = UtilStk.GetRunningTallyOfAllStkObjects();
    List<string> stkObjectNames = UtilStk.GetInstanceNamesOfStkObjects(tallyOfStkObjects);

    foreach (string stkObjectName in stkObjectNames)
    {
        if (!SearchFlightUavTallyByName(stkObjectName))
        {
            if (!SearchLoiterUavTallyByName(stkObjectName))
            {
                if (!SearchEntityTallyByName(stkObjectName))
                {
                    int i = stkObjectNames.IndexOf(stkObjectName);
                    _entityTally.Add(tallyOfStkObjects[i]);
                }
            }
        }
    }
}

我可以看到来自第三方应用程序的事件触发 – 这会根据需要向_entityList添加一个实体,但是没有任何内容添加到lsbEntities – 为什么?

解决方法

(如果你想看到它固定等,请跳到最后一个例子)

线程和“观察者”模式(例如winforms上的数据绑定)很少是好朋友.您可以尝试替换BindingList< T>与ThreadedBindingList< T>的使用我在previous answer上使用的代码 – 但这种线程和UI的组合并不是winforms数据绑定的故意用例.

列表框本身应该支持通过列表通知事件(IBindingList / IBindingListView)进行绑定,只要它们到达形成正确的线程即可. ThreadedBindingList< T>尝试通过代表您的线程切换来解决此问题.请注意,要使其工作,您必须创建ThreadedBindingList< T>来自UI线程,在它具有同步上下文之后,即在它开始显示表单之后.

为了说明列表框确实尊重列表更改通知(处理单个线程时):

using System;
using System.ComponentModel;
using System.Windows.Forms;
class Foo
{
    public int Value { get; set; }
    public Foo(int value) { Value = value; }
    public override string ToString() { return Value.ToString(); }
}
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        using(var form = new Form())
        using (var lst = new ListBox())
        using (var timer = new Timer())
        {
            var data = new BindingList<Foo>();
            form.Controls.Add(lst);
            lst.DataSource = data;
            timer.Interval = 1000;
            int i = 0;
            timer.Tick += delegate
            {
                data.Add(new Foo(i++));
            };
            lst.Dock = DockStyle.Fill;
            form.Shown += delegate
            {
                timer.Start();
            };
            Application.Run(form);
        }
    }
}

现在添加了线程/ ThreadedBindingList< T> (它不适用于常规BindingList< T>):

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
class Foo
{
    public int Value { get; set; }
    public Foo(int value) { Value = value; }
    public override string ToString() { return Value.ToString(); }
}
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        using(var form = new Form())
        using (var lst = new ListBox())
        {
            form.Controls.Add(lst);            
            lst.Dock = DockStyle.Fill;
            form.Shown += delegate
            {
                BindingList<Foo> data = new ThreadedBindingList<Foo>();
                lst.DataSource = data;
                ThreadPool.QueueUserWorkItem(delegate
                {
                    int i = 0;
                    while (true)
                    {
                        data.Add(new Foo(i++));
                        Thread.Sleep(1000);
                    }
                });
            };
            Application.Run(form);
        }
    }
}
public class ThreadedBindingList<T> : BindingList<T>
{
    private readonly SynchronizationContext ctx;
    public ThreadedBindingList()
    {
        ctx = SynchronizationContext.Current;
    }
    protected override void OnAddingNew(AddingNewEventArgs e)
    {
        SynchronizationContext ctx = SynchronizationContext.Current;
        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)
    {
        if (ctx == null)
        {
            BaseListChanged(e);
        }
        else
        {
            ctx.Send(delegate
            {
                BaseListChanged(e);
            },null);
        }
    }
    void BaseListChanged(ListChangedEventArgs e)
    {
        base.OnListChanged(e);
    }
}

相关文章

在项目中使用SharpZipLib压缩文件夹的时候,遇到如果目录较深,则压缩包中的文件夹同样比较深的问题。比...
项目需要,几十万张照片需要计算出每个照片的特征值(调用C++编写的DLL)。 业务流程:选择照片...
var array = new byte[4]; var i = Encoding.UTF8.GetBytes(100.ToString(&quot;x2&quot;));//...
其实很简单,因为Combox的Item是一个K/V的object,那么就可以把它的items转换成IEnumerable&lt;Dic...
把.net4.6安装包打包进安装程序。 关键脚本如下: 头部引用字符串对比库 !include &quot;WordFunc....
项目需求(Winform)可以批量打印某个模板,经过百度和摸索,使用iTextSharp+ZXing.NetʿreeSp...