Unscheduled Jobs Grid Custom View

How to create a custom Jobs Grid view using a MyViews customization point

This guide will step through the process of coding a MyViews customization. If you are just getting started, please first see getting started with customizations and the  customization point basics


Unscheduled Jobs Grid Example

    In this example, we are creating a custom control that loads unscheduled jobs onto a grid and allows the user to schedule any or all of those jobs (if possible) by clicking on a button to peform an ASAP expedite, or a separate button to perform an expedite past the frozen span.

    The following block of code gives a closer look at how the PTMyViews class can be used to build the Unscheduled Jobs Grid project:

    private UserControl m_userControl = new UserControl();
     
    /// <summary>
    /// Override this function to return custom control
    /// </summary>
    /// <returns></returns>
    public override UserControl GetUserControl()
    {
    return m_control;
    }

    /// <summary>
    /// Override Init function to initialize custom control and subscribe to events needed to update the control
    /// </summary>
    /// <param name="a_sd"></param>
    /// <param name="a_eventListener"></param>
    /// <param name="a_currentUser"></param>
    public override void Init(ScenarioDetail a_sd, UICustomizationsLink a_eventListener, User a_currentUser)
    {
    m_control.Initialize(a_sd);

    //Update control when these event are fired
    a_eventListener.ScheduleEventsList.ScenarioOpened += ScheduleEventsList_ScenarioOpened;
    a_eventListener.ScheduleEventsList.ScheduleChanged += ScheduleEventsList_ScheduleChanged;

    //Subscribe to custom control TransmissionFired event to know when we need to fire the MyViewTransmissionFiredEvent
    //so the transmission can be processed
    m_control.TransmissionFired += Control_TransmissionFired;
    }

    /// <summary>
    /// Custom control TranmissionFired event handler
    /// </summary>
    /// <param name="a_t"></param>
    /// <param name="a_sequenced"></param>
    private void Control_TransmissionFired(PTTransmission a_t, bool a_sequenced)
    {
    MyViewTransmissionFiredEvent?.Invoke(a_t, a_sequenced);
    }

    /// <summary>
    /// Schedule Changed event handler
    /// </summary>
    /// <param name="a_sd"></param>
    private void ScheduleEventsList_ScheduleChanged(ScenarioDetail a_sd)
    {
    m_control.Initialize(a_sd);
    }

    /// <summary>
    /// Scenario Opened event handler
    /// </summary>
    /// <param name="a_scenarioid"></param>
    private void ScheduleEventsList_ScenarioOpened(BaseId a_scenarioid)
    {
    m_control.SetScenarioId(a_scenarioid);
    }

    Note that the Init function can be used to subscribe to both scheduler events and custom events from the custom control. The scheduler event handlers give the ability to update information on the custom control, whereas the event handler for the custom event enables us to fire a transmission that will attempt to update the scheduler data.

     

    This next block of code is an example of how to build and populate a custom grid control with job data. Button click handlers are used to collect the data and perform an action with it:

    private DataTable m_table;
    private readonly Dictionary<int, BaseId> m_rowIdxToJobKeyDictionary = new Dictionary<int, BaseId>();
    private DataSet m_dataSet;
    private BaseId m_scenarioId;

    /// <summary>
    /// Event to fire to let UI know to send transmission
    /// </summary>
    public event Action<PTTransmission, bool> TransmissionFired;

    public TestControl()
    {
    InitializeComponent();
    CreateDataSet();
    }

    /// <summary>
    /// Create DataSet to bind to GridView
    /// </summary>
    public void CreateDataSet()
    {
    m_table = new DataTable();
    m_dataSet = new DataSet { DataSetName = "UnscheduledJobs" };

    m_table.Columns.Add("Name", typeof(string));
    m_table.Columns.Add("Id", typeof(BaseId));
    m_table.Columns.Add("Need Date", typeof(DateTime));
    m_table.Columns.Add("External Id", typeof(string));
    m_table.Columns.Add("Product", typeof(string));

    m_dataSet.Tables.AddRange(new[] { m_table });

    //Create a DataView from the table and bind it to the Grid
    gridControl1.DataSource = m_dataSet;
    gridControl1.DataMember = m_table.TableName;
    }

    /// <summary>
    /// Initialize Scenario ID and load data on control
    /// </summary>
    /// <param name="a_sd"></param>
    public void Initialize(ScenarioDetail a_sd)
    {
    m_scenarioId = a_sd.Scenario.Id;
    LoadGrid(a_sd);
    }

    /// <summary>
    /// Update Scenario ID
    /// </summary>
    /// <param name="a_scenarioId"></param>
    public void SetScenarioId(BaseId a_scenarioId)
    {
    m_scenarioId = a_scenarioId;
    }

    /// <summary>
    /// Populate Grid
    /// </summary>
    /// <param name="a_sd"></param>
    public void LoadGrid(ScenarioDetail a_sd)
    {
    m_table.Clear();
    m_rowIdxToJobKeyDictionary.Clear();

    foreach (Job job in a_sd.JobManager)
    {
    if (job.ScheduledStatus == JobDefs.scheduledStatuses.Unscheduled || job.ScheduledStatus == JobDefs.scheduledStatuses.New)
    {
    m_rowIdxToJobKeyDictionary.Add(m_table.Rows.Count, job.Id);
    DataRow newRow = m_table.NewRow();

    newRow["Name"] = job.Name;
    newRow["Id"] = job.Id;
    newRow["Need Date"] = job.NeedDateTime;
    newRow["External Id"] = job.ExternalId;
    newRow["Product"] = job.Product;

    m_table.Rows.Add(newRow);
    }
    }

    simpleButton_Asap.Enabled = simpleButton_PFS.Enabled = m_table.Rows.Count > 0;
    }

    /// <summary>
    /// ASAP button click event handler
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void simpleButton_Asap_Click(object sender, EventArgs e)
    {
    JobKeyList jobKeyList = GetJobKeyList();
    ExpediteJobsHelper(jobKeyList, EJobExpediteType.ASAP);
    }

    /// <summary>
    /// PFS button click event handler
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void simpleButton_PFS_Click(object sender, EventArgs e)
    {
    JobKeyList jobKeyList = GetJobKeyList();
    ExpediteJobsHelper(jobKeyList, EJobExpediteType.PreserveFrozenSpan);
    }

    /// <summary>
    /// Get JobKeyList collection from selected rows
    /// </summary>
    /// <returns></returns>
    private JobKeyList GetJobKeyList()
    {
    int[] rowIds = gridView1.GetSelectedRows();
    List<int> rowHandles = new List<int>();
    foreach (int selectedRow in rowIds)
    {
    int dataSourceIndex = gridView1.ViewRowHandleToDataSourceIndex(selectedRow);
    rowHandles.Add(dataSourceIndex);
    }

    JobKeyList jobIds = new JobKeyList();
    foreach (int rowHandle in rowHandles)
    {
    if (m_rowIdxToJobKeyDictionary.TryGetValue(rowHandle, out BaseId jobId))
    {
    jobIds.Add(jobId);
    }
    }

    return jobIds;
    }

    /// <summary>
    /// Expedite jobs helper function
    /// </summary>
    /// <param name="a_jobs"></param>
    /// <param name="a_jobExpediteType"></param>
    private void ExpediteJobsHelper(JobKeyList a_jobs, EJobExpediteType a_jobExpediteType)
    {
    try
    {
    using (SystemController.Sys.ScenariosLock.TryEnterRead(out ScenarioManager sm, 1000))
    {
    Scenario s = sm.Find(m_scenarioId);

    using (s.ScenarioDetailLock.TryEnterRead(out ScenarioDetail sd, 1000))
    {
    ScenarioDetailExpediteBaseT.ExpediteStartDateType expediteStartType = ScenarioDetailExpediteBaseT.ExpediteStartDateType.Clock;
    DateTime expediteTimeInServerTime = PTDateTime.MinDateTime;

    switch (a_jobExpediteType)
    {
    case EJobExpediteType.ASAP:
    expediteStartType = ScenarioDetailExpediteBaseT.ExpediteStartDateType.Clock;
    break;
    case EJobExpediteType.PreserveFrozenSpan:
    expediteStartType = ScenarioDetailExpediteBaseT.ExpediteStartDateType.EndOfFrozenSpan;
    break;
    }

    //Get list of all Preds and Material supplying MOs.
    MOKeyList mosToExpedite = GetMoListWithSupplyMosAdded(sd.JobManager, a_jobs);

    ScenarioDetailExpediteMOsT t = new ScenarioDetailExpediteMOsT(m_scenarioId, mosToExpedite, expediteStartType, expediteTimeInServerTime.Ticks, false, false);
    TransmissionFired?.Invoke(t, true);
    }
    }
    }
    catch (AutoTryEnterException)
    {
    //
    }
    }

    private static MOKeyList GetMoListWithSupplyMosAdded(JobManager a_jobManager, JobKeyList a_jobKeyList)
    {
    List<ManufacturingOrder> expediteMos = ManufacturingOrder.GetPredecessorMOsRecursively(a_jobManager, a_jobKeyList, out MOKeyList _, true, false);
    List<ManufacturingOrder> matlSupplyMos = new SupplyingMoList(a_jobManager, a_jobKeyList, true, true).GetSupplyingMOList();
    List<List<ManufacturingOrder>> listOfMoLists = new List<List<ManufacturingOrder>> { expediteMos, matlSupplyMos };
    return SupplyingMoList.MergeMoLists(listOfMoLists);
    }

    /// <summary>
    /// Expedite type enumeration
    /// </summary>
    public enum EJobExpediteType
    {
    ASAP,
    PreserveFrozenSpan
    }

    Next Steps

    To expand your customization, meet other types of scheduling requirements or to learn how to better navigate the PlanetTogether data objects explore the following articles:

    Advanced topics

    Coming Soon...