Is Eclipse API ready for Windows Forms Application?

Mar 21 at 12:31 PM
Hi everybody and many thanks in advance for your help. I'm really new in Eclipse API programming.

I've been running some Eclipse API examples using WPF windows (Windows window), however I am not able to show a Form using Windows Forms Application (Form frm).

May any of you confirm if is possible using Windows Forms Applications within an Eclipse API project? Any example to download?

Thxs,

-- Agus
Mar 22 at 10:17 PM
This seems to be a popular topic, I've put together a very basic structure of how to use windows forms. I'm not an expert coder so this is very likely not the most elegant method. There are also many things you may want to add. Such as color, re-ordering of rows so that structures not found are near the bottom, a check of the form height against maximum screen resolution height etc.

I wrote this as a binary plug-in, I didn't try it as a single file plugin. You will have to add references to System.Windows.Forms and System.Drawing.

At my center I setup the form as a single file plug in, compiled this and reference the .dll in binary file plugins. I do this so that I only have to change the form in one location.

Anyway below is the code.
Michael
using System;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections.Generic;
using VMS.TPS.Common.Model.API;
using VMS.TPS.Common.Model.Types;
using System.Windows.Forms;
using System.Drawing;

namespace VMS.TPS
{
  public class Script
  {
    public Script()
    {
    }

    public void Execute(ScriptContext context /*, System.Windows.Window window*/)
    {
        Form1 dvhform = new Form1();
        dvhform.ChangeSize(750, 300); // you could write you own method below to set the height based on the number of rows added
        dvhform.Location = new System.Drawing.Point(200, 50); // sets the form location when it pops up
        PlanSetup plan = context.PlanSetup;
        DataGridView dvhDataGridView = new DataGridView();
        dvhform.SetupDataGridView(dvhDataGridView); //used to personalize your form setup
        // -------------------- Find Structures ------------------------
        Structure ptv = (from s in context.StructureSet.Structures where s.Id == "PTV" select s).SingleOrDefault();
        Structure ctv = (from s in context.StructureSet.Structures where s.Id == "Prostate PSV CTV" select s).SingleOrDefault();

        // --------------------------- Apply your local DVH objectives ----------------------

        if (ptv == null || ptv.Volume == 0)
        {
            // messages here for structure not found
            dvhDataGridView.Rows.Add("PTV", "Objective1", "NA", "Not found"); // (Structure name, protocol objective, plan value, met objective)
        }
        else
        {
            //Code here to get plan value and check if it meets the DVH objective
            dvhDataGridView.Rows.Add("PTV", "Objective1", "Plan Value1", "Yes/No"); // (Structure name, protocol objective, plan value, met objective)
            dvhDataGridView.Rows.Add("PTV", "Objective2", "Plan Value2", "Yes/No"); // (Structure name, protocol objective, plan value, met objective)
        }
        if (ctv == null || ptv.Volume == 0)
        {
            //Code here to get plan value and check if it meets the DVH objective
            dvhDataGridView.Rows.Add("CTV", "Objective3", "NA", "Not Found"); // (Structure name, protocol objective, plan value, met objective)
        }
        else
        {
            //Code here to get plan value and check if it meets the DVH objective
            dvhDataGridView.Rows.Add("CTV", "Objective3", "Plan Value", "Yes/No");
        }

        // Show the windows form
        System.Windows.Forms.Application.Run(dvhform);
    }
    public class Form1 : System.Windows.Forms.Form
    {
        public void ChangeSize(int width, int height)
        {
            this.Size = new System.Drawing.Size(width, height);
        }
        public void SetupDataGridView(DataGridView dvhDataGridView)
        {
            // Use this method to setup the layout of you datagridview
            this.Controls.Add(dvhDataGridView);
            dvhDataGridView.ShowCellToolTips = false;

            dvhDataGridView.ColumnCount = 4;
            dvhDataGridView.AllowUserToAddRows = false;
            dvhDataGridView.Columns[0].Width = 250;
            dvhDataGridView.Columns[1].Width = 150;
            dvhDataGridView.Columns[2].Width = 125;
            dvhDataGridView.Columns[3].Width = 200;

            dvhDataGridView.ColumnHeadersDefaultCellStyle.BackColor = Color.Navy;
            dvhDataGridView.ColumnHeadersDefaultCellStyle.ForeColor = Color.White;
            dvhDataGridView.ColumnHeadersDefaultCellStyle.Font = new Font(dvhDataGridView.Font, System.Drawing.FontStyle.Bold);
            dvhDataGridView.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
            dvhDataGridView.ColumnHeadersDefaultCellStyle.Font = new Font("Arial", 20F, System.Drawing.FontStyle.Bold, GraphicsUnit.Pixel);
            dvhDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;

            dvhDataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders;
            dvhDataGridView.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
            dvhDataGridView.CellBorderStyle = DataGridViewCellBorderStyle.Single;
            dvhDataGridView.RowHeadersVisible = false;

            dvhDataGridView.Columns[0].Name = "Structure";
            dvhDataGridView.Columns[1].Name = "Protocol";
            dvhDataGridView.Columns[2].Name = "Plan";
            dvhDataGridView.Columns[3].Name = "Meets Protocol";

            dvhDataGridView.MultiSelect = false;
            dvhDataGridView.Dock = DockStyle.Fill;
            dvhDataGridView.ClearSelection();
            dvhDataGridView.DefaultCellStyle.SelectionBackColor = Color.LightBlue;
            dvhDataGridView.DefaultCellStyle.SelectionForeColor = Color.Black;
        }

    }
  }
}
Marked as answer by avalgoma on 3/27/2017 at 3:47 AM
Coordinator
Mar 25 at 9:21 PM
If you'd like to see a basic example of a WPF plug-in script, see my blog post Simple DVH Summary Script using WPF and MVVM. The code is on GitHub as DvhSummary.
Marked as answer by avalgoma on 3/27/2017 at 3:47 AM
Sep 27 at 9:30 AM
Hi TrapJaw.

Thanks for posting this. I am interested in developing a single plug-in file using windows forms. I tried to use your code but could not get it to work. All I did was to copy-paste to a .cs file (created with the Eclipse Scripting Wizard) and added System.Windows.Forms and System.Drawing to the solution references. But when I execute the script from within Eclipse, I get the error telling me that

The type or namespace name Forms does not exist int he namespace System.Windows (are you missing an assembly reference?)

But that's exactly what I tried to do? Do you or anyone else know what wrong here?

It's not the first time I have come across this issue, but I am new to Eclipse, so a good explanation would be highly appreciated :)
Coordinator
Sep 27 at 4:36 PM
For single file plug-ins, Eclipse loads only the .cs file. This means that any references you add to your solution are completely ignored. If you want to use Windows Forms, you need to work with a binary plug-in. I describe the differences between plug-ins here: Single-File Plug-In vs. Binary Plug-In vs. Stand-Alone App.

I looked into this problem further and I was surprised by something. If you look at the loaded assemblies in Eclipse (click on the Help button, then on About External Beam Planning, then on More Info, then on OS System Info, then expand Software Environment, and select Loaded Modules), the System.Windows.Forms assembly is apparently loaded. It was surprising to me that even though Forms is loaded in Eclipse, it's inaccessible to your script.

Actually, I was able to access the Forms assembly in a single file plug-in using Reflection, but it was very cumbersome to work with types that way. For example, here's what I had to do to simply create an empty Form and display it:
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var formsAssembly = assemblies.FirstOrDefault(asm => asm.GetName().Name == "System.Windows.Forms");
var formsTypes = formsAssembly.GetExportedTypes();
var formType = formsTypes.FirstOrDefault(t => t.Name == "Form");
var form = Activator.CreateInstance(formType);
var showDialogMethod = formType.GetMethod("ShowDialog", new Type[0]);
showDialogMethod.Invoke(form, null);
I don't know the internals of Eclipse, but I'm guessing they're using something like the CompileAssemblyFromFile method to create an in-memory assembly of your script. That method takes a CompilerParameters object where you can specify which assemblies should be referenced by your script. My guess is that Eclipse doesn't specify the System.Windows.Forms assembly there. It must specify the WPF-related assemblies because you're able to show a WPF message box and access other related types. Again, this is just a guess. Perhaps someone from Varian could explain what's going on.