包含在类中的线程

时间:2012-06-22 02:01:51

标签: c# winforms multithreading

我正在编写一个简单的Windows窗体应用程序,以帮助我了解Threads的内容。到目前为止,我所拥有的是工作,但我想要做的是将它全部包含在一个单独的类中,而不是直接包含在我的表单代码中。

我有一个后台线程,可以从数据库中启动和检索数据。然后我将数据显示在列表框中。

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

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

另外,我是线程新手,所以请随意告诉我,我做错了。我刚刚使用http://www.codeproject.com/Articles/23517/How-to-Properly-Handle-Cross-thread-Events-and-Upd中的示例让我到达现在的位置。

由于

1 个答案:

答案 0 :(得分: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()(每次调用在之前的调用返回其数据之前发生),您将同时发生多个查询,并且它们以异步方式运行,可以以任意顺序返回其数据。在您的情况下,这可能是也可能不是问题。