I am loading a big treeview in a seperate thread. This thread starts at the load event of a form.
All goes well, until an error occurs in the load event. When an error occurs I close the form and the thread that loads my treeview must be aborted. But I don’t know how to do this.
The problem is, that the form is closed and the thread is still working, so I get an InvalidOperationException. The program breaks down and this part of the thread is highlighted:
tvQuestionnaire.Invoke((MethodInvoker)delegate
{
tvQuestionnaire.Nodes.Add(catNode);
});
The treeview on my form is called tvQuestionnaire. The whole function (which is called in my background worker) looks like this:
private void SetTreeviewData()
{
// Get all categories
List<Category> categories = _questionnaire.GetCategoriesFromQuestionnaire();
// Get all questions which are retrieved by the question manager
OrderedDictionary all_ordered_questions = _questionManager.AllQuestions;
// Store all the questions in a List<T>
List<Question> all_questions = new List<Question>();
foreach (DictionaryEntry de in all_ordered_questions)
{
Question q = de.Value as Question;
all_questions.Add(q);
}
foreach (Category category in categories)
{
// Create category node
TreeNode catNode = new TreeNode();
catNode.Text = category.Description;
catNode.Tag = category;
catNode.Name = category.Id.ToString();
// Get all questions which belongs to the category
List<Question> questions = all_questions.FindAll(q => q.CategoryId == category.Id);
// Default set the font to bold (Windows issue)
Font font = new Font(tvQuestionnaire.Font, FontStyle.Regular);
foreach (Question question in questions)
{
// Create question node
TreeNode queNode = new TreeNode();
queNode.Text = question.Question;
queNode.Tag = question;
queNode.Name = "Q" + question.Id;
queNode.NodeFont = font;
// Determine which treenode icon to show
SetTreeNodeIcon(ref queNode, question);
// Add node to category node
catNode.Nodes.Add(queNode);
}
if (_closing)
return;
// Add category node to treeview
tvQuestionnaire.Invoke((MethodInvoker)delegate
{
tvQuestionnaire.Nodes.Add(catNode);
// Now the category (and thus the questions) are added to treeview
// Set questions treenode icon
//SetTreeNodeIcon(questions);
});
}
// Set each category under its parent
for (int i = tvQuestionnaire.Nodes.Count - 1; i >= 0; i--)
{
Category category = tvQuestionnaire.Nodes[i].Tag as Category;
TreeNode node = tvQuestionnaire.Nodes[i];
if (IsWindow(this.Handle.ToInt32()) == 0)
return;
tvQuestionnaire.Invoke((MethodInvoker)delegate
{
if (category.ParentId == null)
return;
else
{
// Find parent node
TreeNode[] parentNodes = tvQuestionnaire.Nodes.Find(category.ParentId.ToString(), true);
//Remove current node from treeview
tvQuestionnaire.Nodes.Remove(node);
parentNodes[0].Nodes.Insert(0, node);
}
});
}
}
This is the only method that my background worker calls.
So my question is, how can I prevent that the Exception occurs? How do I check the form where the treeview is on, is still ‘alive’?
One solution would be to call the CancelAsync method of the backgroundworker (BGW) when you need to close the form. In the DoWork event handler, check at the beginning of the loop that cancellation has not been requested. If it was, exit the loop (and the DoWork handler).
In the form, wait for the BGW to complete (either success or cancellation)