私のアプリには、DataGridView オブジェクトと MousePos タイプの List があります。MousePos は、マウスの X、Y 座標 ("Point" 型) とこの位置の現在のカウントを保持するカスタム クラスです。毎秒 1 回イベントを発生させ、マウス位置をチェックし、このリストのマウス位置のカウントを追加および/または更新するスレッド (System.Timers.Timer) があります。
ユーザーがデータを表示できるように、DataGridView を自動的に Refresh() するために 1 秒に 1 回イベントを再び発生させる、同様の実行中のスレッドが必要です (これも System.Timers.Timer が適切な選択だと思います)。画面更新。(TaskManager のように。)
残念ながら、DataGridView.Refresh() メソッドを呼び出すと、VS2005 が実行を停止し、クロススレッドの状況に陥ったことが通知されます。
私が正しく理解していれば、現在3つのスレッドがあります:
- プライマリ UI スレッド
- MousePos リスト スレッド (タイマー)
- DataGridView 更新スレッド (タイマー)
プライマリ スレッドで DataGridView を Refresh() できるかどうかを確認するために、DataGridView.Refresh() を呼び出すボタンをフォームに追加しましたが、これは (奇妙なことに) 何もしませんでした。DataGridView.DataSource = null を設定してリストに戻すと、データグリッドが更新されることを示すトピックを見つけました。実際、これは機能しましたが、ボタンを介してのみ (プライマリ スレッドで処理されます)。
したがって、この質問は 2 つの部分に変わりました。
- DataGridView.DataSource を null に設定してリストに戻すことは、データグリッドを更新するための受け入れ可能な方法ですか? (私には効率が悪いように思えます...)
- マルチスレッド環境でこれを安全に行うにはどうすればよいですか?
これまでに書いたコードは次のとおりです(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; }
}