2011-01-28 3 views
6

BindingListにバインドされているListBoxがあります。 BindingListは、サードパーティのアプリケーションがイベントを発生させたときに構築されます。 BindingListが正しくバインドされていますが、ListBoxは何も入力されません。私は自分のカスタムタイプのいくつかとまったく同じロジックを使用していますが、通常はとてもうまく動作します。BindingListがバインディングリストボックスを更新しない

Formクラス

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には何も追加されません - なぜですか?

答えて

11

スレッドと(そのようなデータ・バインディングリサイズのような)「オブザーバー」のパターンはめったに良い友達ではない(あなたはそれがなどを固定表示したい場合は、最後の例の権利をジャンプ)。 BindingList<T>の使用方法をprevious answerで使用したThreadedBindingList<T>コードに置き換えることができますが、このスレッドとUIの組み合わせはwinformsデータバインディングの意図的な使用例ではありません。

リストボックス自体が限り、彼らは右ねじを形成到着すると、リストの通知イベント(IBindingList/IBindingListView)を介して結合サポートすべきです。 ThreadedBindingList<T>あなたの代わりにスレッドを切り替えてこれを修正しようとします。これがうまくいくためにはでなければならず、UIスレッドからThreadedBindingList<T>を作成する必要があります。の後に、同期コンテキストがある、つまりフォームの表示を開始した後です。


(単一のスレッドを扱う場合)リストボックスに対するリスト変更通知を行うことポイント例示する:

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>で今(それはdoesnのを通常の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かもしれない?)には、バインディングが失敗したときに発生するイベントがあります。このイベントを購読すると、そうでなければサイレントなエラーメッセージに関する多くの情報を得ることができます。 –

関連する問題