Programmatically Adding Configurator Input Expressions

I’m trying to programmatically add PcInputExpr records to a pre-designed Configurator through a customization but calling configAdapter.GetNewPcInputsExpr(configID, curInput, “Changed”) results in an error of SeqNum is required.

I encountered a similar error trying to create Inputs programmatically, but realized there were different CreateNew methods I needed to use for PcInputs.

I’ve been able to create Dynamic Lists, List Criteria, and Inputs using similar methods, but this seems to be elusive. Updating expressions works fine, but this error to create new expressions has been troublesome.

Any advice is appreciated.

Terry,
Unfortunately I can’t help with your solution but I guess I will be asking the same thing in the not too distant future.

As an aside did you crack the problem of creating Inputs programmatically as that is the problem I am encountering at the moment. If so, can you point me in the right direction!

Thanks
Dave

Wow, what are you guys doing? I can’t image the user requirements that would require this.

Some example code for creating inputs. I was developing Web Configurators, so I’m not sure if there are different required fields for Product Configurators, but this should be a decent starting point, at least.

For my personal use, I created a UD Form with grids that I could paste insert records that I set up in excel.

ConfigurationDesignAdapter configAd = new ConfigurationDesignAdapter(oTrans);
configAd.BOConnect();

// have to GetByID so header rows are in place for foreign key validation
if (configAd.GetByID(configID))
{
	int recCnt = 0;
	foreach (DataRow row in inputsDT.Rows)
	{
		//DataRow r = configAd.ConfigurationDesignData.PcInputs.Rows;
		
		// get new PcInputs (must use CreateNew)
		int pageSeq = 1;
		if (configAd.CreateNewEmptyPcInputs(configID, pageSeq))
		{
			dr = configAd.ConfigurationDesignData.PcInputs.Rows[configAd.ConfigurationDesignData.PcInputs.Rows.Count - 1];
			
			dr["ConfigID"] = configID;
			dr["InputName"] = row["InputName"].ToString();
			dr["WebInputName"] = row["InputName"].ToString();
			dr["SummaryLabel"] = row["InputName"].ToString();
			dr["TabOrder"] = Convert.ToInt16(row["TabOrder"]);
			dr["DataType"] = row["DataType"].ToString();
			dr["FormatString"] = row["FormatString"].ToString();
			dr["SideLabel"] = row["SideLabel"].ToString();
			dr["ControlType"] = row["ControlType"].ToString();
			dr["DesignControlType"] = row["DesignControlType"].ToString();
			
			dr["PageSeq"] = pageSeq;
			dr["xPos"] = 0;
			dr["yPos"] = 0;
			dr["pWidth"] = 190; // these are valid for text and comboboxes (need to improve to manage other controls)
			dr["pHeight"] = 20;
			dr["AutoSizeList"] = true;
			
			recCnt++;
			configAd.Update();
		}
	}
	
	configAd.Dispose();
	MessageBox.Show(recCnt.ToString() + " inputs added for " + configID);
}

When I’m able to get back into developing the configurators, I’ll be needing to make ~40 of them so I was working on a solution to expedite the grindy parts (creating inputs and dynamic lists, specifically). Largely, I was using the form development to learn the ins and outs of developing within Epicor and hopefully save time in the long run in configurator development. Using some grids, I could make a new configurator with all of its inputs and dynamic lists (some inputs have upwards of 5 lists) in about 30 minutes.

Yikes, I wouldn’t want to be in charge of maintaining 40 configurators :scream:

I don’t know if I could even get someone to fill out that many inputs…

That’s going to take 30 minutes to load…

Evan, Ross and Mark,
What I want to do and have successfully accomplished 80%-90% of, is to data drive the configurator display screens, in my case from a Configurator lookup file which holds all the row, column, length, format details of the fields I want to show on the configurator screen.

I have an external program that generates a screen display much easier than the configurator (about 5 minutes to design a bespoke screen) and this outputs the data in a table form (1 x row per control) to an excel spreadsheet which you can then import into the configurator lookup table. The lookup table holds the data for each design screen with a major key being the screen number which will have multiple rows for each field.

Once a screen design is selected from the configurator by the operator, using the PCLookup feature all the data for the requested screen is loaded in and fields are placed on the screen in the correct row, column locations and formatted as required…This works fine, with no issues.

Using Evan’s coding method of loading like inputs into C# Lists each existing input field is then loaded into the list and associated with a field in the Configurator Lookup table making all displayed inputs to be easily modified as the input control can be manipulated by referencing an element in the “input type” list. Effectively you manipulate the inputs by accessing them as a list element. The element number is held inan internal array which mimics the configurator lookup table but contains the list element number of the control it is bound to as opposed to the input name.

This works fine but we have some 50 possible screens that the sales people may well be using, each being a product or a variation. In addition the total number of unique fields to display in the configurator over all screens could be 500-600 “inputs”. Despite only one screen being used for the product, you have to hold all the possible inputs for all the possible screens if you conventionally drive the configurator and only being able to make the inputs visible or invisible - a very messy method of display.

Doing it my way the inputs have to be pre-defined before you can create a list of them in C# so I simply wanted to create the inputs on the fly as I load in the data driven screen data from the configurator lookup table as opposed to hand tabbing them into the configurator as fixed items at configurator entry time. The controls are a mixture of character, checkbox, decimal fields with a couple of images thrown in for good measure.

Not knowing how many of each control I may need now and in the future I have initially pre loaded up 50 of each field type (not images as we only need a couple) into the configurator. I may need 200 text fields but only 50 check boxes and 40 combo boxes over all screens or any combination, so loading up the maximum I will need at configurator entry time is the only way to be sure you can accomodate any input screen. However, creating the inputs on the fly once I know from the data driven table which screen I want to display and hence the number and types of fields I require would be the optimal solution.

The advantage of data driving the runtime displays is that you can assign a list Number to each control having set up lists for each of the data types which you can in effect bind to an internal array of controls as loaded in from the configurator lookup table.It is the closest you can get to having an object reference to an input.

Hope this is making sense to you all. If not I can post some screenshots and examples of it in action for you to see along with anyone else who is interested. Data driving all input screens is something I have always done in C# projects as you generate the data driving software once and then can re-use it ad infinitum. Unfortunately the inability to use C# reflection in the configurator limits whet you can do to manipulate objects in the configurator but I have overcome this, as I said earlier, with some out of the box thinking.

Dave

I like what you’re trying to do - a lot.

A question though: If you create the inputs on the fly, how do you know how to access them later in the Method Rules or Document Rules?

Maybe making one Master screen is too big a bite and you might better off using your system to scaffold a configurator for each family of parts. :man_shrugging:

Mark,
I construct an array in memory of the controls on the form aligned with the outside data driver table. That way I know which input is to be referenced by accessing the List of controls directly. I means you never reference an input directly, you reference an element in the list that “is” the control. a little like passing a parameter by reference not by value. I’ll post an example later on today.

It really works fine with no screen delays when showing a screen design. As you can immediately reference an input name to correlate with an on screen control then finding a control to add validation/verification code onto is no problem.

I’d love to see a screenshot of a Document Rule or a Method Rule!

Mark,
Rules are no problem and you simply address the objects in the List of control objects as opposed to the actual Inputs. Within the configurator data driver table I hold the name of the Input that is bound to the list item.

Example of a configurator lookup table used to drive the configurator display. Each bagtype (product) has a number of records containing all the field information required to display on the screen.

of input, TextBoxes, EditBocxes, Checkboxes and Labels:

Within the configurator I have a pre-defined number of Inputs with fixed names
txtVar_000 -> txtVar_??? Text Inputs
chkVar_000 -> chkVar_??? Checkbox Inputs
txtVar_000 -> txtVar_??? Label Inputs
imgVar_000 -> imgVar_??? Image Inputs
txtEdit_000 -> txtEdit_??? EditBox Inlputs

So, initially I create a list for each type

/*****************************
String fields to hold Character fields
******************************/
var String_Var = new List<Erp.Shared.Lib.Configurator.InputControlValueBound<Ice.Lib.Framework.EpiTextBox, System.String>>();
String_Var.Add(Inputs.txtVar_000);
String_Var.Add(Inputs.txtVar_001);
String_Var.Add(Inputs.txtVar_002);

In the layout configurator definition table I hold a reference to the Input within an internal array generated at load time.

So any methods can reference the Inputs as follows:

String_Var[3].Value = String_Var[2].Value + String_Var[1].Value

Which is no more difficult to using Input Names

Here are some examples of the data driven screens…