PlexityHide.GTP

Looking to customize the resource scheduling board. I have looked around and was wondering if someone can point me to location of the method and properties i can use to add columns to the list view and add more information to the chart. Unless Epicor has made it nicer in the new UI

Thanks.

1 Like

Also looking.

This is really old snippet but here’s something that might be useful

using PlexityHide.GTP;
 
public static class PlexityGridController {
    public static void ViewGrid(Grid grid) {
        List<string> columns = new List<string>();
        foreach (GridColumn column in grid.Columns) {
            columns.Add(column.Title);
        }
        //Debug("columns({0}): {1}", columns.Count, String.Join(", ", columns.ToArray()));
        List<string> nodes = new List<string>();
        foreach (GridNode node in grid.RootNodes) {
            nodes.Add(ReadAllCells(node));
        }
        //Debug("nodes({0}): {1}", nodes.Count, String.Join(", ", nodes.ToArray()));
    }
     
    public static int IndexOf(GridColumns columns, string title) {
        foreach (GridColumn column in columns) {
            if (column.Title == title) {
                return column.Index;
            }
        }
        return -1;
    }
 
    public static GridColumn AddColumn(Grid grid, CellType type, string title) {
        GridStructure structure = new GridStructure(grid);
        GridColumn column = new GridColumn(type, structure);
        column.Title = title;
        grid.Columns.Add(column);
        return column;
    }
 
    public static void MoveColumn(Grid grid, GridColumn moveable, int moveTo) {
        List<gridcolumn> columns = new List<gridcolumn>();
        for (int index = 0; index < grid.Columns.Count; index++) {
            GridColumn column = grid.Columns[index];
            if (index == moveTo) {
                columns.Add(moveable);
            }
            if (column.Title == moveable.Title) {
                continue;
            }
            columns.Add(column);
        }
        grid.Columns.Clear();
        foreach (GridColumn column in columns) {
            grid.Columns.Add(column);
        }
    }
 
    public static Cell GetCellByColumnTitle(GridNode node, string title) {
        for (int index = 0; index < node.GridControl.Columns.Count; index++) {
            Cell cell = node.GetCell(index);
            if (cell.Column.Title == title) {
                return cell;
            }
        }
        return null;
    }
     
    public static void SetCellValue(Cell cell, object @value) {
        cell.Content.Value = @value;
    }
     
    private static string ReadAllCells(GridNode node) {
        List<string> cells = new List<string>();
        int index = 0;
        bool hasMore = true;
        while (hasMore) {
            if (index > node.GridControl.Columns.Count) {
                break;
            }
            try {
                Cell cell = node.GetCell(index);
                index = index + 1;
                if (cell == null) {
                    continue;
                }
                ContentEntity content = cell.Content;
                if (content == null) {
                    continue;
                }
                object val = content.Value;
                if (val == null) {
                    continue;
                }
                cells.Add(val.ToString());
            } catch (Exception e) {
                hasMore = false;
            }
        }
        return String.Join(", ", cells.ToArray());
    }
}

Here’s how to modify the Plexity ToolTip

//Gist File: scheduling_board.cs
 
private static PlexityHide.GTP.Gantt gntJobs;
private static PlexityHide.GTP.TimeAreaOffscreenDraw gntTimeArea;
private static PlexityHide.GTP.GridNode currentNode;
private DynamicQueryAdapter dqa;
QueryExecutionDataSet qeds;
 
InitCustomCode()
{
  //Get a hold of the grid
  gntJobs = (PlexityHide.GTP.Gantt)csm.GetNativeControlReference("listPanel1.gntJobs");
   
  //Use our Event Helper Class (other gist) to remove the Epicor Native ToolTip
  cEventHelper.RemoveEventHandler(gntJobs, "OnTimeItem_Hoover");
  //Register the Hoover Event
  gntJobs.OnTimeItem_Hoover += new PlexityHide.GTP.TimeItemEvent(this.gntJobs_OnTimeItem_Hoover);
}
 
private void gntJobs_OnTimeItem_Hoover(Gantt aGantt, TimeItemEventArgs e)
{
        Erp.UI.App.MultiResourceSchedulingBoard.ListPanel lp= (Erp.UI.App.MultiResourceSchedulingBoard.ListPanel)csm.GetNativeControlReference("2a0f08ca-a115-4547-999a-e658594fa6b5");
 
        string jobNum="";
        StringBuilder sb = new StringBuilder();
        try
        {
            if (e.TimeItem != null)
            {
                Epicor.Mfg.Lib.Scheduling.taskData td =(Epicor.Mfg.Lib.Scheduling.taskData)e.TimeItem.UserReference;
                qeds.ExecutionParameter.Clear();
                qeds.ExecutionParameter.AddExecutionParameterRow("JobNum", td.JobNum , "nvarchar",false, Guid.NewGuid(),"A");
                qeds.ExecutionParameter.AddExecutionParameterRow("Assy", td.AsmNum.ToString() , "int",false, Guid.NewGuid(),"A");
                dqa.ExecuteByID("SchedBoardToolTip",qeds);
                sb.AppendLine("JobNum: " + td.JobNum);
                sb.AppendLine("Assembly: " + td.AsmNum + " - " + dqa.QueryResults.Tables["Results"].Rows[0]["JobAsmbl_Description"]);
                sb.AppendLine("Order: " +dqa.QueryResults.Tables["Results"].Rows[0]["JobProd_OrderNum"]);
                sb.AppendLine("Customer: " +dqa.QueryResults.Tables["Results"].Rows[0]["Customer_CustID"] + " - " + dqa.QueryResults.Tables["Results"].Rows[0]["Customer_Name"]);
            }
            lp.setGanttToolTip(sb.ToString());
        }
        catch(Exception ex)
        {
        }
}
2 Likes

That is super helpful. I scanned through that - does the bar text get updated with the ToolTip or is that just a tooltip that appears when hovering? My main goal is to update the text on the “TimeItems” I think is what they are called. By default, it shows me a job # and something in parenthesis.

I honestly don’t remember Dan this was a code snippet from 2020 that I had laying around.

No worries. I’ll plug it in and see what happens. Thank you so much!!

No worries come back and update us, I know I did successfully add columns and changed tool tips etc but it was so long ago.

Almost there. I think there must be a helper file referenced… is there something you can share from that to help this thing compile?


image

Ah that’s another code snippet I’ll find it for you, here you go. Again Really old code snips so use at your own risk

//Gist File: events_remove.cs
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
 
//Useage
//cEventHandler.RemoveAllEventHandlers(naughty_object);
//cEventHelper.RemoveEventHandler(naughty_object, "SomeEvent");
 
static public class cEventHelper
{
    static Dictionary<type, list<fieldinfo="">> dicEventFieldInfos = new Dictionary<type, list<fieldinfo="">>();
 
    static BindingFlags AllBindings
    {
      get { return BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; }
    }
 
    //--------------------------------------------------------------------------------
    static List<fieldinfo> GetTypeEventFields(Type t)
    {
      if (dicEventFieldInfos.ContainsKey(t))
        return dicEventFieldInfos[t];
 
      List<fieldinfo> lst = new List<fieldinfo>();
      BuildEventFields(t, lst);
      dicEventFieldInfos.Add(t, lst);
      return lst;
    }
 
    //--------------------------------------------------------------------------------
    static void BuildEventFields(Type t, List<fieldinfo> lst)
    {
      // Type.GetEvent(s) gets all Events for the type AND it's ancestors
      // Type.GetField(s) gets only Fields for the exact type.
      //  (BindingFlags.FlattenHierarchy only works on PROTECTED & PUBLIC
      //   doesn't work because Fieds are PRIVATE)
 
      // NEW version of this routine uses .GetEvents and then uses .DeclaringType
      // to get the correct ancestor type so that we can get the FieldInfo.
      foreach (EventInfo ei in t.GetEvents(AllBindings))
      {
        Type dt = ei.DeclaringType;
        FieldInfo fi = dt.GetField(ei.Name, AllBindings);
        if (fi != null)
          lst.Add(fi);
      }
 
      // OLD version of the code - called itself recursively to get all fields
      // for 't' and ancestors and then tested each one to see if it's an EVENT
      // Much less efficient than the new code
/*
      foreach (FieldInfo fi in t.GetFields(AllBindings))
      {
        EventInfo ei = t.GetEvent(fi.Name, AllBindings);
        if (ei != null)
        {
          lst.Add(fi);
          Console.WriteLine(ei.Name);
        }
      }
      if (t.BaseType != null)
        BuildEventFields(t.BaseType, lst);*/
    }
 
    //--------------------------------------------------------------------------------
    static EventHandlerList GetStaticEventHandlerList(Type t, object obj)
    {
      MethodInfo mi = t.GetMethod("get_Events", AllBindings);
      return (EventHandlerList)mi.Invoke(obj, new object[] { });
    }
 
    //--------------------------------------------------------------------------------
    public static void RemoveAllEventHandlers(object obj) { RemoveEventHandler(obj, ""); }
 
    //--------------------------------------------------------------------------------
    public static void RemoveEventHandler(object obj, string EventName)
    {
      if (obj == null)
        return;
 
      Type t = obj.GetType();
      List<fieldinfo> event_fields = GetTypeEventFields(t);
      EventHandlerList static_event_handlers = null;
 
      foreach (FieldInfo fi in event_fields)
      {
        if (EventName != "" && string.Compare(EventName, fi.Name, true) != 0)
          continue;
 
        // After hours and hours of research and trial and error, it turns out that
        // STATIC Events have to be treated differently from INSTANCE Events...
        if (fi.IsStatic)
        {
          // STATIC EVENT
          if (static_event_handlers == null)
            static_event_handlers = GetStaticEventHandlerList(t, obj);
 
          object idx = fi.GetValue(obj);
          Delegate eh = static_event_handlers[idx];
          if (eh == null)
            continue;
 
          Delegate[] dels = eh.GetInvocationList();
          if (dels == null)
            continue;
 
          EventInfo ei = t.GetEvent(fi.Name, AllBindings);
          foreach (Delegate del in dels)
            ei.RemoveEventHandler(obj, del);
        }
        else
        {
          // INSTANCE EVENT
          EventInfo ei = t.GetEvent(fi.Name, AllBindings);
          if (ei != null)
          {
            object val = fi.GetValue(obj);
            Delegate mdel = (val as Delegate);
            if (mdel != null)
            {
              foreach (Delegate del in mdel.GetInvocationList())
                ei.RemoveEventHandler(obj, del);
            }
          }
        }
      }
    }
}
//Gist File: removeValidatingEvent.cs
 
//This will remove the initial event when you type a JobNum in JobEntry -JG From Frazier customization
 
Type type = etb.GetType();
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
 
var eventInfo = type.GetEvent("Validating", bindingFlags);
Type tHandler = eventInfo.EventHandlerType;
 
Erp.UI.App.JobEntry.JobHeadDetailPanel jd = csm.GetNativeControlReference("d08296b1-a700-4a45-aa1a-475309696931") as Erp.UI.App.JobEntry.JobHeadDetailPanel;
MethodInfo mi = jd.GetType().GetMethod("txtKeyField_Validating",BindingFlags.NonPublic | BindingFlags.Instance);
Delegate del = Delegate.CreateDelegate(tHandler, jd, mi);
 
// detach the event handler
if (del != null)
  eventInfo.RemoveEventHandler(etb, del);
1 Like

Sorry - still not quite there. Now I’m getting this error and I feel like it’s a silly one that I should be able to figure out but after about 20 minutes now, I’m not finding it. Any help for this?

image

Its FieldInfo (cammel case) from System.Reflection.

1 Like
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

// Usage:
// cEventHelper.RemoveAllEventHandlers(naughty_object);
// cEventHelper.RemoveEventHandler(naughty_object, "SomeEvent");

static public class cEventHelper
{
    static Dictionary<Type, List<FieldInfo>> dicEventFieldInfos = new Dictionary<Type, List<FieldInfo>>();

    static BindingFlags AllBindings
    {
        get { return BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; }
    }

    //--------------------------------------------------------------------------------
    static List<FieldInfo> GetTypeEventFields(Type t)
    {
        if (dicEventFieldInfos.ContainsKey(t))
            return dicEventFieldInfos[t];

        List<FieldInfo> lst = new List<FieldInfo>();
        BuildEventFields(t, lst);
        dicEventFieldInfos.Add(t, lst);
        return lst;
    }

    //--------------------------------------------------------------------------------
    static void BuildEventFields(Type t, List<FieldInfo> lst)
    {
        foreach (EventInfo ei in t.GetEvents(AllBindings))
        {
            Type dt = ei.DeclaringType;
            FieldInfo fi = dt.GetField(ei.Name, AllBindings);
            if (fi != null)
                lst.Add(fi);
        }
    }

    //--------------------------------------------------------------------------------
    static EventHandlerList GetStaticEventHandlerList(Type t, object obj)
    {
        MethodInfo mi = t.GetMethod("get_Events", AllBindings);
        return (EventHandlerList)mi.Invoke(obj, new object[] { });
    }

    //--------------------------------------------------------------------------------
    public static void RemoveAllEventHandlers(object obj) { RemoveEventHandler(obj, ""); }

    //--------------------------------------------------------------------------------
    public static void RemoveEventHandler(object obj, string EventName)
    {
        if (obj == null)
            return;

        Type t = obj.GetType();
        List<FieldInfo> event_fields = GetTypeEventFields(t);
        EventHandlerList static_event_handlers = null;

        foreach (FieldInfo fi in event_fields)
        {
            if (EventName != "" && string.Compare(EventName, fi.Name, true) != 0)
                continue;

            if (fi.IsStatic)
            {
                if (static_event_handlers == null)
                    static_event_handlers = GetStaticEventHandlerList(t, obj);

                object idx = fi.GetValue(obj);
                Delegate eh = static_event_handlers[idx];
                if (eh == null)
                    continue;

                Delegate[] dels = eh.GetInvocationList();
                if (dels == null)
                    continue;

                EventInfo ei = t.GetEvent(fi.Name, AllBindings);
                foreach (Delegate del in dels)
                    ei.RemoveEventHandler(obj, del);
            }
            else
            {
                EventInfo ei = t.GetEvent(fi.Name, AllBindings);
                if (ei != null)
                {
                    object val = fi.GetValue(obj);
                    Delegate mdel = val as Delegate;
                    if (mdel != null)
                    {
                        foreach (Delegate del in mdel.GetInvocationList())
                            ei.RemoveEventHandler(obj, del);
                    }
                }
            }
        }
    }
}

Thank you @josecgomez and @klincecum. I’m not all the way there yet but I am past the silly errors. The camel case thing has gotten me before. You’d think I’d learn.

Now I have to figure out how to make it work. I see no difference in my Multi Resource Scheduling Board.

2 Likes