Acumatica中点击Next/Prev导航时数据绑定失效问题
Acumatica INLocation表单切换记录后界面不更新问题
我正在开发一个用于更新INLocation记录的Acumatica基础表单,默认加载第一条记录,支持PREV/NEXT切换、字段修改和删除操作。目前首次运行能正确加载第一条记录,但点击NEXT或PREV按钮时,后台已切换到对应记录(断点验证通过),但界面信息未更新。
ASPX代码
<%@ Page Language="C#" MasterPageFile="~/MasterPages/FormView.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="IN900100.aspx.cs" Inherits="Page_IN900100" Title="Untitled Page" %> <%@ MasterType VirtualPath="~/MasterPages/FormView.master" %> <asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server"> <px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" TypeName="ASGExecuteSQL.INLocationMaint" PrimaryView="Locations" > <CallbackCommands> </CallbackCommands> </px:PXDataSource> </asp:Content> <asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server"> <px:PXFormView ID="form" runat="server" DataSourceID="ds" DataMember="Locations" Width="100%" AllowAutoHide="false"> <Template> <px:PXLayoutRule runat="server" StartRow="True" ID="PXLayoutRule1" ></px:PXLayoutRule> <px:PXLayoutRule runat="server" ID="CstPXLayoutRule6" StartGroup="True" ></px:PXLayoutRule> <px:PXLabel runat="server" ID="CstLabel7" Text="INLocation Information" /> <px:PXSegmentMask runat="server" ID="CstPXSegmentMask9" DataField="SiteID" /> <px:PXSegmentMask runat="server" ID="CstPXSegmentMask8" DataField="LocationCD" CommitChanges="True" /> <px:PXTextEdit runat="server" DataField="Descr" ID="edDescr" ></px:PXTextEdit> <px:PXTextEdit CommitChanges="True" runat="server" DataField="LocationID" ID="edLocationID" ></px:PXTextEdit> </Template> <AutoSize Container="Window" Enabled="True" MinHeight="200" ></AutoSize> </px:PXFormView> </asp:Content>
C#后端代码
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using PX.Data; using PX.Data.BQL.Fluent; using PX.Objects.FS; using PX.Objects.IN; using static PX.Data.BQL.BqlPlaceholder; namespace ASGExecuteSQL { public class INLocationMaint : PXGraph<INLocationMaint> { // Primary view for INLocation DAC public PXCancel<INLocation> Cancel; public PXSave<INLocation> Save; public SelectFrom<INLocation>.View Locations; public INLocationMaint() { // Optionally load the first record into Locations.Current to initialize data if (Locations.Current == null) { Locations.Cache.AllowInsert = false; // don't let them create a blank record INLocation firstRecord = SelectFrom<INLocation>.View.Select(this); if (firstRecord != null) { Locations.Current = firstRecord; } if (Locations.Current != null) { var onCode = Locations.Current.LocationCD; var onID = Locations.Current.LocationID; var StopHere = 0; } } } protected void _(Events.RowSelected<INLocation> e) { var cache = e.Cache; // the default display for this is Location ID, which is confusing... so... PXUIFieldAttribute.SetDisplayName<INLocation.locationCD>(cache, "Location Code"); } // NEXT button action public PXNext<INLocation> Next; [PXButton(CommitChanges = true)] [PXUIField(DisplayName = "Next", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)] protected IEnumerable next(PXAdapter adapter) { INLocation current = Locations.Current; INLocation next = PXSelect<INLocation, Where<INLocation.locationID, Greater<Required<INLocation.locationID>>>, OrderBy<Asc<INLocation.locationID>>> .Select(this, current.LocationID) .FirstOrDefault(); if (next != null) { Locations.Current = next; Locations.Cache.Update(next); Locations.View.RequestRefresh(); } return adapter.Get(); } // PREVIOUS button action public PXPrevious<INLocation> Previous; [PXButton(CommitChanges = true)] [PXUIField(DisplayName = "Previous", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)] protected IEnumerable previous(PXAdapter adapter) { INLocation current = Locations.Current; INLocation prev = PXSelect<INLocation, Where<INLocation.locationID, Less<Required<INLocation.locationID>>>, OrderBy<Desc<INLocation.locationID>>> .Select(this, current.LocationID) .FirstOrDefault(); if (prev != null) { Locations.Current = prev; Locations.Cache.Update(prev); Locations.View.RequestRefresh(); } return adapter.Get(); } // DELETE button action public PXDelete<INLocation> Delete; [PXButton(CommitChanges = true)] [PXUIField(DisplayName = "Delete", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)] protected IEnumerable deleteLocation(PXAdapter adapter) { INLocation current = Locations.Current; if (current != null) { Locations.Delete(current); this.Actions.PressSave(); } return adapter.Get(); } } }
问题原因及修复方案
核心问题
仅设置Locations.Current = next并调用RequestRefresh()不足以触发Acumatica界面刷新,因为没有让PXAdapter正确同步缓存状态并通知数据源更新界面绑定。
修复步骤
修改Next/Previous方法逻辑
移除冗余的Cache.Update()和RequestRefresh()调用,改用SetCurrent()设置缓存当前记录,并通过yield return返回新记录,让PXAdapter自动处理界面同步:修改后的Next方法:
protected IEnumerable next(PXAdapter adapter) { INLocation current = Locations.Current; INLocation nextRecord = PXSelect<INLocation, Where<INLocation.locationID, Greater<Required<INLocation.locationID>>>, OrderBy<Asc<INLocation.locationID>>> .Select(this, current.LocationID) .FirstOrDefault(); if (nextRecord != null) { adapter.View.Cache.SetCurrent(nextRecord); yield return nextRecord; } else { yield return current; } }修改后的Previous方法:
protected IEnumerable previous(PXAdapter adapter) { INLocation current = Locations.Current; INLocation prevRecord = PXSelect<INLocation, Where<INLocation.locationID, Less<Required<INLocation.locationID>>>, OrderBy<Desc<INLocation.locationID>>> .Select(this, current.LocationID) .FirstOrDefault(); if (prevRecord != null) { adapter.View.Cache.SetCurrent(prevRecord); yield return prevRecord; } else { yield return current; } }验证表单绑定
当前ASPX中PXFormView的DataMember和DataSourceID配置正确,无需修改。
原理说明
Acumatica的PXAdapter会处理回调中的数据同步逻辑,通过SetCurrent()更新缓存状态,配合yield return返回新记录,能触发数据源通知界面控件重新绑定数据,实现界面刷新。
内容的提问来源于stack exchange,提问作者MarkJoel60
相关产品推荐
相关产品推荐

