0

我正在编写一个简单的 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中的示例来了解我现在的位置。

谢谢

4

1 回答 1

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

于 2012-06-22T03:16:00.080 回答