我正在编写一个简单的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中的示例让我到达现在的位置。
由于
答案 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()
(每次调用在之前的调用返回其数据之前发生),您将同时发生多个查询,并且它们以异步方式运行,可以以任意顺序返回其数据。在您的情况下,这可能是也可能不是问题。