2012-06-22 37 views
0

我正在写一个简单的Windows窗体应用程序,让我进入线程的东西摆动。到目前为止,我拥有的是工作,但我想要做的是将其全部包含在单独的类中,而不是直接在我的表单代码中。类中包含的线程

我有一个后台线程启动并从数据库中检索数据。然后我将这些数据显示在列表框中。

private delegate void UpdateListValues(List<ListBoxItem> itemList); 

private void form_main_Shown(object sender, EventArgs e) 
{    
    // Set the loading text. 
    list_selection.Items.Add(ListHelpers.LoadingItem()); 

    // Start the data access on a seperate thread. 
    Thread worker = new Thread(GetInvoicingData); 
    worker.IsBackground = true; 
    worker.Start(); 
} 

private void GetInvoicingData() 
{ 
    // Query database 
    List<ListBoxItem> values = DAC.GetInvoicingAccounts(); 

    // Display results 
    BeginInvoke(new UpdateListValues(DisplayList), new object[] { values }); 
} 

private void DisplayList(List<ListBoxItem> itemList) 
{ 
    // Display each result 
    list_selection.Items.Clear(); 
    for (int i = 0; i < itemList.Count; i++) 
    { 
     list_selection.Items.Add(itemList[i]); 
    } 
} 

的问题是,在显示列表的方法,我将无法访问列表框(list_selection),因为它是窗体类的一部分。有没有人对我如何做到这一点有任何建议。

此外,我是新的线程,所以随时告诉我,我做的绝对是错误的。我只是用http://www.codeproject.com/Articles/23517/How-to-Properly-Handle-Cross-thread-Events-and-Upd这个例子来让我知道我现在的位置。

感谢

+1

任何你没有使用'BackgroundWorker'的理由? –

+0

请注意,Control.BeginInvoke“在创建控件的底层句柄的线程上异步执行委托”(来自MSDN),因此它在技术上位于同一线程中。 –

+0

@BryanCrosby并非如我所说的那样,我只是跟着那篇文章而已。似乎有很多不同的方式来使用线程我不确定在哪种情况下使用哪一种。 –

回答

2

怎么是这样的:

// Added the form's class declaration to highlight separation of thread code into a separate class, but may not be exactly the same as yours depending on naming 
public class Form1 : Form 
{ 
    private readonly DataRetriever _dataRetriever; 

    private void form_main_Shown(object sender, EventArgs e) 
    {    
     // Set the loading text. 
     list_selection.Items.Add(ListHelpers.LoadingItem()); 

     // Create the DataRetriever, and provide it with a delegate to DisplayList for returning data 
     _dataRetriever = new DataRetriever(DisplayList); 
     // Start retrieving data on a separate thread... 
     _dataRetriever.GetData(); 
    } 

    private void DisplayList(List<ListBoxItem> itemList) 
    { 
     if (InvokeRequired) 
     { 
      // Ensure the update occurs on the UI thread 
      Invoke((Action)(() => DisplayList(itemList))); 
      return; 
     } 
     // Display each result 
     list_selection.Items.Clear(); 
     foreach (var item in itemList) 
     { 
      list_selection.Items.Add(item); 
     } 
    } 
} 

// Separate class to hold thread code 
public class DataRetriever 
{ 
    public delegate void UpdateCallbackDelegate(List<ListBoxItem> itemList); 

    private readonly UpdateCallbackDelegate _updateCallback; 

    public DataRetriever(UpdateCallbackDelegate updateCallback) 
    { 
     _updateCallback = updateCallback; 
    } 

    public void GetData() 
    { 
     var thread = new Thread(GetInvoicingData) 
     { 
      IsBackground = true 
     }; 
     thread.Start(); 
    } 

    private void GetInvoicingData() 
    { 
     // Not sure whether "DAC" is a static class, if it needs to be constructed 
     // in the DataRetriever's constructor, or passed to it as a parameter 
     _updateCallback(DAC.GetInvoicingAccounts()); 
    } 
} 

正如你可以看到,所有的线程代码现在是在一个单独的类DataRetriever,构建它的时候,以使所提供的委托检索一旦检索完成,数据将被传回表单。处理回调的方法确保将调用编组到UI线程以防止跨线程异常。

我想指出,这不是作为“最好”的方式来做到这一点,而仅仅是作为对问题的回答(如何将线程代码分离到单独的类中)。正如其他人所说的,现在已经有机制来做这种事情了(例如BackgroundWorker)。为了清楚起见,省略了一些复杂性。例如,在这里介绍的实现中,如果您要多次调用GetData()(每次调用在前一次调用返回数据之前发生),那么您将同时发生多个查询,并且当它们异步运行时,可能会返回它们的数据以任意顺序排列。这可能是也可能不是你的情况。

+0

谢谢,看起来正是我想要的。我必须仔细观察一下,然后围住它,但我会尽快回复你。 –