2011-01-28 5 views
6

를 업데이트하지 나는 BindingList에 바인딩 된 ListBox 있습니다. BindingList은 타사 응용 프로그램에서 이벤트를 발생시킬 때 만들어집니다. BindingList이 바운드 된 것을 볼 수 있지만 아무 것도 ListBox에 들어갑니다. 내 자신의 사용자 지정 형식 중 일부와 동일한 논리를 사용하고 일반적으로 잘 작동합니다.는 바인딩이 결합 된 목록 상자

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

은 (당신이 등을 고정보고 싶다면 마지막 예제에서 오른쪽으로 이동). 당신은 내가 previous answer에 사용되는 ThreadedBindingList<T> 코드를 사용하여 BindingList<T> 사용을 대체하는 시도 할 수 있었다 - 그러나 스레드의 조합 및 UI는 윈폼는 데이터 바인딩의 의도적 인 사용이 아니다.

목록 상자 자체는만큼 그들은 올바른 스레드를 형성 도착, 목록 알림 이벤트 (IBindingList/IBindingListView)를 통해 바인딩을 지원해야합니다. ThreadedBindingList<T> 스레드를 대신하여이 문제를 해결하려고 시도합니다. 이것은 당신이 가 동기화 컨텍스트, 즉 그 형태를 표시 시작된 후이있다 후 UI 스레드에서 ThreadedBindingList<T>, 를 작성해야 작동하는 것을 유의하십시오.


가 (단일 스레드를 처리 할 때) 관련 목록 - 변경 통지를하지 목록 상자 지점 설명하기 : 추가/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); 
     } 
    } 
} 

과을 (그것은 아무튼 정규 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일까요?)에는 바인딩이 실패 할 때 발생하는 이벤트가 있습니다. 이 이벤트에 가입하면 침묵하는 오류 메시지에 대한 많은 정보를 얻을 수 있습니다. –