[RESOLVED] WinForm Not Responding message while background thread is running
I've got a custom tree view control. It take several seconds for all the nodes to be populated. I decided to kick this functionality off in its own thread to prevent UI locking. The UI is responsive (I can move it), but the "Not Responding" message appears at the top of the form until the thread completes. Did I miss something?
Code:
// This delegate enables asynchronous calls for setting
// the text property on a TreeView control.
delegate void PopulateTreeDelegate(X12View view, Button button);
/// <summary>
/// Handles import button's Click event.
/// </summary>
/// <param name="sender">Object calling the method.</param>
/// <param name="e">Event arguments.</param>
private void ImportButton_Click(object sender, EventArgs e)
{
try
{
// reset controls
this.nextIdButton.Enabled = false;
this.inputFileTextBox.Nodes.Clear();
this.claimIdTextBox.Clear();
this.filteredTextBox.Nodes.Clear();
this.remainingTextBox.Nodes.Clear();
this.nextFilteredButton.Enabled = false;
// load new file
var result = this.openDialog.ShowDialog();
if (result == System.Windows.Forms.DialogResult.OK)
{
var content = System.IO.File.ReadAllText(this.openDialog.FileName);
try
{
// set the control's text property.
// this will be used later to populate tree nodes
this.inputFileTextBox.Text = content;
// do work in seperate thread to prevent UI locking
var thread = new System.Threading.Thread(new System.Threading.ThreadStart(this.AsyncImportFile));
thread.Start();
}
catch (Exception)
{
throw new Exception("There was an error parsing the input file. Ensure this is a non compressed text file and contains valid 837 data.");
}
}
}
catch (Exception ex)
{
this.HandleError(ex);
}
}
/// <summary>
/// This should be initialized in its own thread to prevent UI locking
/// </summary>
private void AsyncImportFile()
{
this.PopulateTree(this.inputFileTextBox, this.nextIdButton);
}
/// <summary>
/// Thread safe method used by async methods to populate nodes in a tree view
/// </summary>
/// <param name="view"></param>
/// <param name="button"></param>
private void PopulateTree(X12View view, Button button)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (view.InvokeRequired)
{
var d = new PopulateTreeDelegate(this.PopulateTree);
this.Invoke(d, new object[] { view, button });
}
else
{
try
{
this.Cursor = Cursors.WaitCursor;
view.PopulateTree();
button.Enabled = true;
this.Cursor = Cursors.Default;
}
catch (Exception ex)
{
this.HandleError(ex);
}
}
}
Re: WinForm Not Responding message while background thread is running
It appears that all you are doing is marshaling the populate routine back to the UI thread. Typically, you would populate and a TreeNode on the secondary thread and return that node back to the UI to assign to the Treeview.
Edit: Bad example code. Will update later
Edit: New Example
VB.Net Code:
Private Sub UpdateTV(node As TreeNode)
TreeView1.Nodes.Clear()
TreeView1.Nodes.Add(node)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim t As Task
t = Task.Factory.StartNew(Sub()
Dim root As New TreeNode
root.Nodes.Add("A")
root.Nodes.Add("B")
Threading.Thread.Sleep(5000) ' simulate long process
Me.Invoke(New Action(Of TreeNode)(AddressOf UpdateTV), root)
End Sub)
End Sub
Re: WinForm Not Responding message while background thread is running
Thanks Tn, you were correct, I was making this a whole lot more complicated. Building the node structure was very fast, so adding the parent to the tree view once at the end of the process as opposed to adding the parent in the beginning solved my problems.