WinFormsを使用してC#のVisual Studio 2010.NET4.0で作業しています。
DataGridView
フォームには、にバインドされたデータであるシングルがありますDataSet
。
は、から読み取られているデータを処理しDataSet
ているから入力されています。Thread
ConcurrentQueue
このコードは、セマフォを使用してへのアクセスをシリアル化します。DataSet
これは、「ワーカー」スレッドとUIメインスレッド(更新時DataGridView
)からアクセスできるためです。
UI /フォームには、System.Windows.Forms.Timer
1/4秒ごとに起動DataGridView
して、の現在の内容でを更新する関数を呼び出す機能がありDataSet
ます。
DataGridView
データがスクロールしてスクロールバーが表示されるまで、コードは正しく実行されます。この時点で、フォーム全体が応答しなくなります。タイトルのキャプションには「プログラムが応答していません」と表示されます。
興味深いのは、デバッガーで実行している間はこれが発生しないことです。プログラムがデプロイされている場合のみ。そして、例外は発生しません。
動作を変更せずに、InvokeとBeginInvokeの両方を使用してみました。
質問:
1-以下の私のコードの何が問題になっている可能性がありますか?
2-デバッガーで実行している間はこの動作を観察できないので、問題の原因を特定するにはどうすればよいですか?
コードの壁を以下に示します。たくさんのコードがあることは知っていますが、できる限り切り取っています。
// deleted using statements for brevity
namespace namcom
{
public partial class wndXMLtrans : Form
{
private DataSet dsRecords = new DataSet();
private Thread threadConsumeXML = null;
private static Semaphore ResourceLock;
public wndXMLtrans(String ip)
{
InitializeComponent();
ResourceLock = new Semaphore(1, 1);
curSize = this.Size;
m_ip = ip;
}
private Boolean AddRowToDataSet(String[] columns, String xml)
{
Boolean retCode = true;
String value = String.Empty;
Int64 id = -1;
DataRow row;
ResourceLock.WaitOne();
row = dsRecords.Tables[0].NewRow();
// prepare row code omitted - brevity
// add new data row to DataSet
dsRecords.Tables[0].Rows.Add(row);
ResourceLock.Release();
// SQL inserts into DB removed - brevity
return (retCode);
}
private Boolean HandleSingleXMLMessage(String[] columns, String xml, out String exceptionMessage)
{
Boolean boolRet = true;
exceptionMessage = String.Empty;
// store data in dataset and database
if ( closeRequested == false )
{
AddRowToDataSet(columns, xml);
}
return (boolRet);
}
private Boolean StoreG2SMessages(String message)
{
// code removed - brevity
// removed code just parses out string and in a loop calls HandleSingleXMLMessage
// until all XML in message have been processed
HandleSingleXMLMessage(columns,xml, out exceptionMessage) // call in loop
return (ret);
}
// pull XML out of mainwnd.msgQueue and update database
private void G2SParseThread()
{
String Data;
String exceptionMsg = String.Empty;
while ( /* thread is to be active - code removed for brevity */)
{
Data = String.Empty;
if (mainwnd.msgQueue.TryDequeue(out Data) == true)
{
this.StoreG2SMessages(Data);
}
Thread.Sleep(20);
}
// thread ended cleanup code removed - brevity
}
private void StartThreads()
{
// start XML packet processing thread
threadConsumeXML = new Thread(G2SParseThread);
threadConsumeXML.SetApartmentState(ApartmentState.STA);
threadConsumeXML.Start();
threadMonitor = new Thread(() => threadHandleStatusMsg(ref mainwnd.statusQueue));
threadMonitor.Start();
}
private void wndXMLtrans_Shown(object sender, EventArgs e)
{
// remove SQL code - brevity
// fill dsRecords ( DataSet )
try
{
var adapter = new SQLiteDataAdapter(selectSQL, dbConnection);
adapter.Fill(dsRecords);
dataGrid.DataSource = dsRecords.Tables[0].DefaultView;
adapter.Dispose();
}
catch { } // catch code removed - brevity
StartThreads();
}
private void gridUpdateTimer_Tick(object sender, EventArgs e)
{
ResourceLock.WaitOne();
try
{
if (dataGrid != null && numRows < dsRecords.Tables[0].Rows.Count)
{
if (dataGrid.RowCount > 0)
{
dataGrid.FirstDisplayedScrollingRowIndex = dataGrid.RowCount - 1;
}
dataGrid.Refresh();
numRows = dsRecords.Tables[0].Rows.Count;
}
}
catch { }
ResourceLock.Release();
}
}
}
DataSet
編集:ハンスは、ワーカースレッドからバウンドを更新できないという答えを提供しました。そこで、以下を追加することで問題を解決することができました。
これらは、Invokeを使用してデリゲート関数によって呼び出されます。更新前に呼び出されたバインドを解除DataSet
し、更新後にバインドしDataSet
ます。これは機能DataGridView
しますが、がちらついたり、何度も再描画されたりするように見えます。これを改善する方法はありますか?
public void UnbindDataGridView(DataGridView grid)
{
grid.DataSource = null;
}
public void BindDataGridView(DataGridView grid)
{
grid.DataSource = dsRecords.Tables[0].DefaultView;
}