采购收货分配面板自定义字段UsrWgtIndex值异常求助
Acumatica采购收货分配面板自定义字段计算异常:始终显示第一行值而非对应行结果
我在Acumatica的采购收货(Purchase Receipts)分配(Allocation)面板中添加了自定义字段UsrWgtIndex,需求是让这个字段等于同一行下另一自定义字段UsrWgtPerUnit的总和。但现在遇到了异常:打开不同的分配面板时,UsrWgtIndex始终显示第一行交易的计算值,而不是当前打开的对应行的结果。
我的代码如下,逻辑上应为每行交易计算总和并赋值给对应行的UsrWgtIndex,但实际未达预期:
namespace PX.Objects.PO { public class POReceiptEntry_Extension: PXGraphExtension < POReceiptEntry > { #region Event Handlers decimal totalCgt = 0 M, tempTotal = 0 M; protected void POReceiptLine_RowSelected(PXCache cache, PXRowSelectedEventArgs e) { POReceiptLine poRLine = (POReceiptLine) e.Row; if (poRLine != null) { totalCgt = 0 M; foreach(POReceiptLineSplit line in Base.splits.Select()) { POReceiptLineSplitExt poReceiptLineSplitExt = line.GetExtension < POReceiptLineSplitExt > (); var recentQty = poReceiptLineSplitExt.UsrWgtPerUnit; var temp = Convert.ToDecimal(recentQty); totalCgt = totalCgt + temp; }; var cgt = Convert.ToDecimal(totalCgt); if (totalCgt != null) { cache.SetValue < POReceiptLineExt.usrTotalWgt > (poRLine, cgt); //This line is setting the value of usrWgtIndex cache.SetValue < POReceiptLineExt.usrWgtIndex > (poRLine, cgt); }; } } } }
补充细节:
- 自定义字段
usrWgtIndex属于数据类POReceiptLine,但控件放置在分配面板上。 - 测试发现:若将相同值分配给分配面板的
UnassignedQty字段,或同时修改POReceiptLine中的其他字段,均能正常工作;仅修改分配面板上的自定义字段时出现此异常。 - 未将
UsrWgtIndex添加到DACLotSerOptions,因为尝试用setValueEXT方法赋值时,未找到LotSerOptionsExt,故将其放在POReceiptLine中,通过cache.SetValue<POReceiptLineExt.usrWgtIndex>(poRLine, cgt);赋值。
问题根源分析
我帮你梳理下代码里的几个关键问题:
- 全局变量状态污染:类级别的
totalCgt和tempTotal会在多次行选择操作中保留之前的计算值,导致后续行的计算结果被污染。 - 未过滤当前行的拆分记录:
Base.splits.Select()会获取所有的拆分记录,而不是当前选中的POReceiptLine对应的拆分,所以你计算的是所有行的UsrWgtPerUnit总和,而非当前行的。 - 缓存更新方式错误:使用
SetValue而不是SetValueExt,无法触发Acumatica缓存的更新事件,导致界面无法正确刷新对应字段的值。 - 事件上下文不匹配:分配面板的上下文是
POReceiptLineSplit,但字段属于POReceiptLine,当拆分记录的UsrWgtPerUnit变化时,没有触发主行的重新计算。
修正后的代码
namespace PX.Objects.PO { public class POReceiptEntry_Extension : PXGraphExtension<POReceiptEntry> { #region Event Handlers protected void POReceiptLine_RowSelected(PXCache cache, PXRowSelectedEventArgs e) { POReceiptLine poRLine = e.Row as POReceiptLine; if (poRLine == null) return; decimal totalCgt = 0M; // 只查询当前POReceiptLine对应的拆分记录 foreach (POReceiptLineSplit line in Base.splits.SelectWhere<POReceiptLineSplit, Where<POReceiptLineSplit.receiptNbr, Equal<Current<POReceiptLine.receiptNbr>>, And<POReceiptLineSplit.lineNbr, Equal<Current<POReceiptLine.lineNbr>>>>>()) { POReceiptLineSplitExt poReceiptLineSplitExt = line.GetExtension<POReceiptLineSplitExt>(); // 空值判断,避免转换异常 if (poReceiptLineSplitExt.UsrWgtPerUnit != null) { totalCgt += Convert.ToDecimal(poReceiptLineSplitExt.UsrWgtPerUnit); } } // 使用SetValueExt触发缓存更新,确保界面同步刷新 cache.SetValueExt<POReceiptLineExt.usrTotalWgt>(poRLine, totalCgt); cache.SetValueExt<POReceiptLineExt.usrWgtIndex>(poRLine, totalCgt); } // 监听拆分字段变化,实时更新主行总和 protected void POReceiptLineSplit_UsrWgtPerUnit_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e) { POReceiptLineSplit split = e.Row as POReceiptLineSplit; if (split == null) return; // 获取当前拆分对应的主行记录 POReceiptLine poLine = Base.transactions.Select<POReceiptLine, Where<POReceiptLine.receiptNbr, Equal<Current<POReceiptLineSplit.receiptNbr>>, And<POReceiptLine.lineNbr, Equal<Current<POReceiptLineSplit.lineNbr>>>>>(); if (poLine != null) { // 触发主行的RowSelected事件,重新计算总和 Base.transactions.Cache.RaiseRowSelected(poLine); } } #endregion } }
关键修正说明
- 移除全局变量:把
totalCgt移到RowSelected方法内部,每次计算都是独立的,避免状态残留。 - 精准过滤拆分记录:用
SelectWhere筛选出当前POReceiptLine对应的拆分,确保计算的是当前行的总和。 - 替换为
SetValueExt:这个方法会触发缓存的更新事件,让界面能实时同步字段值,解决你提到的只有修改系统字段才生效的问题。 - 添加字段更新事件:当
UsrWgtPerUnit的值变化时,自动触发主行的重新计算,保证分配面板上的UsrWgtIndex能实时更新。
额外注意事项
- 确认
UsrWgtPerUnit字段在DAC中定义为可空类型(比如public decimal? UsrWgtPerUnit { get; set; }),避免空引用转换异常。 - 检查分配面板上的
UsrWgtIndex控件,确保DataField属性正确指向POReceiptLine的UsrWgtIndex字段,数据源设置正确关联主记录。
内容的提问来源于stack exchange,提问作者JackZeng
相关产品推荐
相关产品推荐

