2011-01-28 2 views
6

У меня есть ListBox, который связан с BindingList. BindingList создается, когда стороннее приложение вызывает событие. Я вижу, что 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 по желанию, но noothing добавляется к lsbEntities - почему?

ответ

11

(переход права на последний пример, если вы хотите увидеть его фиксированным и т.д.)

Нити и «Наблюдатель» модель (такие как привязки данных на WinForms) хорошие друзья редко. Вы можете попробовать заменить использование вашего BindingList<T> кодом ThreadedBindingList<T>, который я использовал на previous answer, но эта комбинация потоков и пользовательского интерфейса не является преднамеренным прецедентом привязки данных winforms.

ListBox сам должен поддерживать связывание через список уведомлений событий (IBindingList/IBindingListView), до тех пор, как они прибывают, формируют правильную нить. ThreadedBindingList<T> пытается исправить это путем переключения потоков от вашего имени. Обратите внимание, что для этого вам нужно должно создать ThreadedBindingList<T> из потока пользовательского интерфейса, после имеет контекст синхронизации, то есть после того, как он начал отображать формы.


Для иллюстрации того, что ListBox делает уведомления список-изменения уважения (при работе с одним потоком):

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

Спасибо! Я собираюсь попробовать это. Я не уверен, почему - в моем коде - используется другой поток? Я не определяю его явно для использования. Не могли бы вы рассказать мне, почему? – wulfgarpro

+2

Не только ваши примеры помогли мне понять природу потоков в WinForms; Я узнал о пуле потоков, делегатах и ​​обработке событий. Большое вам спасибо за ваше время и усилия. С этой основой я теперь могу получить более полное представление о C# и разработке программного обеспечения в целом. – wulfgarpro

+0

@WulfgarPro - на нескольких типах (возможно, BindingSource?) Есть событие, которое возникает при сбое привязки. Если вы подписаны на это мероприятие, вы можете получить гораздо больше информации об сообщениях об ошибках, которые в противном случае будут тихими. –

Смежные вопросы