我有一个绑定到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 – 为什么?
@R_404_323@
(如果你想看到它固定等,请跳到最后一个例子)
线程和“观察者”模式(例如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);
- }
- }