【问题标题】:BindingList not updating bound ListBoxBindingList 不更新绑定的 ListBox
【发布时间】:2011-06-16 22:42:41
【问题描述】:

我有一个绑定到BindingList 的ListBox。 BindingList 是在第三方应用程序引发事件时建立的。我可以看到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 - 为什么?

【问题讨论】:

    标签: c# winforms data-binding


    【解决方案1】:

    (如果您想查看它是否已修复等,请直接跳到最后一个示例)

    线程和“观察者”模式(例如 winforms 上的数据绑定)很少是好朋友。您可以尝试用我在 previous answer 上使用的 ThreadedBindingList&lt;T&gt; 代码替换您的 BindingList&lt;T&gt; 用法 - 但这种线程和 UI 的组合并不是 winforms 数据绑定的有意用例。

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


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

    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&lt;T&gt;(它不适用于常规的BindingList&lt;T&gt;):

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

    【讨论】:

    • 谢谢!我正要试试这个。我不确定为什么 - 在我的代码中 - 正在使用不同的线程?我没有明确定义一个使用。你能告诉我为什么吗?
    • 你的例子不仅帮助我理解了WinForms中线程的本质;我已经了解了线程池、委托和事件处理。非常感谢您的时间和精力。有了这个基础,我现在可以更广泛地了解 C# 和软件开发。
    • @WulfgarPro - 在一些类型上(可能是 BindingSource?),当绑定失败时会引发一个事件。如果您订阅此事件,您可以获得更多关于错误消息的更多信息,否则这些消息是无声的。
    猜你喜欢
    • 1970-01-01
    • 2013-06-10
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 2015-01-04
    • 2019-04-04
    相关资源
    最近更新 更多