Add UD fields from other BO in grid

Here’s my full code FFR. To add the field to every grid on POEntry is more code than I thought it would be, and if adding multiple fields it could get cumbersome to the point that it might be better to add a UD field to the PODetail table instead. If the grid is used in two places like it is on POEntry, you need duplicate statements for each using the “-1” control reference modifier or the column does not appear in the second grid location. Interestingly, you cannot use the same column key name in the duplicate grids without getting a “duplicate key” error.

// **************************************************
// Custom code for POEntryForm
// Created: 12/14/2018 11:33:02 AM
// **************************************************

extern alias Erp_Contracts_BO_Vendor;
extern alias Erp_Contracts_BO_Company;
extern alias Erp_Contracts_BO_Part;
extern alias Erp_Contracts_BO_VendorPPSearch;
extern alias Erp_Contracts_BO_VendCntSearch;
extern alias Erp_Contracts_BO_PO;
extern alias Erp_Contracts_BO_MiscShip;
extern alias Erp_Contracts_BO_Receipt;
extern alias Erp_Contracts_BO_Plant;
extern alias Erp_Contracts_BO_JobEntry;
extern alias Erp_Contracts_BO_JobMtlSearch;
extern alias Ice_Contracts_Lib_BOReader;

using System;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using Erp.Adapters;
using Erp.UI;
using Ice.Lib;
using Ice.Adapters;
using Ice.Lib.Customization;
using Ice.Lib.ExtendedProps;
using Ice.Lib.Framework;
using Ice.Lib.Searches;
using Ice.UI.FormFunctions;
using Ice.Proxy.Lib;
using Ice.Core;
using Erp.BO;
using Ice.BO;

public class Script
{
	// ** Wizard Insert Location - Do Not Remove 'Begin/End Wizard Added Module Level Variables' Comments! **
	// Begin Wizard Added Module Level Variables **

	// End Wizard Added Module Level Variables **

	// Add Custom Module Level Variables Here **
	EpiUltraGrid invGrid;
	EpiUltraGrid jobGrid;
	EpiUltraGrid otherGrid;
	EpiUltraGrid subcGrid;
	EpiUltraGrid allGrid;

	EpiUltraGrid inv1Grid;
	EpiUltraGrid job1Grid;
	EpiUltraGrid other1Grid;
	EpiUltraGrid subc1Grid;
	EpiUltraGrid all1Grid;

	BOReaderImpl _boReader;

	public void InitializeCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Variable Initialization' lines **
		// Begin Wizard Added Variable Initialization

		// End Wizard Added Variable Initialization

		// Begin Wizard Added Custom Method Calls

		// End Wizard Added Custom Method Calls
		invGrid = (EpiUltraGrid)csm.GetNativeControlReference("619b890f-7d96-4dbe-9309-fd59da524a6a");
		jobGrid = (EpiUltraGrid)csm.GetNativeControlReference("f50efdf8-0d94-4cf6-94a0-f36ef621a65f");
		otherGrid = (EpiUltraGrid)csm.GetNativeControlReference("f9f11205-b912-427d-8a3b-e0611df23bcc");
		subcGrid = (EpiUltraGrid)csm.GetNativeControlReference("43480e8c-c34e-43f6-89f7-f9760d615158");
		allGrid = (EpiUltraGrid)csm.GetNativeControlReference("b106bc38-b2e2-4a22-ab02-6c3eea9acbf6");
		inv1Grid = (EpiUltraGrid)csm.GetNativeControlReference("619b890f-7d96-4dbe-9309-fd59da524a6a-1");
		job1Grid = (EpiUltraGrid)csm.GetNativeControlReference("f50efdf8-0d94-4cf6-94a0-f36ef621a65f-1");
		other1Grid = (EpiUltraGrid)csm.GetNativeControlReference("f9f11205-b912-427d-8a3b-e0611df23bcc-1");
		subc1Grid = (EpiUltraGrid)csm.GetNativeControlReference("43480e8c-c34e-43f6-89f7-f9760d615158-1");
		all1Grid = (EpiUltraGrid)csm.GetNativeControlReference("b106bc38-b2e2-4a22-ab02-6c3eea9acbf6-1");		

		invGrid.DisplayLayout.Bands[0].Columns.Add("SageID_c","Sage ID");
		jobGrid.DisplayLayout.Bands[0].Columns.Add("SageID_c","Sage ID");
		otherGrid.DisplayLayout.Bands[0].Columns.Add("SageID_c","Sage ID");
		subcGrid.DisplayLayout.Bands[0].Columns.Add("SageID_c","Sage ID");
		allGrid.DisplayLayout.Bands[0].Columns.Add("SageID_c","Sage ID");
		inv1Grid.DisplayLayout.Bands[0].Columns.Add("SageID_c1","Sage ID");
		job1Grid.DisplayLayout.Bands[0].Columns.Add("SageID_c1","Sage ID");
		other1Grid.DisplayLayout.Bands[0].Columns.Add("SageID_c1","Sage ID");
		subc1Grid.DisplayLayout.Bands[0].Columns.Add("SageID_c1","Sage ID");
		all1Grid.DisplayLayout.Bands[0].Columns.Add("SageID_c1","Sage ID");
		
		invGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		jobGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		otherGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		subcGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		allGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		inv1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst1_InitializeRow);
		job1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst1_InitializeRow);
		other1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst1_InitializeRow);
		subc1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst1_InitializeRow);
		all1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst1_InitializeRow);

		_boReader = WCFServiceSupport.CreateImpl<BOReaderImpl>((Ice.Core.Session)oTrans.Session, Epicor.ServiceModel.Channels.ImplBase<Ice.Contracts.BOReaderSvcContract>.UriPath);
	}
	private void grdMatLst_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
	{
		if(!String.IsNullOrEmpty(e.Row.Cells["PartNum"].Value.ToString()))
		{
			DataSet ds = _boReader.GetRows("Erp:BO:Part","PartNum = '" + e.Row.Cells["PartNum"].Value.ToString() + "'","PartNum, SageID_c");
			if(ds.Tables[0].Rows.Count > 0 ) 
			{
				e.Row.Cells["SageID_c"].Value = ds.Tables[0].Rows[0]["SageID_c"].ToString();
			}
		}
	}
	private void grdMatLst1_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
	{
		if(!String.IsNullOrEmpty(e.Row.Cells["PartNum"].Value.ToString()))
		{
			DataSet ds = _boReader.GetRows("Erp:BO:Part","PartNum = '" + e.Row.Cells["PartNum"].Value.ToString() + "'","PartNum, SageID_c");
			if(ds.Tables[0].Rows.Count > 0 ) 
			{
				e.Row.Cells["SageID_c1"].Value = ds.Tables[0].Rows[0]["SageID_c"].ToString();
			}
		}
	}
	public void DestroyCustomCode()
	{
		// ** Wizard Insert Location - Do not delete 'Begin/End Wizard Added Object Disposal' lines **
		// Begin Wizard Added Object Disposal

		// End Wizard Added Object Disposal

		// Begin Custom Code Disposal

		// End Custom Code Disposal
		invGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		jobGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		otherGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		subcGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		allGrid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		inv1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		job1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		other1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		subc1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);
		all1Grid.InitializeRow += new Infragistics.Win.UltraWinGrid.InitializeRowEventHandler(grdMatLst_InitializeRow);				
		_boReader = null;
	}
}
2 Likes

Hi @james and @rbucek
many thanks for this update, finally i got my customisation to work following your code logic, so many thanks for this guys, the only issue as you said is that UI become a bit slow retrieving the data for each row of the grid, just wonder what is Epicor design structure trick when build such custom tracker screen, they obviously using a different technique to call data from different BO into such grids.


in doing this we are hijacking off of some infragistics control events to bring in data and you are making a call for every row as it initializes in the screen. Epicor wires up their data calls using their framework and binds the datasource accordingly. We are making inefficient calls to bring back additional data. At the point this becomes too poor in performance is where you need to hang your own grid entirely, create a custum epidata view from a BAQ and subscribe to some key value in the form.

2 Likes

Discovered an issue with this method this morning: after adding a new row, this code forces the previous row to be active. In POEntry, entering a part number on a new line and then tabbing out causes the previous line to show in the Lines>Detail tab. Trying to select the newly added line throws the “A valid quantity is required” error, so it is never selectable, and the only way out is the undo button. If adding lines in the Lines>List tab or if entering the quantity prior to entering a part number this is not a problem.
Code also throws a “Record not found” error when deleting the PO, so a test should be added to check for the active record may be needed. I’ve had to turn off this customization for now until I find a way to end on the new row, or to reinitialize each row only after the new row is saved.

many thanks @rbucek,
i can replace the entire grid as you suggest, but with most of these grids, it contains custom calculated fields, custom tracker views, and/or linked functional buttons which can not be replicated easelly even if you have Epicor KDS.

Depending on the screen I would not give up on adding a column as there are multiple ways. The example below uses a dynamic query to pull data (by passing a parameter list), stores this in a variable and then updates the grid (I show it using Click Me button) but it can be done once the grid is painted. As you can see the addition of the column is very fast (timer shows with 100 rows)

thanks for that @danbedwards
performance look good, are you using GetRows or GetList? and could you share your code ?

@danbedwards @rbucek @james
just to let you know guys that using dynamic query instead of GetRows/bo_Reader has improved the performance by approximately 64%

1 Like

Nice. You can trim additional time off by building a list of Job numbers by looping through the rows in the grid and then passing the job list through a dynamic query (parameter list) and pull back a larger data set vs. row by row. In your example, if you had 500 rows then the dynamic query gets called 500 times - if you use the method I listed above you could call the dynamic query once and return everything in one call. You can also put the grid in edit mode and disable the row sync for improved performance when adding columns or updating data.
https://www.infragistics.com/community/forums/f/ultimate-ui-for-windows-forms/15306/wingrid-performance-guide

1 Like

why don’t you use a BPM on the getList method to populate a custom column and just create a basic customization to show that column? You will not have a hit on performance if you use this approach

Regards

1 Like

many thanks @Christian_Pouchoulen
how you will link the key value for each row on the custom grid to the one column returned list ? i appreciate if you could share any code example of using this approach i.e. GetList within BPM classes

that is an interesting idea, i will check this website and try it, it will definitely improve the performance even better when the dynamic query execution to run once.

is this what you mean by formatted the column and make it disable

This is what I would do. It takes 10 lines of code to add any column from other tables to that grid. I created a ui customization just to repurpose one of the hidden columns. I also created a BPM that populates that column with the information that I want. On my example, I wanted to display the JobHead.JobRelease flag.

I hope this helps

JobSchedBoard.docx (165.9 KB)

7 Likes

@Christian_Pouchoulen,
this is very smart mate :ok_hand::ok_hand:, really out of the box solution :heavy_check_mark::heavy_check_mark::heavy_check_mark:

using one of the grid built-in field, intercept its value at grid display and replace it by ours using BPM class.
i believe this will always be the easiest solution to apply unless that all grid fields need to be displayed, i really appreciate sharing this great idea my friend.:+1::+1:

1 Like

Yes, I like this solution. It is fast, reliable and easy to maintain. My advise is to repurpose fields only when you can’t add udfields

Happy coding!

Did you share your code on this?

1 Like

@skearney, here is the code

Hi,
I have a similar customization to do. I am thinking this method would be ideal but I am getting this error right at the start;

The name ‘ttSchedulingBoard’ does not exist in the current context

Have I overlooked something obvious?

Kinetic doesn’t use the same nomenclature. Try … (from row in result.SchedulingBoard select row)

2 Likes

Excellent! thanks @Doug.C

It’s all these little things that make upgrading so frustrating. I would never have known that.

Thanks again.