views:

254

answers:

1

I have a treeview using BackGround worker to add nodes when you expand any. I display a "Loading.." message after the expand and remove it after the nodes are loaded. It works fine and all. Now I want to change the loading message to "Loading...node n/n". I was able to do it but the problem is this message is not displayed(updated to) while doing the node adding operation but after it's completed. I couldn't figure out what I'm doing wrong and I hope someone can shed a light on this.

Here's my code. I debugged SetValue method and it correctly updates the node text, but it doesn't displayed until the end of the operation..

private void t_AfterExpand(object sender, NodeEventArgs e)
{
    t.AppendNode(new object[] { "Loading.." }, e.Node);
    bw.RunWorkerAsync(new object[] { e.Node });
}

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    t.Invoke(new MethodInvoker( () => AddSubNodes(e.Argument) ));
    e.Result = e.Argument;
}

private void AddSubNodes(object arg)
{
    object[] args = arg as object[];
    TreeListNode parentNode = args[0] as TreeListNode;

    int nodeCount = 10;
    for (int i = 0; i < nodeCount; i++)
    {
        t.AppendNode(new object[] { "node cell text" }, parentNode);
        bw.ReportProgress(i, new object[]{ parentNode, "node: " + i.ToString() + "/" + nodeCount.ToString()});
    }
}

private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    object[] args = e.UserState as object[];
    TreeListNode parentNode = args[0] as TreeListNode;
    string percentMsg = args[1].ToString(); //node: n/n message

    t.Invoke(new MethodInvoker(() => parentNode.Nodes[0].SetValue(0, percentMsg))); //change "Loading.." to "node: n/n"
    //parentNode.Nodes[0].SetValue(0, mesaj);
}

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    object[] result = e.Result as object[];
    TreeListNode node = result[0] as TreeListNode;

    node.Nodes.RemoveAt(0); //remove loading text
}
A: 

The (main) problem is with your bw_ProgressChanged. It does not need to Invoke anything because it is the Bgw's job to synchronize the ProgressChanged. I doesn't hurt, but loose the Invoke anyway.

The reason you don't see any changes is the lack of an Update().

private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    object[] args = e.UserState as object[];
    TreeListNode parentNode = args[0] as TreeListNode;
    string percentMsg = args[1].ToString(); //node: n/n message

    parentNode.Nodes[0].SetValue(0, percentMsg); //change "Loading.." to "node: n/n"
    parentNode.TreeView.Update(); // or Form.Update

}

There is another problem in bw_DoWork(), you use Invoke on the AddSubNodes() method. As a result 99% of your code runs entirely on the main thread and your solution is not multi-threaded at all.

I would do something like:

//untested
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
//    t.Invoke(new MethodInvoker( () => AddSubNodes(e.Argument) ));
    object[] args = arg as object[];
    TreeListNode parentNode = e;

    var newNodes = new List<TreeNode>();

    int nodeCount = 10;
    for (int i = 0; i < nodeCount; i++)
    {
       // t.AppendNode(new object[] { "node cell text" }, parentNode);
        newNodes.Add(new object[] { "node cell text" }); // ???
        bw.ReportProgress(i, new object[]{ parentNode, "node: " + i.ToString() + "/" + nodeCount.ToString()});
    }

    // e.Result = e.Argument;
    e.Result = newNodes;
}

And then, in bw_RunWorkerCompleted, quickly add the elements of newNodes to 't'.

Henk Holterman
Thanks a lot. As someone who just started to use BackgroundWorker I'd like to ask two things:1. Doesn't DoWork in a seperate thread? Thus shouldn't my AddSubNodes() invokes work in that seperate thread?2. If I have to do the work in RunWorkerCompleted, what's the point of DoWork?I guess I'm missing something with BackGroundWorker..
Armagan
1) Yes, DoWork is async but Invoke pushes (all) the work back to the main Thread. 2) You should use a BGW to do most of the non-GUI work (fetching data for the nodes) and only touch the GUI through Invoke, UpdateProgress or Completed.
Henk Holterman
I moved my AddSubNodes() call from DoWork to RunWorkerCompleted, the tree still hangs during operation. Tried to invoke it, same hang up. What's wrong with this?
Armagan
You have to split AddSubNodes (GUI and non-GUI).
Henk Holterman