【问题标题】:Acumatica Processing Screen with Parameter Doesn't Refresh带有参数的 Acumatica 处理屏幕不刷新
【发布时间】:2018-02-22 12:00:09
【问题描述】:

问题摘要:

我的新屏幕上的处理逻辑正在运行,但页面没有向用户显示任何反馈(例如,计时器没有显示,没有红色/绿色复选框,复选框没有被禁用)

问题详情:

我正在创建一个处理屏幕,它需要来自用户的单独信息以供处理委托使用。业务逻辑有效,但用户体验与其他处理屏幕不同。当您单击处理时,不会向用户显示任何内容。通常,页面会通过禁用并仅显示正在处理的选定项目来刷新网格,此外还会添加长操作计时器(然后根据进程是成功还是失败替换为绿色检查或红色 x)。当我单击处理时,检查了整个网格的所有选定列,但没有其他任何变化(例如,没有计时器、状态,也没有禁用网格)。最终,流程和流程都执行业务逻辑,但用户看不到任何表明成功/失败的信息。

屏幕显示所有客户位置,因为该过程正在更新我们根据每个位置存在的订单为每个位置保留的一些统计信息。

我的图表

public class CalculateLocationStatsProcess : PXGraph<CalculateLocationStatsProcess>
{
    public PXCancel<LocationStatsFilter> Cancel;

    public PXFilter<LocationStatsFilter> filterLocStat;
    public PXFilteredProcessingJoin<Location,
        LocationStatsFilter,
        InnerJoin<Customer, On<Customer.bAccountID, Equal<Location.bAccountID>>>,
        Where<True, Equal<True>>,
        OrderBy<Asc<Customer.acctCD, Asc<Location.locationCD>>>> processLocations;

    public CalculateLocationStatsProcess()
    {
    }

    public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
    {
        processLocations.SetProcessDelegate(
            delegate (List<Location> list)
            {
                var newList = new List<Location>();
                foreach (Location locLp in list)
                {
                    newList.Add(locLp);
                }
                CalculateLocationStatsProcess.updateLocationStats(newList, filterLocStat.Current);
            }
        );
    }

    public static void updateLocationStats(List<Location> locations, LocationStatsFilter filter)
    {
        var graph = new PXGraph();
        var locStats = new StatsHelper(graph, filter.TargetDate);

        bool erred = false;
        for (int iLp = 0; iLp < locations.Count; iLp++)
        {
            Location locationLp = locations[iLp];
            PXProcessing<Location>.SetCurrentItem(locationLp);
            try
            {
                locStats.setCommStats(locationLp);
            }
            catch (Exception ex)
            {
                erred = true;
                PXProcessing<Location>.SetError(iLp, ex.Message);
            }
        }

        locStats.StatCache.Persist(PXDBOperation.Insert);
        locStats.StatCache.Persist(PXDBOperation.Update);

        if (erred)
        {
            throw new PXException("Location(s) failed during recalculation process. View individual lines to see their specific error.");
        }
    }
}

我的页面

<%@ Page Language="C#" MasterPageFile="~/MasterPages/FormDetail.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="SO509503.aspx.cs" Inherits="Page_SO509503" Title="Calculate Location Stats" %>
<%@ MasterType VirtualPath="~/MasterPages/FormDetail.master" %>

<asp:Content ID="cont1" ContentPlaceHolderID="phDS" runat="Server">
    <px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" PrimaryView="filterLocStat" TypeName="exampleNS.CalculateLocationStatsProcess">
        <CallbackCommands>
        </CallbackCommands>
    </px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" runat="Server">
    <px:PXFormView ID="formFilter" runat="server" DataMember="filterLocStat" DataSourceID="ds" Style="z-index: 100" Width="100%" >
        <Template>
            <px:PXLayoutRule runat="server" ID="PXLayoutRule1" ControlSize="M" LabelsWidth="M" StartRow="true" />
            <px:PXDateTimeEdit runat="server" ID="edTargetDate" DataField="TargetDate" />
        </Template>
    </px:PXFormView>
</asp:Content>
<asp:Content ID="cont3" ContentPlaceHolderID="phG" runat="Server">
    <px:PXGrid ID="gridLocations" runat="server" 
        AdjustPageSize="Auto" AllowPaging="True" AllowSearch="true" DataSourceID="ds" FilesIndicator="false" 
        Height="400px" NoteIndicator="false" SkinID="Inquire" Style="z-index: 100" SyncPosition="true" Width="100%" >
        <AutoSize Container="Window" Enabled="True" MinHeight="200" />
        <Levels>
            <px:PXGridLevel DataMember="processLocations">
                <Columns>
                    <px:PXGridColumn DataField="Selected" Type="CheckBox" AllowCheckAll="true" Width="40px" />
                    <px:PXGridColumn DataField="Customer__AcctCD" Width="125px" />
                    <px:PXGridColumn DataField="LocationCD" Width="75px" />
                    <px:PXGridColumn DataField="Descr" Width="175px" />
                </Columns>
            </px:PXGridLevel>
        </Levels>
    </px:PXGrid>
</asp:Content>

我的过滤器 DAC

public class LocationStatsFilter : IBqlTable
{
    #region TargetDate
    public abstract class targetDate : IBqlField { }
    [PXDate()]
    [PXUIField(DisplayName = "Target Month and Year")]
    public virtual DateTime? TargetDate { get; set; }
    #endregion
}

我的附加地址信息 DAC

[PXTable(typeof(Location.locationID), typeof(Location.bAccountID), IsOptional = false)]
public class LocationExt : PXCacheExtension<Location>
{
    #region Selected
    public abstract class selected : IBqlField { }
    [PXBool()]
    [PXDefault(false)]
    [PXUIField(DisplayName = "Selected")]
    public virtual bool? Selected { get; set; }
    #endregion
    #region DateFirstService
    public abstract class dateFirstService : IBqlField { }
    [PXDBDate()]
    [PXUIField(DisplayName = "Date of First Service")]
    public virtual DateTime? DateFirstService { get; set; }
    #endregion
}

我根据我找到的几个处理屏幕对我的解决方案进行了建模,但是我查看了很多我无法说出我使用哪些作为示例的屏幕。我在 RowSelected 事件和构造函数之间移动了 SetProcessDelegate 调用,但没有成功。我尝试将 updateLocationStats 函数设为静态而不是静态(使用现有图表),但没有成功。

更新:

  • 直接调用 updateLocationStats 方法而不是创建一个 列表的副本没有改变结果。
  • 将 PXFilterable 添加到 PXFilteredProcessingJoin 并没有改变结果
  • 删除对 locStats 的调用(creation、setCommStats(locationLp)、Persist)并没有改变结果
  • 添加了缺失的位置 DAC
  • 已尝试将 Selected 从 LocationExt DAC 移动到新的 LocationAlt:Location DAC 结果没有变化。
  • 向页面中的选定字段添加了 DataType="Boolean"。行为没有改变
  • 在 PXGrid 标记中添加了 BatchUpdate="True"。行为没有变化。
  • 添加了 PXProcessing.SetProcessed();在 locStats.setCommStats(locationLp) 之后;行为没有改变。

替代测试

public class LocationAlt : Location
{
    #region Selected
    public abstract class selected : IBqlField { }
    [PXBool()]
    [PXDefault(false)]
    [PXUIField(DisplayName = "Selected")]
    public virtual bool? Selected { get; set; }
    #endregion
}

public class CalculateLocationStatsProcess : PXGraph<CalculateLocationStatsProcess>
{
    public PXCancel<LocationStatsFilter> Cancel;

    public PXFilter<LocationStatsFilter> filterLocStat;
    [PXFilterable()]
    public PXFilteredProcessingJoin<LocationAlt,
        LocationStatsFilter,
        InnerJoin<Customer, On<Customer.bAccountID, Equal<LocationAlt.bAccountID>>>,
        Where<True, Equal<True>>,
        OrderBy<Asc<Customer.acctCD, Asc<LocationAlt.locationCD>>>> processLocations;

    public CalculateLocationStatsProcess()
    {
    }

    public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
    {
        processLocations.SetProcessDelegate(
            delegate (List<LocationAlt> list)
            {
                CalculateLocationStatsProcess.updateLocationStats(list, filterLocStat.Current);
            }
        );
    }

    public static void updateLocationStats(List<LocationAlt> locations, LocationStatsFilter filter)
    {
        var graph = new PXGraph();
        var locStats = new CommStatsHelper(graph, filter.TargetDate);

        bool erred = false;
        for (int iLp = 0; iLp < locations.Count; iLp++)
        {
            LocationAlt locationLp = locations[iLp];
            PXProcessing<LocationAlt>.SetCurrentItem(locationLp);
            try
            {
                locStats.setCommStats(locationLp);
            }
            catch (Exception ex)
            {
                erred = true;
                PXProcessing<LocationAlt>.SetError(iLp, ex.Message);
            }
        }

        locStats.StatCache.Persist(PXDBOperation.Insert);
        locStats.StatCache.Persist(PXDBOperation.Update);

        if (erred)
        {
            throw new PXException("Location(s) failed during recalculation process. View individual lines to see their specific error.");
        }
    }
}

请注意,备用测试也不起作用。

【问题讨论】:

  • 我注意到在您的 Persist 上您正在使用 DataView。您是否尝试过直接使用图形全局缓存。例如:“graph.Persist();”另外,您能否提供有关 StatsHelper() 和 setCommStats() 方法的详细信息? (不清楚您是否坚持在静态方法上声明的相同图或“locStats”是否属于另一个图。
  • @cbetabeta 我理解这个问题,但即使我注释掉所有包含 locStats 的 4 行,页面的行为也是一样的。它没有放置计时器,没有放置绿色/红色状态指示器,也没有禁用/缩小网格。
  • 作为一个仅供参考,StatsHelper 是一个将图形作为参数的类(将其存储为属性,然后将其用于需要执行的任何选择/持久化)。 StatCache 只是获取 graph.Caches[typeof(LocationStat)] 的只读属性
  • 我认为您应该分别处理所有问题。例如,计时器可能会被隐藏,因为您没有在委托中做任何重要的工作。尝试将 Thread.Sleep 放在那里而不是评论实际过程。
  • 代码中有很多可能出错的地方,但我们不知道,因为我们没有看到它。更直接的方法将消除歧义。例如,不要为已处理的记录创建列表副本 'var newList',直接使用委托 'List list'。尝试直接修改和保存记录,例如:list[0].Active = false; sender.Caches[typeof(Location)].Update(list[0]); sender.Caches[typeof(Location)].Persist(PXDBOperation.Update);.

标签: acumatica


【解决方案1】:

遇到的问题是因为原始图实例(即您第一次进入屏幕时所在的图实例)没有保持执行图实例的范围(即正在执行逻辑的图表)。

为了让 Acumatica 放置处理状态逻辑(例如计时器、绿色/红色状态圆圈),看起来原始图表需要指向执行操作的图表的链接。当您将 SetProcessDelegate 指向方法委托时,这似乎为您处理得很好。

在此处的问题中,您正在创建一个临时委托(通过在构造函数/rowselected 事件中使用委托关键字)。变量声明(不是实例化)需要在委托之外。

更正了代表的设置

CalculateLocationStatsProcess graph = null;
processLocations.SetProcessDelegate((List<Location> list) => 
    {
        graph = PXGraph.CreateInstance<CalculateLocationStatsProcess>();
        CalculateLocationStatsProcess.updateLocationStats(list, filterLocStat.Current);
    }
);

注意第一行在 SetProcessDelegate 调用之前。即使图形没有在委托之外实例化,也会创建图形指针。因此,它会在分配链接并根据需要更新 UI 时出现。

补充说明

  • 所选字段仍作为扩展的一部分存在
  • 我将函数保留为静态,但如果转换为非静态,它确实可以正常工作,您只需将 CalculateLocationStatsProcess.updateLocationStats(list, filterLocStat.Current); 更改为 graph.updateLocationStats(list, filterLocStat.Current);
  • 委托声明可以出现在构造函数public CalculateLocationStatsProcess() 或过滤器的行选定事件处理程序public virtual void LocationStatsFilter_RowSelected(PXCache sender, PXRowSelectedEventArgs e) 中,两者都对我有用。
  • BatchUpdate="true" 不是必需的。
  • DataType="Boolean" 不是必需的。

最后,链接的Customer__AcctCD 会在进程完成后清除(连接似乎不会保留字段填充),因此需要更改一些用于在图表上显示AcctCD 的代码。由于这不是所提出问题的重点,因此我不打算在此处包含该代码。

【讨论】:

  • 嗨 yc9nyw08vf,正如您所提到的,Customer__AcctCD 将在处理过程中被清除。对我来说,这实际上正在发生一种类似的情况。请告诉我如何在处理过程中重新填充图表中的这些列。
  • @Krunal,我结束了将处理缓存修改为新投影,而不是与客户连接的位置。我的投影被定义为 [PXProjection(typeof(Select2>>>))] (IBqlTable 实现定义了 BAccountID、LocationID、AcctCD、Descr、 LocationCD,选定的字段)。然后更新我的静态方法以接受我的投影列表,并修改逻辑以检索 Location 作为循环的第一步。最后,页面更新为投影中定义的字段名。
  • 完美。谢谢@yc9nyw08vf
【解决方案2】:

我认为您的 DAC 中缺少 Selected data 字段:

#region Selected
public abstract class selected : IBqlField
{
}
protected bool? _Selected = false;
[PXBool]
[PXDefault(false)]
[PXUIField(DisplayName = "Selected")]
public bool? Selected
{
    get
    {
        return _Selected;
    }
    set
    {
        _Selected = value;
    }
}
#endregion

不要直接使用 Location,而是为 Location (LocationStat?) 创建一个 DAC 扩展,您将在其中添加 Selected 字段。不要在处理屏幕中使用位置,使用包含所选字段的扩展名。

【讨论】:

  • 我忘记包含我所做的地址扩展。我已经编辑了我的问题以显示此信息。对于您的建议“不要使用位置”,我有点不确定您的意思,除非实际使用字段,否则不需要在 BQL 中直接引用位置的缓存扩展。我实施了我相信您所问的内容并将其添加到问题的末尾。如果我误解了,请您澄清一下您的意思吗?
  • 该框架实际上是在处理屏幕的封面下使用 Selected 字段,它不是 Location DAC 的一部分。我的意思是将 Location 的所有引用替换为 CalculateLocationStatsProcess 中的扩展。它看起来不错。例如:“PXFilteredProcessingJoin
  • 如果您实际上是在使用 PXTrace 或托管调试器访问进程委托,您是否进行了调试?
  • 同样在 ASPX 中
  • 您可能还想尝试在 PXGrid 元素上添加 BatchUpdate="True" 属性。
猜你喜欢
  • 1970-01-01
  • 2018-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
  • 1970-01-01
相关资源
最近更新 更多