Comment puis-je en toute sécurité remplir avec les données et de les Actualiser() un DataGridView dans une application multi-thread?

Mon application a un DataGridView objet et une Liste de type MousePos. MousePos est une classe personnalisée qui tient la souris coordonnées X,Y (de type "Point") et un nombre de cette position. J'ai un fil (le Système.Les minuteries.Timer) qui déclenche un événement, une fois par seconde, vérifie la position de la souris, ajoute et/ou mises à jour le comte de la position de la souris sur cette Liste.

Je voudrais avoir un semblable thread en cours d'exécution (encore une fois, je pense que le Système.Les minuteries.La minuterie est un bon choix), qui serait nouveau soulever un événement une fois de plus une seconde pour Actualiser automatiquement() le DataGridView, de sorte que l'utilisateur peut voir les données sur l'écran de mise à jour. (comme le gestionnaire de tâches.)

Malheureusement, l'appel de la DataGridView.Méthode Refresh() résultats dans VS2005 l'arrêt de l'exécution, et en notant que j'ai couru en croix-threading situation.

Si je suis bien comprendre, j'ai 3 fils maintenant:

  • Primaire thread d'INTERFACE utilisateur
  • MousePos fil de la Liste (Timer)
  • DataGridView thread d'Actualisation (Timer)

Pour voir si je pouvais Refresh (), le DataGridView sur le thread principal, j'ai ajouté un bouton au formulaire qui appelle DataGridView.Refresh(), mais cette (étrangement) n'a rien fait. J'ai trouvé un sujet qui semble indiquer que si j'ai mis DataGridView.DataSource = null et de retour à ma Liste, que ce serait l'actualisation de la grille de données. Et en effet cela a fonctionné, mais seulement à travers le bouton (qui est traitée sur le thread principal.)


Ainsi, cette question s'est transformée en deux parties:

  1. Est le réglage de DataGridView.Source de données à null et de retour à ma Liste une façon acceptable d'actualisation de la grille de données? (Il semble inefficace pour moi...)
  2. Comment je peux faire cela dans un environnement multi-thread?

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 mettre [C#] dans le sujet est verboten, hein?

OriginalL'auteur Pretzel | 2008-11-03