0

我使 TDataset 后代异步,而不是sleepProcessMessages主线程中,它通过来自网络线程的事件工作。因此,当 Recordset 准备就绪时,它会调用

procedure TMySqlQuery.OrdinalOnDataReady(Sender: TObject);
begin
  AddToLog('OrdinalOnDataReady');
  FDataAvailable := true; // used in IsCursorOpen
  inherited Open;
  if Assigned(FParentOnDataReady) then
      FParentOnDataReady(self);
end;

它可以工作,但有时我会遇到从这个线程调用的问题,而GetRecordDBGrid从 Form 的 ProcessMessages调用的 DBGrid 从主线程调用。通过记录我看到的两个功能OpenGetFieldDataDrawCells

[17:10:39] RecordToBuffer row 0
[17:10:39] len = 17 buf : 
00 E0 10 C3 00 0A 00 00 00 F0 10 C3 00 0B 00 00   |  .ïœ.ï“.....ÿ€.ï“....
00   |  .
[17:10:40] RecordToBuffer row 1
[17:10:40] len = 17 buf : 
00 00 FF C3 00 25 00 00 00 10 11 C3 00 0B 00 00   |  ..ÿï“.%.....ï“....
00   |  .
[17:10:40] ActiveBuffer
[17:10:40] len = 17 buf : 
00 E0 10 C3 00 0A 00 00 00 F0 10 C3 00 0B 00 00   |  .ïœ.ï“.....ÿ€.ï“....
00   |  .
...
more ActiveBuffer
...
[17:10:40] ActiveBuffer
[17:10:40] len = 17 buf : 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   |  ................
00   |  .
[17:10:40] len = 8 buf : 
00 00 00 00 00 00 00 00   |  ........

并且当 ActiveBuffer 列数据为零时断言中断,我可以看到 DBGrid 尝试读取比GetRecord读取到自己的内部 FBuffers 更高的行。例如,如果断言在GetFieldData第 3 行触发 - FBuffers 从 Recordset 中可用的总共 36 行中填充到第 2 行。当我使用 F8 逐步调试时,GetRecord没有错误,我按 F9 并在另一条记录中获得断言。

我不太明白究竟是如何DBGrid工作的TDataset(即使堆栈跟踪很大),但是这个线程竞争可以解决吗?

4

1 回答 1

0

解决方案非常简单:由于 TDataset 的 FBuffers(来自 Data.DB)中的数据在未初始化的情况下填充为 0,因此可以通过在记录中添加另一个标记字节并在 GetRecord 中分配不为 0 来通过 GetRecord 找到填充的 ActiveBuffer。因此,如果 DBGrid 尝试读取未初始化的数据,我会检查 GetFieldData 中的标记,如果 0 结果为假并退出。由于 DBGrid 不止一次地将数据提取到相同的单元格,因此我仍然用正确的数据填充它。这是解决方法,但它有效。

于 2014-01-12T13:58:53.930 回答