【问题标题】:Creating TreeView for Acumatica为 Acumatica 创建 TreeView
【发布时间】:2017-07-11 17:43:31
【问题描述】:

在 Acumatica 中,我想为物料清单屏幕创建一个 TreeView。 This is what the screen currently looks like 我需要帮助填充网格左侧看到的树。我希望树的最高值是 BOM 项目,然后构成该项目的材料将在每个项目的下方打开。到目前为止,这是我的代码。

<DataTrees>
        <px:PXTreeDataMember TreeKeys="BOMID" TreeView="Nodes" />
        <px:PXTreeDataMember TreeView="_AMBOMTree_Tree_" TreeKeys="OberNbr" />
        <px:PXTreeDataMember TreeKeys="Key" TreeView="CacheTree" />
        <px:PXTreeDataMember TreeKeys="Key" TreeView="EntityItems" />
    </DataTrees>

这是针对数据树本身的。

<px:PXTreeSelector CommitChanges="True" SuppressLabel="False" ID="edGraphType" runat="server" DataField="GraphType" PopulateOnDemand="True"
            ShowRootNode="False" TreeDataSourceID="ds" TreeDataMember="CacheTree" InitialExpandLevel="0" MinDropWidth="297" MaxDropWidth="500"
            TextField="Name" Size="XL">
            <Images>
                <ParentImages Normal="tree@Folder" Selected="tree@FolderS" />
                <LeafImages Normal="tree@Screen" Selected="tree@Screen" />
            </Images>
            <DataBindings>
                <px:PXTreeItemBinding DataMember="CacheTree" TextField="Name" ValueField="SubKey" ImageUrlField="Icon" />
            </DataBindings>
        </px:PXTreeSelector>

这里是 TreeSelector。现在我把它从另一个屏幕上拉下来,想知道这一切是如何运作的。由于我希望该项目显示在顶层,因此请转到构成该项目的材料。如果选择了一个项目,我希望填充网格。我知道 DataField = GraphType 不正确,因为这是从不同的屏幕中提取的,但我不知道应该在这里的值。

<px:PXTreeView ID="tree" runat="server" DataSourceID="ds" Height="500px" PopulateOnDemand="True" ShowRootNode="False"
                    ExpandDepth="1" AutoRepaint="true" Caption="Tree" AllowCollapse="true" PreserveExpanded="true">
                    <ToolBarItems>
                        <px:PXToolBarButton Tooltip="Reload Tree" ImageKey="Refresh">
                            <AutoCallBack Target="tree" Command="Refresh" />
                        </px:PXToolBarButton>
                    </ToolBarItems>
                    <AutoCallBack Target="grid" Command="Refresh" ActiveBehavior="True">
                        <Behavior RepaintControlsIDs="gridMatl" />
                        <Behavior RepaintControlsIDs="gridStep" />
                        <Behavior RepaintControlsIDs="gridTool" />
                        <Behavior RepaintControlsIDs="gridOvhd" />
                    </AutoCallBack>
                    <AutoSize Enabled="True" MinHeight="300" />
                    <DataBindings>
                        <px:PXTreeItemBinding DataMember="Nodes" TextField="Name" ValueField="AssignmentRouteID" ImageUrlField="Icon" />
                    </DataBindings>
                </px:PXTreeView>

那么这就是树视图本身。

如果有人可以帮我编写这棵树,那将是很棒的,或者至少可以为我指明正确的方向。

【问题讨论】:

  • 值得一提的是,这不是标准的 Acumatica 页面
  • 确实这不是标准页面。这是一个自定义页面。我只是不确定 TreeView 在 Acumatica 中的工作原理或至少在选择时填充数据。

标签: c# tree treeview customization acumatica


【解决方案1】:

要在 Acumatica 中添加数据树,需要做 3 件事:

  1. 在 ASPX 页面中,在 PXDataSource 中声明 PXDataTreeMember:

    <px:PXDataSource ID="ds" runat="server" Visible="True" PrimaryView="Document" SuspendUnloading="False" TypeName="PX.TreeDemo.TreeEntry">
      <CallbackCommands>
            <px:PXDSCallbackCommand CommitChanges="True" Name="MyAction" />
            <px:PXDSCallbackCommand CommitChanges="True" Name="MyOtherAction" Visible="False" />
            <px:PXDSCallbackCommand CommitChanges="True" Name="SomeOtherOtherAction" Visible="False" />        
        </CallbackCommands>
        <DataTrees>
            <px:PXTreeDataMember TreeView="Nodes" TreeKeys="NodeID" />
        </DataTrees>
    </px:PXDataSource>
    
  2. 使用链接的 FormView 添加 PXTreeView(通常带有 PXSplitContainer),以显示所选记录。

    <px:PXSplitContainer runat="server" ID="sp1" SplitterPosition="300">
        <AutoSize Enabled="true" Container="Window" />
        <Template1>
            <px:PXTreeView ID="tree" runat="server" DataSourceID="ds" Height="180px"
                ShowRootNode="False" AllowCollapse="False" Caption="Tree Demo" AutoRepaint="True"
                SyncPosition="True" ExpandDepth="4" DataMember="Nodes" KeepPosition="True" 
                SyncPositionWithGraph="True" PreserveExpanded="True" PopulateOnDemand="true" SelectFirstNode="True">
                <ToolBarItems>
                    <px:PXToolBarButton Text="Add Tree Node" Tooltip="Add Tree Node">
                        <AutoCallBack Command="AddNode" Enabled="True" Target="ds" />
                        <Images Normal="main@AddNew" />
                    </px:PXToolBarButton>
    
                    <px:PXToolBarButton Text="Delete Tree Node" Tooltip="Delete Tree Node">
                        <AutoCallBack Command="DeleteNode" Enabled="True" Target="ds" />
                        <Images Normal="main@Remove" />
                    </px:PXToolBarButton>
                </ToolBarItems>
                <AutoCallBack Target="formTree" Command="Refresh" Enabled="True" />
                <DataBindings>
                    <px:PXTreeItemBinding DataMember="Nodes" TextField="DisplayName" ValueField="NodeID" />
                </DataBindings>
                <AutoSize Enabled="True" />
            </px:PXTreeView>
        </Template1>
        <Template2>
            <px:PXFormView ID="formTree" runat="server" DataSourceID="ds" DataMember="CurrentNode" 
                        Caption="Node Info" Width="100%" >
                <Template>
                    <px:PXLayoutRule ID="PXLayoutRule1" runat="server" StartColumn="True" LabelsWidth="S" ControlSize="SM" />
                    <px:PXSelector ID="edNodeID" runat="server" DataField="NodeID" CommitChanges="True" AutoRefresh="True" />                   
                </Template>
            </px:PXFormView>
        </Template2>
    </px:PXSplitContainer>
    
  3. 创建 DataViews、DataViews 委托和 Tree Actions。

    public PXSelect<TreeNode> Nodes;
    public PXSelect<TreeNode,
               Where<TreeNode.parentNodeID,
                   Equal<Optional<TreeNode.nodeID>>>> ChildNodes;
    public PXSelect<TreeNode, 
                Where<TreeNode.nodeID, 
                    Equal<Current<TreeNode.nodeID>>>> CurrentNode;
    
    #endregion
    
    #region Delegates
    
    protected virtual IEnumerable nodes(
        [PXInt]
        int? nodeID
    )
    {
        if (nodeID == null)
        {
            yield return new TreeNode()
            {
                ParentNodeID = 0,
                NodeID = 0
            };
        }
        else
        {
            foreach (TreeNode node in ChildNodes.Select(nodeID))
            {
                yield return node;
            }
        }
    
    }
    protected virtual IEnumerable currentNode()
    {
        if (Nodes.Current != null)
        {
            var isNotRoot = Nodes.Current.NodeID != 0;
    
            //Situation where we would want to limit the recursion to one 
            AddNode.SetEnabled(!isNotRoot);
            DeleteNode.SetEnabled(isNotRoot);
    
            Caches[typeof(TreeNode)].AllowInsert = isNotRoot;
            Caches[typeof(TreeNode)].AllowDelete = isNotRoot;
            Caches[typeof(TreeNode)].AllowUpdate = isNotRoot;
    
            foreach (TreeNode item in PXSelect<TreeNode,
                                                    Where<TreeNode.nodeID, 
                                                        Equal<Required<TreeNode.nodeID>>>>.
                                                Select(this, Nodes.Current.NodeID))
            {
                yield return item;
            }
        }
    }
    
    
    public PXAction<NodeSetup> AddNode;
    [PXUIField(DisplayName = " ", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Enabled = true)]
    [PXButton()]
    public virtual IEnumerable addNode(PXAdapter adapter)
    {
        var selectedNode = Nodes.Current;
        if (selectedNode.ParentNodeID == 0)
        {
            var inserted = (TreeNode)Caches[typeof(TreeNode)].Insert(new TreeNode
            {
                ParentNodeID = Nodes.Current.NodeID
            });
    
            inserted.TempChildID = inserted.NodeID;
            inserted.TempParentID = inserted.ParentNodeID;
    
            Nodes.Cache.ActiveRow = inserted;
        }
        return adapter.Get();
    }
    
    public PXAction<NodeSetup> DeleteNode;
    [PXUIField(DisplayName = " ", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Enabled = true)]
    [PXButton()]
    public virtual IEnumerable deleteNode(PXAdapter adapter)
    {
        var selectedNode = Nodes.Current;
        if(selectedNode.NodeID != 0)
        {
            if(selectedNode.ParentNodeID == 0)
            {
                var childrenNodes = ChildNodes
                                     .Select(selectedNode.NodeID)
                                     .Select(br => (TreeNode)br).ToList();
    
                if (childrenNodes.Any())
                {
                    if (Document.Ask(Messages.ValidationDeleteChildren, MessageButtons.YesNo) == WebDialogResult.Yes)
                    {
                        foreach(var childrenNode in childrenNodes)
                        {
                            Caches[typeof(TreeNode)].Delete(childrenNode);
                        }
                        Caches[typeof(TreeNode)].Delete(selectedNode);
                    }
                }
                else
                {
                    Caches[typeof(TreeNode)].Delete(selectedNode);
                }
            }
            else
            {
                Caches[typeof(TreeNode)].Delete(selectedNode);
            }
        }
    
        return adapter.Get();
    }
    

解决问题的最简单方法通常是使用单个 ID。因为您的对象不会都是相同的(BOM / MATL / ETC),所以您需要能够从 ID 中找出它。我建议的解决方案是格式化 NodeID 以获取获取所需记录所需的所有信息(E.I. BOM-BM00001_MATL-INVIDANDOTHERKEYFIELD)。这样您就可以知道自己的级别并返回正确的子级(在 Dataview 委托 nodes(int? nodeID) 中)。

【讨论】:

  • 单一ID是指节点ID还是BOM ID?
  • 我将添加一个新的未绑定 DAC,它是一个通用的“BomTreeNode”。此 DAC 的关键字段将是所有其他相关关键字段的可解析聚合(例如:要查找 MATL,您需要有一个 BOMID + MATLID,因此对于单个字符串,您需要拥有所有信息来创建选择查询点在 MATL 上)。
  • TreeNode 在哪里被引用?它与我的代码中的 WebControls 发生冲突,在删除和添加 PX.SM 时它仍然说同样的话。
  • 受保护的虚拟 IEnumerable currentNode() { if (Nodes.Current != null) { var isNotRoot = Nodes.Current.BOMID != "0"; foreach (AMBomItem item in PXSelect>>>. Select(this, Nodes.Current.BOMID)) { yield return item; } } }
  • 上面的代码说需要一个对象引用,但我不知道该放在哪里。
猜你喜欢
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 2020-02-06
相关资源
最近更新 更多