Run Custom Action through Customization Code

Hi all!
Thanks for your input on my last related post:
https://www.epiusers.help/t/more-than-one-ubaq-in-a-dashboard/

This post expands on the issue I had encountered at the end, but it doesn’t really have to do with the topic of the original post.

I have a UBAQ loaded into an ultragrid on a dashboard. In the UBAQ there are two checkboxes that allows the user to either delete or update a release. On the dashboard, I added a button to run the custom action (actionID = ProcessCommands) after the user clicks some checkboxes. Here is the code for that button. The function at the bottom just reloads the ultragrid with the refreshed UBAQ.

	private void epiBtnUpdateOur_Click(object sender, System.EventArgs args)
	{
		// ** Place Event Handling Code Here **
		DynamicQueryAdapter dqa = new DynamicQueryAdapter(oTrans);
		DataTable results;		
		results = new DataTable(); 	   
		dqa.BOConnect();
		dqa.Update("x_ThisWeekUpdate_OurUnmatched", results.DataSet); 
		dqa.RunCustomAction("x_ThisWeekUpdate_OurUnmatched", "ProcessCommands", results.DataSet, true);
		LoadMyBAQ("x_ThisWeekUpdate_OurUnmatched", epiUltraGridC2);
	}

I kept getting this error until I went to Updateable BAQ Maintenance and refreshed my UBAQs.

There is no BPM customization attached to Update method of ‘x_ThisWeekUpdate_OurUnmatched’ updatable query in ‘VTAERO’ company or BPM system is not enabled.
Please check presence of BPM customization and/or ask administrator for assistance.

After I updated the BAQ, the error changed to this:

Application Error

Exception caught in: Epicor.ServiceModel

Error Detail

Message: Object reference not set to an instance of an object.
Program: Epicor.ServiceModel.dll
Method: ShouldRethrowNonRetryableException

Client Stack Trace

at Epicor.ServiceModel.Channels.ImplBase1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets) at Ice.Proxy.BO.DynamicQueryImpl.RunCustomActionByID(String queryID, String actionID, DataSet queryResultDataset) at Ice.Adapters.DynamicQueryAdapter.<>c__DisplayClass34_0.<RunCustomAction>b__0(DataSet datasetToSend) at Ice.Adapters.DynamicQueryAdapter.ProcessUbaqMethod(String methodName, DataSet updatedDS, Func2 methodExecutor, Boolean refreshQueryResultsDataset)
at Ice.Adapters.DynamicQueryAdapter.RunCustomAction(String queryID, String actionId, DataSet updatedDS, Boolean refreshQueryResultsDataset)
at Script.epiBtnUpdateOur_Click(Object sender, EventArgs args)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButtonBase.OnClick(EventArgs e)
at Ice.Lib.Framework.EpiButton.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButton.OnMouseUp(MouseEventArgs e)
at Ice.Lib.Framework.EpiButton.OnMouseUp(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

It seems like this simple code should do the trick. Can you see any major issues?

Rather than try to fix this code, or figure out this elusive error, does anyone have any code examples showing how you implemented your custom actions inside a dashboard customization?

Thanks a lot for your time!
Nate

Here is another similarly simple version of the same code. It compiles ok, but returns an error. The problem seems to be with the Update line. I have tried calling these methods with every overload version I can think of and get similar errors each time. I must be missing something critical.

	private void epiBtnUpdateOur_Click(object sender, System.EventArgs args)
	{
		// ** Place Event Handling Code Here **
		DynamicQueryAdapter dqa = new DynamicQueryAdapter(oTrans);
		DataTable results;		
		results = new DataTable(); 
		dqa.BOConnect();
		dqa.ExecuteByID("x_ThisWeekUpdate_OurUnmatched");		
		Ice.BO.DynamicQueryDataSet dqDS;
		dqDS = dqa.DynamicQueryData;
		dqa.Update(dqDS, results.DataSet);
		dqa.RunCustomAction(dqDS, "ProcessCommands", results.DataSet, true);
		LoadMyBAQ("x_ThisWeekUpdate_OurUnmatched", epiUltraGridC2);
	}

With error:

Application Error

Exception caught in: Epicor.ServiceModel

Error Detail

Message: Can’t find query definition in passed dataset
Program: Epicor.ServiceModel.dll
Method: ShouldRethrowNonRetryableException

Client Stack Trace

at Epicor.ServiceModel.Channels.ImplBase1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets) at Ice.Proxy.BO.DynamicQueryImpl.Update(DynamicQueryDataSet queryDS, DataSet queryResultDataset) at Ice.Adapters.DynamicQueryAdapter.<>c__DisplayClass27_0.<Update>b__0(DataSet datasetToSend) at Ice.Adapters.DynamicQueryAdapter.ProcessUbaqMethod(String methodName, DataSet updatedDS, Func2 methodExecutor, Boolean refreshQueryResultsDataset)
at Ice.Adapters.DynamicQueryAdapter.Update(DynamicQueryDataSet queryDS, DataSet updatedDS, Boolean refreshQueryResultsDataset)
at Script.epiBtnUpdateOur_Click(Object sender, EventArgs args)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButtonBase.OnClick(EventArgs e)
at Ice.Lib.Framework.EpiButton.OnClick(EventArgs e)
at Infragistics.Win.Misc.UltraButton.OnMouseUp(MouseEventArgs e)
at Ice.Lib.Framework.EpiButton.OnMouseUp(MouseEventArgs e)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

I am still struggling with this issue. This is also related to another post:

The code looks straightforward, but returns an error:

		DynamicQueryAdapter dqa = new DynamicQueryAdapter(this.oTrans);
		DataTable results = new DataTable();
		dqa.BOConnect();
		string baqname = "ChangeOpenJobResGrpIDs";		
		dqa.RunCustomAction(baqname, "ChangeResGrpID", results.DataSet, true);
		LoadMyBAQwParam(baqname, epiUltraGridC1, "OldResGrpID", epiTextBoxC1.Value.ToString());
		dqa.Dispose();

The error is:

Object reference not set to an instance of an object.

The error occurs when processing the custom action line. I can’t seem to figure out the simple process of executing a custom action for a BPM from code. I have gone through dozens of iterations that didn’t work (I won’t bore you with them here). I assume someone else must have done this once before.

Any ideas are welcome!
Thanks!
Nate

Is this a UBAQ the same UBAQ as the dashboard? That is is this a regular dashboard with a UBAQ and you want to invoke the custom action? Or is this baq completely loaded via code?

The BAQ is completely loaded by code. I am starting with a blank dashboard consisting of an empty tracker view. Then I load all the elements in customization. Like the textboxes, buttons, and the grid to display the results.

I wanna ask why but I’ll just refrain haha

The below method will execute a custom action on a DataView that is you will need a BAQDataView or a DataView which matches that which the BAQ Expects.

private void BAQRunCustomAction(EpiDataView iEdv, string iActionID)
{
    BAQDataView BAQView = (BAQDataView)iEdv;
    Assembly assembly = Assembly.LoadFrom("Ice.Lib.EpiClientLib.dll");
    Type t = assembly.GetType("Ice.Lib.Framework.BAQUpdater");
    BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
    MethodInfo mi = t.GetMethod("BAQRunCustomAction", bf);
    object[] param = new object[] { BAQView, iActionID};
    mi.Invoke("Ice.Lib.Framework.BAQUpdater", param);
}

After a second look, I guess I did use my UBAQ as the base for the dashboard.
I am only using Advanced BPM Update, not the standard BPM Update.

I plugged in the code you gave and got a few errors. I assume they are related to missing references.

As implemented in button2:

private void epiButtonC2_Click(object sender, System.EventArgs args)
	{
		// ** Place Event Handling Code Here **
		// Make sure New ID and Description text fields are populated
		if (String.IsNullOrEmpty(epiTextBoxC2.Text) == true)
		{
			 MessageBox.Show("Please enter a new Resource Group ID.");
			 return;
		}
		if (String.IsNullOrEmpty(epiTextBoxC3.Text) == true)
		{
			 MessageBox.Show("Please enter a new Resource Group Description.");
			 return;
		}
		// set callcontextbpmdata fields to textbox values
		EpiDataView edvCallContextBpmData = ((EpiDataView)(this.oTrans.EpiDataViews["CallContextBpmData"]));
		System.Data.DataRow edvCallContextBpmDataRow = edvCallContextBpmData.CurrentDataRow;
		edvCallContextBpmDataRow["ShortChar01"] = epiTextBoxC2.Text;
		edvCallContextBpmDataRow["Character01"] = epiTextBoxC3.Text;
		// Run custom code to change resource group ID for open jobs from old to new res grp id
		// Run custom code to update op description and res grp description to new description
                BAQRunCustomAction(edvCallContextBpmData, "ChangeResGrpID");
	}

Will not compile. Returns errors:

Error: CS0246 - line 110 (384) - The type or namespace name ‘Assembly’ could not be found (are you missing a using directive or an assembly reference?)
Error: CS0103 - line 110 (384) - The name ‘Assembly’ does not exist in the current context
Error: CS0246 - line 112 (386) - The type or namespace name ‘BindingFlags’ could not be found (are you missing a using directive or an assembly reference?)
Error: CS0103 - line 112 (386) - The name ‘BindingFlags’ does not exist in the current context
Error: CS0103 - line 112 (386) - The name ‘BindingFlags’ does not exist in the current context
Error: CS0103 - line 112 (386) - The name ‘BindingFlags’ does not exist in the current context
Error: CS0103 - line 112 (386) - The name ‘BindingFlags’ does not exist in the current context
Error: CS0246 - line 113 (387) - The type or namespace name ‘MethodInfo’ could not be found (are you missing a using directive or an assembly reference?)

add
using System.Reflection;

1 Like

Now you won’t be able to call with with BpmCallContext as the dataView. It needs a dataview which the BAQ expects. Though if you are using custom code only maybe it doesn’t matter.

Yes, I see I am using the wrong dataview. working out the syntax now. This seems to be going in the right direction!
Thanks!
Nate

1 Like

How do I grab the EpiDataView associated with my grid, epiUltraGridC1?

Should be one of the dataviews in your binding

var edv = oTrans.Factory("NameOfYourBindingDv");
1 Like

Yes! Yes! Yes!
Thank you! This is working great!
After all those iterations, this was all I needed! Yay!!!

var edv = oTrans.Factory("V_ChangeOpenJobResGrpIDs_1View");
BAQRunCustomAction(edv, "ChangeResGrpID");

Now on to make sure the CustomAction works! :slight_smile:

1 Like

I am back again. I am struggling with implementing my custom action. The custom action runs, but it seems like ttResults is empty when I run the custom action this way.

Is there a way to run the custom action on the ttResults just like it would in the BAQ view?

Check out where I am on this post for a bit more background: