EpiData Grid Conditional formatting - Help Needed

Preface

We have a customization on our Part tracker. This customization adds a separate tab to the main screen. This tab has an epidata grid on it that is populated by a baq in our system. The grid shows our milestones based on the jobs related to the selected part. The jobs are shown vertically with operations listed beneath. As operations are complete the operation will light up green.

What I Need

I was asked to change the color of the job column to yellow if there is a listed DMR against the job. What is the best way to accomplish this? I do not believe that I can create a column rule on the grid for a table that is not referenced.

Any and all help is greatly appreciated.

Good morning,
I followed the help file for Kinetic: Working With Rules. I was able to use a data rule to highlight a column in my custom grid. You need to make sure you reference the right dataview in the rule. It should be the same as the dataview used to populate the grid. I only just got this working once, so I am no pro. Post up what you have so far and I bet we can sort it out.
Good luck!
Nate

@NateS

Below is the code’s current state. All of this was built by someone back in 2016. The sections I am currently working on are highlighted by “//------------------------------------------Here”. I’ve been reading up on Infragistics and using the following two pages for most of my information.

https://www.infragistics.com/help/winforms/wingrid-changing-the-appearance-of-wingrid-columns

What we are trying to accomplish now is to only have the column header highlight yellow if the job has an open DMR against it instead of the whole column.

Currently, the code highlights everything except for the last item listed that should be highlighted. This is caused by the for loop in the second chunk of code I’ve been working on. The reason I use a for look for all columns listed here is that it’s the only way that I can get anything to highlight and not an error.

What I want is to replace the for loop with a single hit when the job number from the first dataset matches an entry in the second dataset.

Additionally, this customization only seems to work if you click the button its programed for twice. The first click will load the part as well as the do the initial highlight. The second click highlights the header section.

Thanks for taking a look at this. Let me know what questions you have.

extern alias Erp_Contracts_BO_NonConf;
extern alias Erp_Contracts_BO_SerialNo;


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;

//eb1:
using Infragistics.Win.UltraWinGrid;
using Infragistics.Win;

//baq:
using Ice.Core;
using Ice.Contracts;
using Epicor.ServiceModel.Channels;
using Ice.BO;
using Ice.Adapters;
//baq2:
//using System.Collections.Generic;
using System.Collections.Generic;


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 **

	//eb1:
	private EpiBaseAdapter oTrans_partAdapter;
	private EpiDataView edvPart;
	private Ice.Proxy.BO.DynamicQueryImpl dynamicQuery;
	private Session session;

	private DataTable dtResults;
	private DataTable dtResults2;
	private DataTable dtDisplay;
	private DataTable dtDisplay2;
	private DataView dvDisplay;	
	private DataView dvDisplay2;

	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

		//eb1:
		this.oTrans_partAdapter = ((EpiBaseAdapter)(this.csm.TransAdaptersHT["oTrans_partAdapter"]));
		this.oTrans_partAdapter.AfterAdapterMethod += new AfterAdapterMethod(this.oTrans_partAdapter_AfterAdapterMethod);
		this.edvPart = ((EpiDataView)(this.oTrans.EpiDataViews["Part"]));
		btnRetrieveLocations.Click += btnRetrieveLocations_Click;

		//baq:
		//Session session = (Session)this.oTrans.Session;
		session = (Session)this.oTrans.Session;
		dynamicQuery = WCFServiceSupport.CreateImpl<Ice.Proxy.BO.DynamicQueryImpl>(session, ImplBase<DynamicQuerySvcContract>.UriPath);

		dtResults = new DataTable();
		dtDisplay = new DataTable();
		dvDisplay = dtDisplay.DefaultView;
		dtResults2 = new DataTable();
		dtDisplay2 = new DataTable();

		this.PartTrackerForm.AfterToolClick += new Ice.Lib.Framework.AfterToolClickEventHandler(this.PartTrackerForm_AfterToolClick);
		this.eugLocations.Paint += eugLocations_AfterPaint;
	}

	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

		//eb1:
		this.oTrans_partAdapter.AfterAdapterMethod -= new AfterAdapterMethod(this.oTrans_partAdapter_AfterAdapterMethod);
		this.oTrans_partAdapter = null;
		this.edvPart = null;
		btnRetrieveLocations.Click -= btnRetrieveLocations_Click;

		dtResults = null;
		dtDisplay = null;
		dtResults2 = null;
		dtDisplay2 = null;
		dvDisplay = null;
		this.PartTrackerForm.AfterToolClick -= new Ice.Lib.Framework.AfterToolClickEventHandler(this.PartTrackerForm_AfterToolClick);
		this.eugLocations.Paint -= eugLocations_AfterPaint;

	}

	private void eugLocations_AfterPaint(object sender, PaintEventArgs e)
	{
		//when: form loads, jump to that tab, hit retrieve button (twice), mouse over, clear button, 
		//MessageBox.Show("dg paint");

		//FMSColors();
	}
	

	private void oTrans_partAdapter_AfterAdapterMethod(object sender, AfterAdapterMethodArgs args)
	{
		// ** Argument Properties and Uses **
		// ** args.MethodName **
		// ** Add Event Handler Code **

		// ** Use MessageBox to find adapter method name
		//MessageBox.Show(args.MethodName);

		switch (args.MethodName)
		{
			case "GetByID":
				// Happens when find/enter a part, or select from the drop down list up top
				DataRow partRow = edvPart.dataView[edvPart.dataView.Count - 1].Row;
				//MessageBox.Show(partRow["PartNum"].ToString());

				ClearPartLocations();

				break;
		}

	}

	private void ClearPartLocations()
	{
		dtResults.Clear();
		dtDisplay.Clear();
		dtResults2.Clear();
		dtDisplay2.Clear();
	}



	private void btnRetrieveLocations_Click(object sender, System.EventArgs args)
	{
		if(edvPart.dataView.Count == 0)
		{
			return;
		}

		ClearPartLocations();

		DataRow partRow = edvPart.dataView[edvPart.dataView.Count - 1].Row;
		//MessageBox.Show(partRow["PartNum"].ToString());
		string currentPartNum = (string)partRow["PartNum"];

		DynamicQueryDataSet ds = dynamicQuery.GetByID("_PartTracker");
		QueryExecutionDataSet execDS = new QueryExecutionDataSet();
		execDS.ExecutionParameter.AddExecutionParameterRow("PartNum", currentPartNum, "nvarchar", false, Guid.NewGuid(), "");
		execDS.AcceptChanges();
		dtResults.Clear();
		dtResults = dynamicQuery.Execute(ds, execDS).Tables["Results"];
//------------------------------------------Here
		DynamicQueryDataSet ds2 = dynamicQuery.GetByID("_DMRTracker");
		QueryExecutionDataSet execDS2 = new QueryExecutionDataSet();
		execDS2.ExecutionParameter.AddExecutionParameterRow("PartNum", currentPartNum, "nvarchar", false, Guid.NewGuid(), "");
		execDS2.AcceptChanges();
		dtResults2.Clear();
		dtResults2 = dynamicQuery.Execute(ds2, execDS2).Tables["Results"];
//-----------------------------------------------
		//DataTable dtDisplay = new DataTable();
		//dtDisplay.Clear();
		/*
		dtDisplay.PrimaryKey = null;
		for( int index=dtDisplay.Columns.Count-1; index>=0; index-- )
	    {
	        dtDisplay.Columns.RemoveAt( index );
	    }
		*/

		if(dtDisplay.Columns.Count == 0)
		{
			DataColumn colOprSeqKey = new DataColumn("OprSeqKey", typeof(string));
			colOprSeqKey.ReadOnly = true;
			dtDisplay.Columns.Add(colOprSeqKey);
			dtDisplay.Columns["OprSeqKey"].ColumnMapping = MappingType.Hidden;
			DataColumn[] key1 = new DataColumn[1];
			key1[0] = colOprSeqKey;
			dtDisplay.PrimaryKey = key1;
	
			DataColumn colOprSeq = new DataColumn("OprSeq", typeof(int));
			colOprSeq.ReadOnly = true;
			colOprSeq.Caption = "Opr";
			dtDisplay.Columns.Add(colOprSeq);
	
			DataColumn colOperation = new DataColumn("OpDesc", typeof(string));
			colOperation.ReadOnly = true;
			colOperation.Caption = "Operation";
			dtDisplay.Columns.Add(colOperation);
		}
		else
		{
			// Remove old columns pertaining to jobs, keeping the 3 main columns
			for( int index=dtDisplay.Columns.Count-1; index>=0; index-- )
		    {
				switch(dtDisplay.Columns[index].ColumnName)
				{
					case "OprSeqKey":
					case "OprSeq":
					case "OpDesc":
					{
						break;
					}
					default:
					{
						dtDisplay.Columns.RemoveAt( index );
						break;
					}

				}
		    }

		}
		int color = 0;
		string strLastJob = "";
		string strLastJob2 = "";
		Dictionary<string, int> dictJobLastSeq = new Dictionary<string, int>();
		foreach(DataRow row in dtResults.Rows)
		{
			//MessageBox.Show((string)row["PartDtl.PONum"].ToString());

			string strCurrentJob = (string)row["JobHead_JobNum"];

			if(strLastJob != strCurrentJob)
			{
				// Add a column for the job
				//eb2:
				//DataColumn colJobNum = new DataColumn(strCurrentJob, typeof(DateTime));
				DataColumn colJobNum = new DataColumn(strCurrentJob, typeof(string));
//------------------------------------------Here
 
				foreach(DataRow row2 in dtResults2.Rows)
				{							
					string strCurrentJob2 = (string)row2["DMRHead_JobNum"];
					if(strCurrentJob2 != strCurrentJob)
					{	 
					    // One way to allow the column headers to show custom colors is to disallow the grid  
					    // to use XP themes at all.  
					    //  
					    this.eugLocations.SupportThemes = false;   
					      
					    //  
					    // A more surgical approach would be to allow the grid to support XP themes, but to   
					    // disable themes just for the column headers.  
					    //  
					    this.eugLocations.SupportThemes = true;  
					    
						foreach( UltraGridColumn col in this.eugLocations.DisplayLayout.Bands[0].Columns )  
					    {  
					        // Here we "turn off" theming for the column header.  
					        col.Header.Appearance.ThemedElementAlpha = Infragistics.Win.Alpha.Transparent;   
					      
					        col.Header.Appearance.BackColor = System.Drawing.Color.Yellow;  
					        col.Header.Appearance.BackColorDisabled = System.Drawing.Color.Yellow;  
 						   col.Header.Appearance.ForeColor = System.Drawing.Color.Black;
					    }   
					
						strLastJob2 = strCurrentJob2;


					}
				}	

//-----------------------------------------------
				//colJobNum.ReadOnly = true;
				dtDisplay.Columns.Add(colJobNum);

				strLastJob = strCurrentJob;
			}

			//if(!dictJobLastSeq.ContainsKey(strCurrentJob))
			if(    !dictJobLastSeq.ContainsKey(strCurrentJob)
				&& IsInteger(row["Calculated_LastOprSeq"].ToString())	)
			{
				// Add to dictionary containing each job and it's last completed oprseq
				dictJobLastSeq.Add(strCurrentJob, (int)row["Calculated_LastOprSeq"]);
			}

			string[] strMatchKey = new string[1];
			strMatchKey[0] = ((int)row["JobOper_OprSeq"]).ToString();
			DataRow foundRow = dtDisplay.Rows.Find(strMatchKey);
			if (foundRow == null)
			{
				// Add a row for the operation
				DataRow rowNewRow;
		        rowNewRow = dtDisplay.NewRow();
		        rowNewRow["OprSeqKey"] = ((int)row["JobOper_OprSeq"]).ToString();
		        rowNewRow["OprSeq"] = (int)row["JobOper_OprSeq"];
		        rowNewRow["OpDesc"] = (string)row["OpMaster_OpDesc"];
		        dtDisplay.Rows.Add(rowNewRow);
			}
			foundRow = dtDisplay.Rows.Find(strMatchKey);
			if (foundRow != null)
			{
				// Update the row cell for the operation
				if(!(row["JobOper_DueDate"] is DBNull) )
				{
					//eb2:
					//foundRow[strCurrentJob] = (DateTime)row["JobOper_DueDate"];
					foundRow[strCurrentJob] = String.Format("{0:M/d/yyyy}", (DateTime)row["JobOper_DueDate"]);
				}
				if(!(row["JobOper_LastLaborDate"] is DBNull) )
				{
					//eb2:
					//foundRow[strCurrentJob] = (DateTime)row["JobOper_LastLaborDate"];
					foundRow[strCurrentJob] = String.Format("{0:M/d/yyyy}", (DateTime)row["JobOper_LastLaborDate"]);
				}
			}

			//eb2:
			strMatchKey[0] = "Job Qty";
			foundRow = dtDisplay.Rows.Find(strMatchKey);
			if (foundRow == null)
			{
				// Add a row for Job Quantity
				DataRow rowNewRow;
		        rowNewRow = dtDisplay.NewRow();
		        rowNewRow["OprSeqKey"] = "Job Qty";
		        rowNewRow["OprSeq"] = 0;
		        rowNewRow["OpDesc"] = "Job Qty";
		        dtDisplay.Rows.Add(rowNewRow);
			}
			foundRow = dtDisplay.Rows.Find(strMatchKey);
			if (foundRow != null)
			{
				// Update the row cell for the Job Quantity
				foundRow[strCurrentJob] = (String.Format("{0:0.##}", (Decimal)row["JobHead_ProdQty"])).ToString();
			}

		}
		
		// Make all data read only (can't do so when create columns, because then can't populate them)
		foreach(DataColumn column in dtDisplay.Columns)
		{
			column.ReadOnly = true;
		}

		//eugLocations.DataSource = dtDisplay;
		//DataView dvDisplay = dtDisplay.DefaultView;
		dvDisplay.Sort = "OprSeq";
		//dvDisplay.ReadOnly = true;
		eugLocations.DataSource = dvDisplay;

		eugLocations.DisplayLayout.UseFixedHeaders = true;
		eugLocations.DisplayLayout.Bands[0].Columns["OprSeq"].Header.Fixed = true;
		eugLocations.DisplayLayout.Bands[0].Columns["OpDesc"].Header.Fixed = true;

		eugLocations.DisplayLayout.Override.FixedRowStyle = FixedRowStyle.Top;
		eugLocations.Rows[0].Fixed = true;

		/*
		//foreach(Infragistics.Win.UltraWinGrid.UltraGridColumn ugr in eugLocations.Columns)
		foreach(Infragistics.Win.UltraWinGrid.UltraGridColumn ugc in eugLocations.DisplayLayout.Bands[0].Columns)
		{
			//eugLocations.DisplayLayout.Bands[0].Columns[i].
			//ugc.Rows[0].Appearance.BackColor = System.Drawing.Color.LightGreen;
		}
		*/

		foreach(Infragistics.Win.UltraWinGrid.UltraGridRow ugr in eugLocations.Rows)
		{
			foreach(Infragistics.Win.UltraWinGrid.UltraGridCell ugc in ugr.Cells)
			{
				string gridColumnName = ugc.Column.ToString();
				if(dictJobLastSeq.ContainsKey(gridColumnName))
				{
					if((int)ugr.Cells["OprSeq"].Value <= dictJobLastSeq[gridColumnName])
					{
							ugc.Appearance.BackColor = System.Drawing.Color.LightGreen;				
					}
				}
			}
		}


	}

	public static bool IsInteger(string theValue)
	{
		try
		{
			Convert.ToInt32(theValue);
			return true;
		}
		catch
		{
			return false;
		}
	}



	private void PartTrackerForm_AfterToolClick(object sender, Ice.Lib.Framework.AfterToolClickEventArgs args)
	{
		//MessageBox.Show(args.Tool.Key);
		switch (args.Tool.Key)
		{
			case "ClearTool":
				ClearPartLocations();
				break;
		}

	}


	private void PartTrackerForm_Load(object sender, EventArgs args)
	{
		// Add Event Handler Code
		EpiBasePanel detailPanel1;
		detailPanel1 = (EpiBasePanel)csm.GetNativeControlReference("9eb86014-e17c-405d-9ea4-6fce29dab421");
		detailPanel1.Focus();
	}
}

I see. I thought you were trying to do this in Kinetic. The code you posted is a bit more than I can debug myself. If your approach was strictly in a Kinetic form, then this might be a little easier using the data rules.

1 Like

Nate,

Any chance you know how to add a new row to an epigrid that doesn’t have a data value?

Not really. :\ If the epigrid is bound to a dataview, then you might be able to add a new row with GetNew, or a similar method. I think there are others on here that may be better able to answer this one.

Currently, I have changed the way we are going a little bit. I am now trying to highlight the column headers based on whether or not there is a DMR against the job listed in a second BAQ dataset I’m looking against. This is a snapshot of the functionality I’m seeing currently:

The issue with what is shown above is that some columns that shouldn’t be highlighted are. In this instance, both the Opr and Operation columns are highlighted when they shouldn’t be. Below is the current version of the chunk of code causing the color.

			this.eugLocations.SupportThemes = true;  
		    foreach( UltraGridColumn col in this.eugLocations.DisplayLayout.Bands[0].Columns )  
    		   {  						
				foreach(DataRow row2 in dtResults2.Rows)
				{	
					string strCurrentJob2 = (string)row2["DMRHead_JobNum"];
					if(strCurrentJob2 == strCurrentJob)
					{
 						   eugLocations.BeginUpdate(); 
						eugLocations.SuspendRowSynchronization();
						col.Header.Appearance.ThemedElementAlpha = Infragistics.Win.Alpha.Transparent;   
				        col.Header.Appearance.BackColor = System.Drawing.Color.Yellow;  
						col.Header.Appearance.ForeColor = System.Drawing.Color.Black;
				        col.Header.Appearance.BackColorDisabled = System.Drawing.Color.Orange; 
						eugLocations.ResumeRowSynchronization();
						eugLocations.EndUpdate();  		       											
						break;
					}
				}
			}

I believe that the " foreach( UltraGridColumn col in this.eugLocations.DisplayLayout.Bands[0].Columns )" line of code is what is causing both of them to be highlighted. Is there a better way to highlight each column header independently instead of saying for each column?

Below are some links to where I got my bits of code from:

https://www.infragistics.com/help/winforms/wingrid-changing-the-appearance-of-wingrid-columns

https://www.infragistics.com/help/winforms/wingrid-changing-the-appearance-of-wingrid-bands

@hasokeric @josecgomez ,

Hate to bother you guys, but do either of you know how to do this?