crocteamgg
-
25 janv. 2013 à 21:06
yann_lo_san
Messages postés1137Date d'inscriptionlundi 17 novembre 2003StatutMembreDernière intervention23 janvier 2016
-
29 janv. 2013 à 22:03
Bonjour/soir,
J'essaie dernièrement d’utiliser l’élément treeview de WPF et je rencontre un problème avec son utilisation.
Je m'entraîne en récupérant l'arborescence de mon ordinateur depuis un dossier, et avec de la récursivité je récupère les sous-dossiers et les fichiers présents.
Ça sa marche très bien, l'inconvénient est que ça prend quelques secondes à tout charger et donc j'ai mis mon code dans un thread.
Le problème survient quand je veux repasser toute l'arborescence créée avec des TreeViewItem à mon treeView. A ce moment là j'obtient un InvalidOperationException "Le thread appelant ne peut pas accéder à cet objet parce qu'un autre thread en est propriétaire."
Ce problème je l'ai déjà eu dans d'autres programmes et je l'ai résolu en utilisant un Dispatcher.BeginInvoke
Mon code appelé depuis le thread pour mettre à jour le treeview se présente comme suit.
public void MiseAJourNode(TreeViewItem node)
{
treeViewMain.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
delegate()
{
treeViewMain.Items.Add(node);
}));
}
Le node reçu comporte tous les nodes et sous nodes de mon arborescence et j'essaie ensuite simplement de l'ajouter à mon treeview. Habituellement le bout de code au-dessus me permet de régler les problèmes de communications d'un thread à un autre. Mais là même avec, je n'arrive pas à éviter une exception.
Une expérience à partager à propos des treeview et des threads?
Je vous remercie d'avance et vous souhaite un bon week-end.
A voir également:
Le thread appelant ne peut pas accéder à cet objet parce qu'un autre thread en est propriétaire
yann_lo_san
Messages postés1137Date d'inscriptionlundi 17 novembre 2003StatutMembreDernière intervention23 janvier 201626 26 janv. 2013 à 14:44
Salut,
as-tu essayé avec un delegate non anonyme et un test sur treeView.InvokeRequired ? :
// déclare
private delegate void addItemDelegate(TreeViewItem node);
// Marche sur le [main] thread ET sur les threads secondaires
private void OnAddItem(TreeViewItem node)
{
if (treeViewMain.InvokeRequired) /*IMPORTANT*/
{
// Invoke la même méthode mais sur le [main] thread
this.Invoke(new addItemDelegate(OnAddItem), node);
}
else
{
// acces au treeView
treeViewMain.Items.Add(node);
}
}
// exemple d'appel dans un autre thread OU sur le formulaire principal
{
OnAddItem(new TreeViewItem(/*...*/));
}
J'ai essayé votre solution et je n'ai pas réussi à la faire fonctionner. Ce n'est pas du code utilisable en WPF et je ne vois comment le réécrire, les threads n'étant pas ma spécialités
yann_lo_san
Messages postés1137Date d'inscriptionlundi 17 novembre 2003StatutMembreDernière intervention23 janvier 201626 29 janv. 2013 à 22:03
Re,
oui pardon, en wpf, il faut utiliser un thread STA et rajouter un paramètre pour savoir si on appelle la méthode depuis le thread pricipal ou non, exemple :
public partial class Window1 : Window
{
private delegate void addItemDelegate(TreeViewItem node, bool bThisWindow);
private System.Threading.Thread _thread = null;
public Window1()
{
InitializeComponent();
this.Activated += new EventHandler(Window1_Activated);
}
void Window1_Activated(object sender, EventArgs e)
{
// Lance le thread
System.Threading.ThreadStart t = new System.Threading.ThreadStart(myCallback);
_thread = new System.Threading.Thread(t);
_thread.SetApartmentState(System.Threading.ApartmentState.STA);
_thread.Start();
}
private void myCallback()
{
TreeViewItem tv1 = new TreeViewItem();
tv1.Items.Add("root");
tv1.Items.Add("node");
OnAddItem(tv1, false);
}
private void OnAddItem(TreeViewItem node, bool bThisWindow)
{
if (!bThisWindow)
{
treeView1.Dispatcher.Invoke(new addItemDelegate(OnAddItem), node, true);
}
else
{
for (int i = 0; i < node.Items.Count; i++)
treeView1.Items.Add(node.Items[i]);
}
}
}