2012-10-17 54 views
1

使用Delphi 2005,我有一个TwwDBGrid(InfoPower),允许用户选择零件数量来生成报价。部分选择过程是允许用户为由DiscountAmount和DiscountType组成的每个部分添加折扣。 DiscountAmount是折扣金额,DiscountType是折扣金额类型(折扣,折扣或平价)。这些数据保存在一个名为ClientDataSetParts的ClientDataSet中。OnCalcFields导致StackOverflow

在OnCalc方法(ClientDataSetPartsCalcFields)中,我有以下代码将根据零件成本和任何折扣重新计算TotalPrice。 RangePricing在其中一个价格是基于数量的范围内(即,1-100 = $ 100 101-200 = $ 150等)内计算的情况下使用:

procedure TfrmCustom_Services.ClientDataSetPartsCalcFields(
    DataSet: TDataSet); 
begin 
    inherited; 
    // if part is selected then calculate Total 
    if (ClientDataSetPartsSelected.Value) then begin 
    // if range pricing is defined 
    if (ClientDataSetParts.FieldByName('RangePricing').AsBoolean) then begin 
     ClientDataSetParts.FieldByName('TotalPrice').Value := 
      ClientDataSetParts.FieldbyName('UnitPrice').Value; 
    // otherwise use regular pricing 
    end else begin 
     ClientDataSetParts.FieldByName('TotalPrice').Value := 
      ClientDataSetParts.FieldbyName('UnitPrice').Value * 
      ClientDataSetParts.FieldByName('Quantity').Value; 
    end; 

    // otherwise clear the Total 
    end else begin 
    ClientDataSetParts.FieldByName('TotalPrice').Clear; 
    if (ClientDataSetParts.FieldByName('Quantity').Value <> null) then 
     ClientDataSetParts.FieldByName('Quantity').Clear; 
    if (ClientDataSetParts.FieldByName('DiscountAmount').Value <> null) then 
     ClientDataSetParts.FieldByName('DiscountAmount').Clear; 
    if (ClientDataSetParts.FieldByName('DiscountType').Value <> null) then 
     ClientDataSetParts.FieldByName('DiscountType').Clear; 
    end; 

    // Update totals if Discount is applied 
    // Only recalculate if both discount value and type are applied 
    // otherwise will constantly get errors when switching fields 
    if ((ClientDataSetPartsDiscountAmount.Value > 0) and (ClientDataSetPartsDiscountType.Value <> '')) then begin 
    case StringToCaseSelect((ClientDataSetPartsDiscountType.Value), ['% Disc','$ Disc','Price']) of 
     0 : 
     begin 
     ClientDataSetParts.FieldByName('DiscountDollarAmount').Value := 
      ClientDataSetParts.FieldByName('TotalPrice').Value * (ClientDataSetParts.FieldByName('DiscountAmount').Value/100); 
     ClientDataSetPartsTotalPrice.Value := ClientDataSetPartsTotalPrice.Value - (ClientDataSetPartsTotalPrice.Value * (ClientDataSetPartsDiscountAmount.Value/100)); 
     end; 
     1 : 
     begin 
     ClientDataSetParts.FieldByName('DiscountDollarAmount').Value := ClientDataSetPartsDiscountAmount.Value; 
     ClientDataSetPartsTotalPrice.Value := ClientDataSetPartsTotalPrice.Value - ClientDataSetPartsDiscountAmount.Value; 
     end; 
     2 : 
     begin 
     ClientDataSetParts.FieldByName('DiscountDollarAmount').Value := 
      ClientDataSetPartsTotalPrice.Value - ClientDataSetPartsDiscountAmount.Value; 
     ClientDataSetPartsTotalPrice.Value := ClientDataSetPartsDiscountAmount.Value; 
     end; 
    end; 
    end; 

end; 

问题是当我尝试计算DiscountDollarAmount(折扣的实际美元数字,我必须通过API返回到外部来源)。每次我设置ClientDataSetParts.FieldByName('DiscountDollarAmount')。值时,ClientDataSetPartsCalcFields被再次调用,导致无尽的调用并最终导致堆栈溢出。

如何在不递回调用ClientDataSetPartsCalcFields的情况下更新此值?

+0

您是否尝试过将AutoCalcFields设置为false? –

+0

不改变任何东西。 – BrianKE

+0

好的。但是请阅读关于'AutoCalcFields'的文档,或许它会提供一些见解。 –

回答

2

您正在进入的无限循环是由代码更改值,看到它已更改并重新启动更改(如您已知)所致。为了解决这个问题,在过程开始时,将OnCalc事件设置为零,然后在最后重新设置该过程。这样,事件监视将在实际处理期间暂停,然后在处理完成后恢复并分配新值。

+3

这可能会掩盖潜在的错误并导致其他错误。 –

+0

谢谢汤姆,那工作。 – BrianKE

+0

@David Heffernan - 你能详细说明吗?我不明白它会如何破坏任何东西,而且在过去,我根据自己的消息来源(书籍,互联网搜索和高级同事)使用此解决方案作为“正确”解决方案。 –

2

此行为是您修改非计算字段时发生的情况。 OnCalcFields事件不应对非计算字段进行任何修改。

我对数据库结构一无所知,但如果我的预感是正确的,那么您正在修改OnCalcFields事件处理程序中的某个非计算字段。而且,由于您修改了非计算字段,因此需要重新计算计算的字段。因此调用OnCalcFields。其中修改了非计算字段。而且,好吧,你可以看到这是怎么回事!

+0

字段DiscountDollarAmount是fkCalculated类型。我的操作说明解释了我在做什么,以TotalPrice并应用折扣。我如何做到这一点,使我不会遇到这种递归,而不使用@Tom建议的方法? – BrianKE

+1

好的,显然你正在做别的事情。在启用了Debug DCU的情况下使用调试器,并在首次递归调用OnCalcFields时查看调用堆栈。查看调用堆栈中的线索,了解为什么顶级'OnCalcFields'引发对'OnCalcFields'的递归调用。如果可能,请向我们显示该调用堆栈。 –

+0

所以我通过@Tom的建议得到了一切。然后我注释掉了两行关闭,然后再打开OnCalcFields方法,一切都按预期工作。无法解释为什么昨天我遇到了无限循环,今天我并不是唯一的改变就是从这两行中脱颖而出。无论如何,感谢大家的帮助。 – BrianKE

相关问题