首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么OnEditError或OnPostError不能捕获TClientDataSet中的无效用户条目?

为什么OnEditError或OnPostError不能捕获TClientDataSet中的无效用户条目?
EN

Stack Overflow用户
提问于 2012-06-06 23:49:01
回答 1查看 1.4K关注 0票数 4

我有一个内存中的数据集,通过一些数据源连接到TDBGrid。问题是,每当用户在数字字段中输入减号并按ENTER键或导航到另一条记录时,就会触发AV (验证错误)。我无法从TDBGrid或TClientDataSet (OnEditError、OnPostError)捕获AV。

我是不是做错了什么。如果没有,有谁有办法解决这个问题吗?

使用XE2企业版,第4次更新;最新的MIDAS.DLL;目标平台: Win64。

==============================================================================

请尝试以下操作:

1-创建一个新的VCL应用程序/表单,并在表单中添加对象: TClientDataSet、TDBGrid和TDataSource。ClientDataSet未连接到任何数据库(在内存中)

2-向Table1 ( TClientDataSet)添加永久数字字段。

3-链接上述三个对象。持久字段的列应该出现在TDBGrid上。

4-在主窗体的OnShow方法中添加以下行:

表1.Active := False;

表1.CreateDataSet;

表1. :=真;

5-运行您的程序并在数字字段列中键入减号,然后按Enter键。

检查AV,然后尝试向Table1添加OnEditError和/或OnPostError事件处理程序以捕获AV。您不能中止帖子。这意味着,AV将会发生,您只能使用Application.OnException处理程序捕获它。这可不好。假设您的应用程序包含许多表单和例程,而不是更高的级别,那么您应该能够在您的程序运行的级别上执行某些操作。

我希望我的问题说得更清楚了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-07 02:31:00

正如Ken所说,如果没有示例代码,很难为您提供帮助。因此,我不能直接回答您的问题,但通过一些提示,您也许能够自己解决这个问题。所以我要试着教你钓鱼。;)

我对Delphi3和Delphi6中的TClientDataSet有相当多的经验,我怀疑事情有那么大的变化。另外,我将更多地关注一些技术,让您在正确的方向上起步。

首先,确保使用Debug DCU进行编译,这样就可以在VCL代码中获得断点。不要害怕阅读并逐步了解这些代码-这是一个很好的学习方法。此外,您还可以看到Borland/CodeGear/Embarcadero的所有丑陋的错误。

我假设你已经启用了Stop on Exceptions (因此你知道你特别得到了AV错误)。

做你的测试。当你得到你的AV时,你可能会用DbClient.pas (或者一个较低级别的单位)出来。

遍历调用堆栈,查找位于try..except块的try部分中的位置,该位置可以接受异常,也可以短路到另一个处理程序,然后再接受它。

注意: DbClient.pas中有相当多的以下错误代码的实例:

代码语言:javascript
复制
except //swallowing or squashing exceptions is 
end;   //very dangerous and should be avoided.

except
  //short-circuiting to Application.HandleException (usually informs the user)
  //but is not much better. The point is the rest of the program up the 
  //call-stack remains blissfully unaware that something went wrong.
  Application.HandleException(Self);
  Action := raAbort;
end;

侧评:仅仅因为Borland做到了这一点,并不意味着这是一种好的实践。你和其他许多人已经并将被这件事烧毁。

一旦你发现了这一点,你就走到了一半。现在你知道为什么你没有被告知AV了。

现在,在构成调用堆栈一部分的代码中的某个地方,将会提供一个线索,告诉您应该如何处理错误。您还可以在VCL代码中稍早放置一个断点,这样您就可以单步执行来查看导致异常的事件序列。由于您特别提到了AV (访问冲突),因此请查找引用nil的对象。

可能导致该问题的一个示例是来自D5 DbClient.pas的以下代码片段

代码语言:javascript
复制
    FOnReconcileError(DataSet, E, UpdateKind, Action);
  finally
    E.Free;
  end;
except
  Application.HandleException(Self);
  Action := raAbort;
end;

从上面可以看出,某些情况要求您实现一个OnReconcileError事件处理程序。如果没有它,dll将不会被回调到上面的代码片段中,并且许多错误都会被悄悄地踢到地毯下,让您挠头。

我使用TClientDataSet的经验是,为了“正确”使用它,你必须做一些额外的事情。这在文档中并不是特别明显。虽然一旦你弄清楚了你应该做的所有零碎和零碎的事情,但如何做它们的例子要好一些。

不幸的是,我对所有这些事情的记忆有点模糊。这是一本verrry粗略指南,可能遗漏了很多。

  • 考虑使用OnReconcileError event handler.
  • Consider实现UpdateProvider对象。
  • 您提到将其用作内存中的dataset,因此您可能正确地使用了CreateDataSet。但是如果我没记错的话,你有两个选项来指定字段,一些更好的细节属性是一个小的picky.
  • Unrelated提示:注意你的字符串字段的长度,TClientDataSet过去(可能仍然会)以类似于短字符串的方式集中内存。

编辑

根据问题中的其他信息并使用上面描述的技术,您将从以下方法中抛出一个EDatabaseError。

代码语言:javascript
复制
procedure TIntegerField.SetAsString(const Value: string);
var
  E: Integer;
  L: Longint;
begin
  if Value = '' then Clear else
  begin
    Val(Value, L, E);
    if E <> 0 then DatabaseErrorFmt(SInvalidIntegerValue, [Value, DisplayName]);
    SetAsInteger(L);
  end;
end;

在调用堆栈的较高位置,您将获得以下方法,该方法提示如何解决问题。

代码语言:javascript
复制
procedure TField.SetEditText(const Value: string);
begin
  if Assigned(FOnSetText) then FOnSetText(Self, Value) else SetText(Value);
end;

此外,如果按照调用堆栈一直到KeyPress,您会注意到根本不涉及数据集或网格代码。

您尝试处理OnPost中的error错误失败的原因是您无法尝试发布记录。您将收到一个字段验证错误,而处理该错误的位置是在字段上。

返回到如何解决错误的提示-您必须为字段实现一个OnSetText事件。

但是,,我建议你不要这么做。开箱即用的行为是完全可以接受的!用户收到一条错误消息,解释他们做错了什么,然后他们有机会修复它并重试。如果他们改变了主意,他们可以按Escape并取消编辑。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10917671

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档