Mon application a un objet DataGridView et une liste de type MousePos. MousePos est une classe personnalisée qui contient les coordonnées X, Y de la souris (de type "Point") et un compte courant de cette position. J'ai un thread (System.Timers.Timer) qui soulève un événement une fois par seconde, vérifie la position de la souris, ajoute et/ou met à jour le compte de la position de la souris sur cette liste.Comment remplir en toute sécurité avec des données et Refresh() un DataGridView dans une application multithread?
Je voudrais avoir un thread en cours d'exécution similaire (encore une fois, je pense que System.Timers.Timer est un bon choix) qui relancerait un événement une fois par seconde pour actualiser automatiquement le DataGridView afin que l'utilisateur puisse voir les données sur la mise à jour de l'écran. (comme le fait TaskManager.)
Malheureusement, l'appel de la méthode DataGridView.Refresh() entraîne l'arrêt de l'exécution de VS2005 et signale que j'ai rencontré une situation de threads croisés.
Si je comprends bien, j'ai 3 fils maintenant:
- thread d'interface utilisateur primaire
- MousePos fil Liste (minuterie)
- DataGridView de fil de rafraîchissement (minuterie)
Pour voir si je pourrais Refresh() le DataGridView sur le thread primaire, j'ai ajouté un bouton au formulaire qui a appelé DataGridView.Refresh(), mais cela (étrangement) n'a rien fait. J'ai trouvé un sujet qui semblait indiquer que si je définissais DataGridView.DataSource = null et retour à ma liste, cela actualiserait la grille de données. Et en effet, cela a fonctionné, mais seulement à travers le bouton (qui est piloté sur le thread principal.)
Donc, cette question a transformé en deux parter:
- réglage est-il à DataGridView.DataSource null et retour à ma liste un moyen acceptable d'actualiser le DataGrid? (Cela me semble inefficace ...)
- Comment faire cela en toute sécurité dans un environnement multithread?
Voici le code que j'ai écrit jusqu'à présent (C# /. Net 2,0)
public partial class Form1 : Form
{
private static List<MousePos> mousePositionList = new List<MousePos>();
private static System.Timers.Timer mouseCheck = new System.Timers.Timer(1000);
private static System.Timers.Timer refreshWindow = new System.Timers.Timer(1000);
public Form1()
{
InitializeComponent();
mousePositionList.Add(new MousePos()); // ANSWER! Must have at least 1 entry before binding to DataSource
dataGridView1.DataSource = mousePositionList;
mouseCheck.Elapsed += new System.Timers.ElapsedEventHandler(mouseCheck_Elapsed);
mouseCheck.Start();
refreshWindow.Elapsed += new System.Timers.ElapsedEventHandler(refreshWindow_Elapsed);
refreshWindow.Start();
}
public void mouseCheck_Elapsed(object source, EventArgs e)
{
Point mPnt = Control.MousePosition;
MousePos mPos = mousePositionList.Find(ByPoint(mPnt));
if (mPos == null) { mousePositionList.Add(new MousePos(mPnt)); }
else { mPos.Count++; }
}
public void refreshWindow_Elapsed(object source, EventArgs e)
{
//dataGridView1.DataSource = null; // Old way
//dataGridView1.DataSource = mousePositionList; // Old way
dataGridView1.Invalidate(); // <= ANSWER!!
}
private static Predicate<MousePos> ByPoint(Point pnt)
{
return delegate(MousePos mPos) { return (mPos.Pnt == pnt); };
}
}
public class MousePos
{
private Point position = new Point();
private int count = 1;
public Point Pnt { get { return position; } }
public int X { get { return position.X; } set { position.X = value; } }
public int Y { get { return position.Y; } set { position.Y = value; } }
public int Count { get { return count; } set { count = value; } }
public MousePos() { }
public MousePos(Point mouse) { position = mouse; }
}
Je suppose que mettais [C#] dans le sujet est verboten, hein? – Pretzel