2011-01-28 18 views
6

Mam ListBox, który jest powiązany z BindingList. Model BindingList jest tworzony, gdy aplikacja innej firmy wywołuje zdarzenie. Widzę, że BindingList jest prawidłowo związany ... ale nic nie wchodzi do ListBox. Użyłem tej samej logiki z niektórymi własnymi niestandardowymi typami i zwykle działa bardzo dobrze.BindingList nie aktualizuje związanego listBox

klasy Forma klasy

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

Fasada

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

klasy Scenariusz

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

widzę e vent fire z aplikacji innej firmy - to dodaje podmiot do _entityList zgodnie z życzeniem, ale nic nie jest dodawane do lsbEntities - dlaczego?

Odpowiedz

11

(wskoczyć do ostatniego przykładu, jeśli chcesz zobaczyć to ustalone itp)

wątki i wzorce „obserwatora” (takich jak dane wiążące na WinForms) dobrymi przyjaciółmi są rzadko. Możesz spróbować zastąpić swoje użycie BindingList<T> kodem ThreadedBindingList<T>, którego użyłem na previous answer - ale ta kombinacja wątków i interfejsu użytkownika nie jest celowym przypadkiem użycia wiązania danych winforms.

Pole listy Sam powinny wspierać poprzez wiązanie lista wydarzeń powiadomień (IBindingList/IBindingListView), tak długo jak oni przybywają tworzą właściwą nitkę. ThreadedBindingList<T> próbuje to naprawić przez przełączanie wątków w Twoim imieniu. Zauważ, że aby to zadziałało, musisz utworzyć utworzyć ThreadedBindingList<T> z wątku UI, po ma on kontekst synchro- nizacji, tj. Po rozpoczęciu wyświetlania formularzy.


celu zilustrowania stopnia, że ​​LISTBOX ma informację lista wymienialnych zakresie (gdy chodzi o pojedynczą nić):

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

a teraz dodano gwintowania/ThreadedBindingList<T> (nie robi Działa z regularnym 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

Dzięki! Właśnie chcę to wypróbować. Nie jestem pewien dlaczego - w moim kodzie - używany jest inny wątek? Nie definiuję jednoznacznie do użytku. Czy możesz mi powiedzieć, dlaczego? – wulfgarpro

+2

Nie tylko twoje przykłady pomogły mi zrozumieć naturę wątków w WinFormach; Dowiedziałem się o łączeniu wątków, delegatach i obsłudze zdarzeń. Dziękuję bardzo za poświęcony czas i wysiłek. Dzięki tej podstawie mogę teraz uzyskać szersze zrozumienie C# i rozwoju oprogramowania w ogóle. – wulfgarpro

+0

@WulfgarPro - w przypadku niektórych typów (BindingSource maybe?) Istnieje zdarzenie, które jest wywoływane, gdy powiązanie nie powiedzie się. Jeśli zasubskrybujesz to wydarzenie, możesz uzyskać o wiele więcej informacji na temat komunikatów o błędach, które w przeciwnym razie milczą. –