2009-09-15 9 views
0

J'ai une vue arborescente utilisant BackGround worker pour ajouter des nœuds lorsque vous en développez. J'affiche un message "Loading .." après l'expansion et l'enlève après que les noeuds soient chargés. Cela fonctionne bien et tout. Maintenant, je veux changer le message de chargement à "Chargement ... nœud n/n". J'étais capable de le faire mais le problème est que ce message n'est pas affiché (mis à jour) tandis que faisant l'opération d'ajout de nœud mais après l'achèvement. Je ne pouvais pas comprendre ce que je fais mal et j'espère que quelqu'un peut faire la lumière sur cela.Modification de la valeur d'un nœud dans un TreeView asynchrone

Voici mon code. Je débogués méthode SetValue et il met à jour correctement le texte du nœud, mais il ne s'affiche pas jusqu'à la fin de l'opération ..

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 
} 

Répondre

0

Le problème (principal) est avec votre bw_ProgressChanged. Il n'a pas besoin d'Invoquer quoi que ce soit car c'est le travail de Bgw de synchroniser le ProgressChanged. Je ne blesse pas, mais perds l'Invoke de toute façon.

La raison pour laquelle vous ne voyez aucune modification est l'absence d'une mise à jour().

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 

} 

Il y a un autre problème dans bw_DoWork(), vous utilisez Invoke sur la méthode AddSubNodes(). Par conséquent, 99% de votre code s'exécute entièrement sur le thread principal et votre solution n'est pas multi-threadée du tout.

je ferais quelque chose comme:

//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; 
} 

Et puis, en bw_RunWorkerCompleted, ajouter rapidement les éléments de newNodes 't'.

+0

Merci beaucoup. En tant que quelqu'un qui vient de commencer à utiliser BackgroundWorker, je voudrais demander deux choses: 1. Ne fonctionne-t-il pas dans un fil séparé? Ainsi, mon AddSubNodes() ne devrait-il pas fonctionner dans ce thread séparé? 2. Si je dois faire le travail dans RunWorkerCompleted, quel est le but de DoWork? Je suppose qu'il me manque quelque chose avec BackGroundWorker .. – dstr

+0

1) Oui, DoWork est asynchrone mais Invoke repousse (tout) le travail au thread principal. 2) Vous devriez utiliser un BGW pour faire la plupart du travail hors GUI (récupération des données pour les nœuds) et ne toucher que l'interface graphique via Invoke, UpdateProgress ou Completed. –

+0

J'ai déplacé mon appel AddSubNodes() de DoWork à RunWorkerCompleted, l'arbre se bloque toujours pendant l'opération. J'ai essayé de l'invoquer, même raccroche. Quel est le problème avec ça? – dstr

Questions connexes