Cancel and Ok buttons in Eto form

Hi All,

I have been working on a python 3 script with multiple drop down boxes, I have been assisted by Callum and Curtis and now I have the drop downs working with my dictionary.

As this is not written in my usual format which my poor head can follow I find myself struggling to get a Cancel and Ok button on the form and upon clicking “OK” I want to return each of the four drop down list items selected a= dd1, b=dd2, etc.

I have inserted the script as I cannot download a PY3 file, all help appreciated

#! python3

# Imports
import scriptcontext as sc
import rhinoscriptsyntax as rs 
import Rhino
from Rhino.UI import RhinoEtoApp, EtoExtensions
 
from Eto.Drawing import Padding, Size
from Eto.Forms import Dialog, DropDown, DynamicLayout
import Eto.Forms as forms
from System.Collections.ObjectModel import ObservableCollection

items1 = []

#Geo Pipework dialog class
class GeoPipeworkDialog(forms.Dialog[bool]):
    
    # Dialog box Class initializer
    def __init__(dialog):

        # call base class initializer
        super().__init__()
 
        dialog = Dialog()
        dialog.Title = "Geo Pipework"
        dialog.Width = 800
        dialog.Padding = Padding(10)

        # One data source for simplicity. Dictionaries are always good.
        data = {
            "ASME B 16.5": ['ASME B 16.5 45 Long Radius Elbows', 'ASME B 16.5 90 Long Radius Elbows', 'ASME B 16.5 90 Short Radius Elbows', 'ASME B 16.5 As Built Elbows', 'ASME B 16.5 Blind Flanges', 'ASME B 16.5 Flush Face Weld Neck Flanges', 'ASME B 16.5 Pipe', 'ASME B 16.5 Pulled Bends', 'ASME B 16.5 Raised Face Weld Neck Flanges', 'ASME B 16.5 SS Concentric Reducers', 'ASME B 16.5 SS Eccentric Reducers', 'ASME B 16.5 Slip On Flanges', 'ASME B 16.5 Socket Flanges', 'ASME B 16.5 Weld Neck Raised Face Ring Type Joints'],

            'ASME B 16.5 45 Long Radius Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 90 Long Radius Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 90 Short Radius Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 As Built Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 Blind Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Flush Face Weld Neck Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Pipe': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Pulled Bends': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 Raised Face Weld Neck Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 SS Concentric Reducers': ['3/4 x 1/2 inch', '3/4 x 3/8 inch', '1 x 3/4 inch', '1 x 1/2 inch', '1 x 3/8 inch', '1 1/4 x 1 inch', '1 1/4 x 3/4  inch', '1 1/4 x 1/2  inch', '1 1/2 x 1 1/4  inch', '1 1/2 x 1 inch', '1 1/2 x 3/4 inch', '1 1/2 x 1/2 inch', '2 x 1 1/2 inch', '2 x 1 1/4 inch', '2 x 1  inch', '2 x 3/4 inch', '2 1/2 x 2 inch', '2 1/2 x 1 1/2 inch', '2 1/2 x 1 1/4 inch', '2 1/2 x 1 inch', '3 x 2 1/2 inch', '3 x 2 inch', '3 x 1 1/2 inch', '3 x 1 1/4 inch', '3 1/2 x 3  inch', '3 1/2 x 2 1/2 inch', '3 1/2 x 2  inch', '3 1/2 x 1 1/2 inch', '3 1/2 x 1 1/4 inch', '4 x 3 1/4 inch', '4 x 3  inch', '4 x 2 1/2 inch', '4 x 2 inch', '4 x 1 1/2 inch', '5 x 4 inch', '5 x 3 1/2 inch', '5 x 3 inch', '5 x 2 1/2  inch', '5 x 2 inch', '6 x 5 inch', '6 x 4 inch', '6 x 3 1/2 inch', '6 x 3 inch', '6 x 2 1/2 inch', '8 x 6 inch', '8 x 5 inch', '8 x 4 inch', '8 x 3 1/2 inch', '10 x 8 inch', '10 x 6 inch', '10 x 5 inch', '10 x 4  inch', '12 x 10 inch', '12 x 8 inch', '12 x 6 inch', '12 x 5 inch', '14 x 12 inch', '14 x 10 inch', '14 x 8 inch', '14 x 6 inch', '16 x 14 inch', '16 x 12 inch', '16 x 10 inch', '16 x 8 inch', '18 x 16 inch', '18 x 14 inch', '18 x 12 inch', '18 x 10 inch', '20 x 18 inch', '20 x 16 inch', '20 x 14 inch', '20 x 12 inch', '22 x 20 inch', '22 x 18 inch', '22 x 16 inch', '22 x 14 inch', '24 x 22 inch', '24 x 20 inch', '24 x 18 inch', '24 x 16 inch'],
            'ASME B 16.5 SS Eccentric Reducers': ['3/4 x 1/2 inch', '3/4 x 3/8 inch', '1 x 3/4 inch', '1 x 1/2 inch', '1 x 3/8 inch', '1 1/4 x 1 inch', '1 1/4 x 3/4  inch', '1 1/4 x 1/2  inch', '1 1/2 x 1 1/4  inch', '1 1/2 x 1 inch', '1 1/2 x 3/4 inch', '1 1/2 x 1/2 inch', '2 x 1 1/2 inch', '2 x 1 1/4 inch', '2 x 1  inch', '2 x 3/4 inch', '2 1/2 x 2 inch', '2 1/2 x 1 1/2 inch', '2 1/2 x 1 1/4 inch', '2 1/2 x 1 inch', '3 x 2 1/2 inch', '3 x 2 inch', '3 x 1 1/2 inch', '3 x 1 1/4 inch', '3 1/2 x 3  inch', '3 1/2 x 2 1/2 inch', '3 1/2 x 2  inch', '3 1/2 x 1 1/2 inch', '3 1/2 x 1 1/4 inch', '4 x 3 1/4 inch', '4 x 3  inch', '4 x 2 1/2 inch', '4 x 2 inch', '4 x 1 1/2 inch', '5 x 4 inch', '5 x 3 1/2 inch', '5 x 3 inch', '5 x 2 1/2  inch', '5 x 2 inch', '6 x 5 inch', '6 x 4 inch', '6 x 3 1/2 inch', '6 x 3 inch', '6 x 2 1/2 inch', '8 x 6 inch', '8 x 5 inch', '8 x 4 inch', '8 x 3 1/2 inch', '10 x 8 inch', '10 x 6 inch', '10 x 5 inch', '10 x 4  inch', '12 x 10 inch', '12 x 8 inch', '12 x 6 inch', '12 x 5 inch', '14 x 12 inch', '14 x 10 inch', '14 x 8 inch', '14 x 6 inch', '16 x 14 inch', '16 x 12 inch', '16 x 10 inch', '16 x 8 inch', '18 x 16 inch', '18 x 14 inch', '18 x 12 inch', '18 x 10 inch', '20 x 18 inch', '20 x 16 inch', '20 x 14 inch', '20 x 12 inch', '22 x 20 inch', '22 x 18 inch', '22 x 16 inch', '22 x 14 inch', '24 x 22 inch', '24 x 20 inch', '24 x 18 inch', '24 x 16 inch'],
            'ASME B 16.5 Slip On Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Socket Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Weld Neck Raised Face Ring Type Joints': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],



            "ASME B 16.47": ['ASME B 16.47 Raised Face Weld Neck Flanges'],

            'ASME B 16.47 Raised Face Weld Neck Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            #220: [221, 222, 223],
            #230: [231, 232, 233],

            300: ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],

            '1 1/2 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '1 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '2 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '3 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '4 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '5 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '6 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],

            400: ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],

            '150 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '300 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '400 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '600 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '900 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '1500 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '2500 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],

            500: ['3/4 x 1/2 inch', '3/4 x 3/8 inch', '1 x 3/4 inch', '1 x 1/2 inch', '1 x 3/8 inch', '1 1/4 x 1 inch', '1 1/4 x 3/4  inch', '1 1/4 x 1/2  inch', '1 1/2 x 1 1/4  inch', '1 1/2 x 1 inch', '1 1/2 x 3/4 inch', '1 1/2 x 1/2 inch', '2 x 1 1/2 inch', '2 x 1 1/4 inch', '2 x 1  inch', '2 x 3/4 inch', '2 1/2 x 2 inch', '2 1/2 x 1 1/2 inch', '2 1/2 x 1 1/4 inch', '2 1/2 x 1 inch', '3 x 2 1/2 inch', '3 x 2 inch', '3 x 1 1/2 inch', '3 x 1 1/4 inch', '3 1/2 x 3  inch', '3 1/2 x 2 1/2 inch', '3 1/2 x 2  inch', '3 1/2 x 1 1/2 inch', '3 1/2 x 1 1/4 inch', '4 x 3 1/4 inch', '4 x 3  inch', '4 x 2 1/2 inch', '4 x 2 inch', '4 x 1 1/2 inch', '5 x 4 inch', '5 x 3 1/2 inch', '5 x 3 inch', '5 x 2 1/2  inch', '5 x 2 inch', '6 x 5 inch', '6 x 4 inch', '6 x 3 1/2 inch', '6 x 3 inch', '6 x 2 1/2 inch', '8 x 6 inch', '8 x 5 inch', '8 x 4 inch', '8 x 3 1/2 inch', '10 x 8 inch', '10 x 6 inch', '10 x 5 inch', '10 x 4  inch', '12 x 10 inch', '12 x 8 inch', '12 x 6 inch', '12 x 5 inch', '14 x 12 inch', '14 x 10 inch', '14 x 8 inch', '14 x 6 inch', '16 x 14 inch', '16 x 12 inch', '16 x 10 inch', '16 x 8 inch', '18 x 16 inch', '18 x 14 inch', '18 x 12 inch', '18 x 10 inch', '20 x 18 inch', '20 x 16 inch', '20 x 14 inch', '20 x 12 inch', '22 x 20 inch', '22 x 18 inch', '22 x 16 inch', '22 x 14 inch', '24 x 22 inch', '24 x 20 inch', '24 x 18 inch', '24 x 16 inch'],

            '3/4 x 1/2 inch': ['N\A'],
            '3/4 x 3/8 inch': ['N\A'],
            '1 x 3/4 inch': ['N\A'],
            '1 x 1/2 inch': ['N\A'],
            '1 x 3/8 inch': ['N\A'],
            '1 1/4 x 1 inch' : ['N\A'],
            '1 1/4 x 3/4  inch' : ['N\A'],
            '1 1/4 x 1/2  inch' : ['N\A'],
            '1 1/2 x 1 1/4  inch' : ['N\A'],
            '1 1/2 x 1 1/4  inch': ['N\A'],
            '1 1/2 x 1 inch': ['N\A'],
            '1 1/2 x 3/4 inch': ['N\A'],
            '1 1/2 x 1/2 inch': ['N\A'],
            '2 x 1 1/2 inch': ['N\A'],
            '2 x 1 1/4 inch': ['N\A'],
            '2 x 1  inch': ['N\A'],
            '2 x 3/4 inch': ['N\A'],
            '2 1/2 x 2 inch': ['N\A'],
            '2 1/2 x 1 1/2 inch': ['N\A'],
            '2 1/2 x 1 1/4 inch': ['N\A'],
            '2 1/2 x 1 inch': ['N\A'],
            '3 x 2 1/2 inch': ['N\A'],
            '3 x 2 inch': ['N\A'],
            '3 x 1 1/2 inch': ['N\A'],
            '3 x 1 1/4 inch': ['N\A'],
            '3 1/2 x 3  inch': ['N\A'],
            '3 1/2 x 2 1/2 inch': ['N\A'],
            '3 1/2 x 2  inch': ['N\A'],
            '3 1/2 x 1 1/2 inch': ['N\A'],
            '3 1/2 x 1 1/4 inch': ['N\A'],
            '4 x 3 1/4 inch': ['N\A'],
            '4 x 3  inch': ['N\A'],
            '4 x 2 1/2 inch': ['N\A'],
            '4 x 2 inch': ['N\A'],
            '4 x 1 1/2 inch': ['N\A'],
            '5 x 4 inch': ['N\A'],
            '5 x 3 1/2 inch': ['N\A'],
            '5 x 3 inch': ['N\A'],
            '5 x 2 1/2  inch': ['N\A'],
            '5 x 2 inch': ['N\A'],
            '6 x 5 inch': ['N\A'],
            '6 x 4 inch': ['N\A'],
            '6 x 3 1/2 inch': ['N\A'],
            '6 x 3 inch': ['N\A'],
            '6 x 2 1/2 inch': ['N\A'],
            '8 x 6 inch': ['N\A'],
            '8 x 5 inch': ['N\A'],
            '8 x 4 inch': ['N\A'],
            '8 x 3 1/2 inch': ['N\A'],
            '10 x 8 inch': ['N\A'],
            '10 x 6 inch': ['N\A'],
            '10 x 5 inch': ['N\A'],
            '10 x 4  inch': ['N\A'],
            '12 x 10 inch': ['N\A'],
            '12 x 8 inch': ['N\A'],
            '12 x 6 inch': ['N\A'],
            '12 x 5 inch': ['N\A'],
            '14 x 12 inch': ['N\A'],
            '14 x 10 inch': ['N\A'],
            '14 x 8 inch': ['N\A'],
            '14 x 6 inch': ['N\A'],
            '16 x 14 inch': ['N\A'],
            '16 x 12 inch': ['N\A'],
            '16 x 10 inch': ['N\A'],
            '16 x 8 inch': ['N\A'],
            '18 x 16 inch': ['N\A'],
            '18 x 14 inch': ['N\A'],
            '18 x 12 inch': ['N\A'],
            '18 x 10 inch': ['N\A'],
            '20 x 18 inch': ['N\A'],
            '20 x 16 inch': ['N\A'],
            '20 x 14 inch': ['N\A'],
            '20 x 12 inch': ['N\A'],
            '22 x 20 inch': ['N\A'],
            '22 x 18 inch': ['N\A'],
            '22 x 16 inch': ['N\A'],
            '22 x 14 inch': ['N\A'],
            '24 x 22 inch': ['N\A'],
            '24 x 20 inch': ['N\A'],
            '24 x 18 inch': ['N\A'],
            '24 x 16 inch': ['N\A'],

        }

        # ObservableCollection will notify the UI of changes for us
        dd1_data = ObservableCollection[object]()
        dd1_data.Add("ASME B 16.5")
        dd1_data.Add("ASME B 16.47")
        #dd1_data.Add(300)
        #dd1_data.Add(400)
        dd2_data = ObservableCollection[object]()
        dd3_data = ObservableCollection[object]()
        dd4_data = ObservableCollection[object]()

        dd1 = DropDown()
        dd1.DataStore = dd1_data

        dd2 = DropDown()
        dd2.DataStore = dd2_data

        dd3 = DropDown()
        dd3.DataStore = dd3_data

        dd4 = DropDown()
        dd4.DataStore = dd4_data

        # Cache indexes to avoid unnecessary state updates which can be a bit crashy
        dialog.dd1_index = -1
        dialog.dd2_index = -1
        dialog.dd3_index = -1 #RD
        dialog.dd4_index = -1 #RD

        dialog.busy = False
        def update_state(sender, args):
            # Super safe busy check, prevents recursion!
            if (dialog.busy):
                return
            
            dialog.busy = True
            
            # Prevents crashing if there is no data, we should do this more, but I'm lazy
            if dd1.SelectedIndex == -1:
                return

            if (dd1.SelectedIndex != dialog.dd1_index):

                items1 = data[dd1.SelectedValue]
                
                # Note we don't set a NEW value, we use the same collection
                dd2_data.Clear()
                for i in items1:
                    dd2_data.Add(i)
                dd2.SelectedIndex = 0
                dd3.SelectedIndex = 0
                dd4.SelectedIndex = 0
                dialog.dd2_index = 0

            # This should run on 1 or 2 changing index
            if (dd2.SelectedIndex != dialog.dd2_index or
                dd1.SelectedIndex != dialog.dd1_index):
                items2 = data[dd2.SelectedValue]
                

            

                # Note we don't set a NEW value, we use the same collection
                dd3_data.Clear()
                for i in items2:
                    dd3_data.Add(i)
                dd3.SelectedIndex = 0

            if (dd3.SelectedIndex != dialog.dd3_index or
                dd2.SelectedIndex != dialog.dd2_index or
                dd1.SelectedIndex != dialog.dd1_index):

                dd4_data.Clear()
                if dd3.SelectedValue in data.keys():
                    items3 = data[dd3.SelectedValue]

                    # Note we don't set a NEW value, we use the same collection
                    for i in items3:
                        dd4_data.Add(i)
                    dd4.SelectedIndex = 0

            dialog.dd3_index = dd3.SelectedIndex
            dialog.dd2_index = dd2.SelectedIndex
            dialog.dd1_index = dd1.SelectedIndex

            

            
            # We are no longer busy!
            dialog.busy = False

        dd1.SelectedIndexChanged += update_state
        dd2.SelectedIndexChanged += update_state
        dd3.SelectedIndexChanged += update_state
        dd1.SelectedIndex = 0


        
        # Nice way to set up a UI with equal spacing
        dynamic = DynamicLayout()
        dynamic.Spacing = Size(4, 4) # Bit cramped otherwise
        dynamic.BeginHorizontal()
        dynamic.Add(dd1, True)
        dynamic.Add(dd2, True)
        dynamic.Add(dd3, True)
        dynamic.Add(dd4, True)
        dynamic.EndHorizontal()

 

        dialog.Content = dynamic

        parent = RhinoEtoApp.MainWindowForDocument(sc.doc)
        dialog.ShowModal(parent)

# The script that will be using the dialog.
def Pipework():
    #rs.CurrentDimStyle("Default")
    
    #Utility function to show the dialog box
    dialog = GeoPipeworkDialog();
    
    #Open the dialogue

    rc = dialog.ShowModal(Rhino.UI.RhinoEtoApp.MainWindow)
    if not rc: return




    
    print ("End of Geo Pipework")
# Check to see if this file is being executed as the "main" python
# script instead of being used as a module by some other python script
# This allows us to use the module which ever way we want.
if __name__ == "__main__":
    rc = Pipework()

I haven’t done anything with eto forms, but I found these guides that might be helpful:

Thanks Measure,

Read both but my lack of knowledge is the greatest barrier, I can do it when I stick to my usual way of writing code but Callum did the basics different and I find it hard to integrate my approach with his.
Roger

It seems this is the root of the issue then! It’s very important to understand code you are maintaining. I hoped to be helpful but it seems I’ve left you with a jigsaw puzzle without all the pieces.

How might you write this yourself, what is different between your style and mine? :slight_smile:

Hi Callum,

As you will see from this example I am a little more regimented in my approach as this was the layout of the first and only ETO example I could find at the time and based on this I have normally achieved what I need . Your approach was a lot more compact and due to the nature of linking the drop down boxes of which I had no experience I really appreciated the help but it left me then trying to get my head around the last two issues the ok and cancel buttons and the getting of the values when the ok button is picked.
Just different ways we would go about things.
The good news is that I now have the drop down boxes exactly as I needed them, just need to get to the output.

Roger

# Imports
import Rhino
import Rhino.UI
import scriptcontext
import System
import Eto.Drawing as drawing
import Eto.Forms as forms

import rhinoscriptsyntax as rs
from System.Drawing import Color
import codecs
import csv
import datetime

import re

# ImportExportPoints dialog class
class ImportExportPointsDialog(forms.Dialog[bool]):
    

    # Dialog box Class initializer
    def __init__(self):
        # call base class initializer
        super().__init__()

        self.Title = "Import Export Points"
        self.Padding = drawing.Padding(10)
        self.Resizable = False
        
        # Create controls for the dialog
        self.m_import_checkbox = forms.CheckBox()
        self.m_import_checkbox.Text = "Select if import points"
        self.m_import_checkbox.Tag = "Import"

        #(Text = 'Select if import points', Tag="Import")
        
        #self.m_import_checkbox.Checked = True
        self.m_import_checkbox.CheckedChanged += self.OnCCheckedChanged
        
        #self.m_import_checkbox.Checked = True
        
        self.m_export_checkbox = forms.CheckBox()
        self.m_export_checkbox.Text = "Select if export points"
        self.m_export_checkbox.Tag = "Export"
        
        #self.m_export_checkbox.Checked = False
        self.m_export_checkbox.CheckedChanged += self.OnCCheckedChanged
        
        #self.m_export_checkbox.Checked = False
        
        self.m_combobox = forms.ComboBox()
        self.m_combobox.DataStore = ['SC4W.crd', 'Tritop.txt', 'Excel.csv','Faro.txt']
        self.m_combobox.SelectedIndex = 0
        
        self.m_label = forms.Label()
        self.m_label.Text =  "Select Format:"
        
        # Create the default button
        self.DefaultButton = forms.Button()
        self.DefaultButton.Text = "OK"

        self.DefaultButton.Click += self.OnOKButtonClick
        
        # Create the abort button
        self.AbortButton = forms.Button()
        self.AbortButton.Text = "Cancel"
        
        self.AbortButton.Click += self.OnCloseButtonClick
        
        # Create a table layout and add all the controls
        layout = forms.DynamicLayout()
        layout.Spacing = drawing.Size(5, 5)
        layout.AddRow(self.m_import_checkbox)
        layout.AddRow(self.m_export_checkbox)
        layout.AddRow(self.m_label, self.m_combobox)
        layout.AddRow(None) # spacer
        layout.AddRow(self.DefaultButton, self.AbortButton)
        
        # Set the dialog content
        self.Content = layout
        
    def OnCCheckedChanged(self, sender, e):
        
        # if this event is not fired from a CheckBox, exit the event
        if not isinstance(sender, forms.CheckBox): return
        
        # handles enable and disable state depending on check state
        if sender.Tag == "Import":
            print ("Event Call from Import Checkbox")
            if sender.Checked:
                # disable and uncheck the export checkbox
                self.m_export_checkbox.Checked = False
                self.m_export_checkbox.Enabled = False
            else:
                # enable the export checkbox
                self.m_export_checkbox.Enabled = True
            
        elif sender.Tag == "Export":
            print ("Event call from Export Checkbox")
            if sender.Checked:
                # disable and uncheck the import checkbox
                self.m_import_checkbox.Checked = False
                self.m_import_checkbox.Enabled = False
            else:
                # enable the export checkbox
                self.m_import_checkbox.Enabled = True
        
    
    # Start of the class functions
    
    # Get/set the value of the first checkbox
    def GetImport(self):
        return self.m_import_checkbox.Checked
    def SetImport(self, set):
        self.m_import_checkbox.Checked = not set
    
    # Get/set the value of the second checkbox
    def GetExport(self):
        return self.m_export_checkbox.Checked
    def SetExport(self, set):
        self.m_export_checkbox.Checked = not set
        
    # Get/set the value of the combobox
    def GetFormatOption(self):
      return self.m_combobox.SelectedIndex
    def SetFormatOption(self, index):
      self.m_combobox.SelectedIndex = Rhino.RhinoMath.Clamp(index, 0, 2)
    
    # Close button click handler
    def OnCloseButtonClick(self, sender, e):
        self.Close(False)
    
    # OK button click handler
    def OnOKButtonClick(self, sender, e):
        self.Close(True)
    ## End of Dialog Class ##
    
    # Utility function to show the dialog box

def ShowImportExportPointsDialog(setImport = False, setExport = False, setFormat = 0):

    # initialize the dialog
    dialog = ImportExportPointsDialog()
    
    # set the format option
    dialog.SetFormatOption(setFormat)
    
    rc = dialog.ShowModal(Rhino.UI.RhinoEtoApp.MainWindow)
    
    # print what the dialog returns it is either True (OK) or False (Cancel)
    print ( "rc ={}".format(rc))
    
    # exit if the user clicked cancel
    if rc == False: return
    
    # build some result variable from the settings in the dialog
    result = dialog.GetImport(), dialog.GetExport(), dialog.GetFormatOption()
    
    #print out the settings
    print ( "result =", result)
    # handle what has been chosen
    
    if result == (True,False,0):
        #var1 = rc0
        # Import points from SC4W files        
        #
        #prompt the user for a file to import
        filenames = rs.OpenFileNames("Select SC4W Points Files", "SC4W Files (*.crd)|*.crd|All Files (*.*)|*.*||")
        
        # always exit if the user did not open a file
        if not filenames: return
        
        for filename in filenames: #print filename
            file_namea = filename.split("\\")[-1]
            file_nameb = file_namea.split(".")[0]
            #print file_nameb
            ##with open(file_path,"r") as pointfile:
            with open(filename,"r") as pointfile:
                #
                #print file=pointfile
                lines = pointfile.readlines()[1:]
                # Stop printing for time being
                #print (lines)
                rs.AddLayer(file_nameb, Color.Red)
                rs.CurrentLayer(file_nameb)
                #
                # Stop printing for time being
                #print (line)
                for line in lines:
                    row = line.split(",")
                    n = row[0]
                    c = row[1]
                    x = float(row[2])
                    y = float(row[3])
                    z = float(row[4])
                    
                    x=x*1000
                    y=y*1000
                    z=z*1000
                    
                    #print n, c, x, y, z
                    
                    rs.AddLayer(c, Color.Red, parent = file_nameb)
                    rs.CurrentLayer(c)
                
                    #line.split(",")
                    id = rs.AddPoint(x,y,z)
                    rs.ObjectName(id, n)
                    
                    #Close the file after writing!
                    pointfile.close()
        
    elif result == (True,False,1):
        # Import points from Tritop files        
        
        #prompt the user for a file to import
        filenames = rs.OpenFileNames("Select Tritop Points Files", "Tritop Files (*.txt)|*.txt|All Files (*.*)|*.*||")
        
        # always exit if the user did not open a file
        if not filenames: return
        
        for filename in filenames: #print filename
            file_namea = filename.split("\\")[-1]
            file_nameb = file_namea.split(".")[0]
            #print file_nameb
            with open(filename,"r") as pointfile:
                #print file=pointfile
                lines = pointfile.readlines()
                 # Stop printing for time being
                 # print (lines)
                rs.AddLayer(file_nameb, Color.Red)
                rs.CurrentLayer(file_nameb)
    
            for line in lines:
                # Stop printing for time being
                # print (line)
                
                
                n,x,y,z = line.split(" ")
                #n,x,y,z = line
                
                id = rs.AddPoint(float(x),float(y),float(z))
                rs.ObjectName(id, n)
                
                #Close the file after writing!
                pointfile.close()
        
    elif result == (True,False,2):
        #var3 = rc0

        #prompt the user for a file to import
        ##filter = "CSV file (*.csv)|*.csv|All Files (*.*)|*.*||"
        ##file_path = rs.OpenFileName("Select Excel CSV Points File", filter)
        
        filenames = rs.OpenFileNames("Select Excel CSV Points Files", "Excel CSV Files (*.csv)|*.csv|All Files (*.*)|*.*||")
        
        # always exit if the user did not open a file
        if not filenames: return
        
        for filename in filenames:#print filename
            file_namea = filename.split("\\")[-1]
            file_nameb = file_namea.split(".")[0]
            with open(filename, 'r') as infile:
                reader = csv.reader(codecs.EncodedFile(infile, 'utf8', 'utf_8_sig'), delimiter=",")
                # This skips the first row of the CSV file.
                next(reader)
                # This skips the second row of the CSV file.
                next(reader)
                
                rs.AddLayer(file_nameb, Color.Red)
                rs.CurrentLayer(file_nameb)
                
                for row in reader:
                    n = row[0]
                    x = float(row[1])
                    y = float(row[2])
                    z = float(row[3])
                    #print n, x, y, z
                    
                    id = rs.AddPoint(x,y,z)
                    rs.ObjectName(id, n)
                    
                #Close the file after writing!
                infile.close()
                
    elif result == (True,False,3):
        var7 = rc0
        #print ("var7 = ") + str(var7)
        

        

    elif result == (False,True,0):
         
        #Select our points
        pts = rs.GetObjects("Select Points for SC4W Export", 1)
        
        # handle if the user did not select some points
        if not pts: return
        
        x = datetime.datetime.now()
        
        day = x.day
        month = x.month
        year = x.year
        
        Date = str(day) + "/" + str(month) + "/" + str(year)
        #print Date
        
        hour = x.hour
        minute = x.minute
        second = x.second
        
        Time = str(hour) + "/" + str(minute) + "/" + str(second)
        #print Time
        
        
         
        #create a filename variable
        filename = rs.SaveFileName("Save SC4W file","*.crd||", None, "ptExport", "crd")
        
        # handle if the user did not choose a file 
        if not filename: return
        
        #open the file for writing
        file = open(filename, 'w')
         
        #create and write a headerline for our CRD
        headerline = "Name,Code,X,Y,Z\n"
        file.write(headerline)
        #print headerline
        #space = " \n"
        #file.write(space)
         
        #print pts
        for pt in pts:
            ptCoord = rs.PointCoordinates(pt)
            x = ptCoord[0]
            y = ptCoord[1]
            z = ptCoord[2]
            
            x=x*0.001
            y=y*0.001
            z=z*0.001
            
            
            n = rs.ObjectName(pt)
            #print n
            layer = rs.ObjectLayer(pt)
            #print layer
            
            
            
            # using string find() method
            #print(layer.find('::'))
            
            if (layer.find('::')) != -1:
                la = layer.split("::")[1]
                d = layer.split("::")[0]
                    
            elif (layer.find('::')) == -1:
                la = layer
                d = layer
            
            #line = "%s ,%s,%.8f,%.8f,%.8f,,,%s \n" %(n,layer,x,y,z,d)
            line = "%s ,%s,%.8f,%.8f,%.8f,,,%s \n" %(n,la,x,y,z,d)
            file.write(line)
                
        #Close the file after writing!
        file.close()
        
        
        
    elif result == (False,True,1):
        #var5 = rc0
        #print "var5 = " + str(var5)
        
        #Export Points to TXT
 
        #Select our points
        pts = rs.GetObjects("Select Points for TXT Export", 1)
        if not pts: return
         
        #create a filename variable
        filename = rs.SaveFileName("Save Tritop file","*.txt||", None, "ptExport", "txt")
        if not filename: return
        
        # always exit if the user did not open a file
        if not filename: return
        
        #open the file for writing
        file = open(filename, 'w')
         
        #create and write a headerline for our TXT
        headerline = "Name,X,Y,Z\n"
        file.write(headerline)
        space = ",,,,\n"
        file.write(space)
         
        #print pts
        for pt in pts:
            ptCoord = rs.PointCoordinates(pt)
            x = ptCoord[0]
            y = ptCoord[1]
            z = ptCoord[2]
            n = rs.ObjectName(pt)
            #print n
            line = "%s ,%.8f,%.8f,%.8f \n" %(n,x,y,z)
            file.write(line)
            
        #Close the file after writing!
        file.close()
        
    elif result == (False,True,2):
        #var6 = rc0
        #print "var6 = " + str(var6)
        
        #Export Points to CSV
 
        #Select our points
        pts = rs.GetObjects("Select Points for CSV Export", 1)
        if not pts: return
        
        #create a filename variable
        filename = rs.SaveFileName("Save Excel CSV file","*.csv||", None, "ptExport", "csv")
        if not filename: return
        
        #open the file for writing
        file = open(filename, 'w')
         
        #create and write a headerline for our CSV
        headerline = "Name,X,Y,Z\n"
        file.write(headerline)
        space = ",,,,\n"
        file.write(space)
         
        #print pts
        for pt in pts:
            ptCoord = rs.PointCoordinates(pt)
            x = ptCoord[0]
            y = ptCoord[1]
            z = ptCoord[2]
            n = rs.ObjectName(pt)
            #print n
            line = "%s ,%.8f,%.8f,%.8f \n" %(n,x,y,z)
            file.write (line)
        #Close the file after writing!
        file.close()

if __name__ == "__main__":
    ShowImportExportPointsDialog()

Hi Callum,

I now have the buttons showing in the form but keep getting errors on the

dialog.AbortButton.Click += dialog.OnCloseButtonClick

‘Dialog’ object has no attribute ‘OnCloseButtonClick’

so slowly getting to the end just need to resolve this and get the values from the dd lists.

#! python3

# Imports
import scriptcontext as sc
import rhinoscriptsyntax as rs 
import Rhino
from Rhino.UI import RhinoEtoApp, EtoExtensions
import Eto.Drawing as drawing
from Eto.Drawing import Padding, Size
from Eto.Forms import Dialog, DropDown, DynamicLayout
import Eto.Forms as forms
from System.Collections.ObjectModel import ObservableCollection

items1 = []

#Geo Pipework dialog class
class GeoPipeworkDialog(forms.Dialog[bool]):
    
    # Dialog box Class initializer
    def __init__(dialog):

        # call base class initializer
        super().__init__()
 
        dialog = Dialog()
        dialog.Title = "Geo Pipework"
        dialog.Width = 800
        dialog.Padding = Padding(10)

        # One data source for simplicity. Dictionaries are always good.
        data = {
            "ASME B 16.5": ['ASME B 16.5 45 Long Radius Elbows', 'ASME B 16.5 90 Long Radius Elbows', 'ASME B 16.5 90 Short Radius Elbows', 'ASME B 16.5 As Built Elbows', 'ASME B 16.5 Blind Flanges', 'ASME B 16.5 Flush Face Weld Neck Flanges', 'ASME B 16.5 Pipe', 'ASME B 16.5 Pulled Bends', 'ASME B 16.5 Raised Face Weld Neck Flanges', 'ASME B 16.5 SS Concentric Reducers', 'ASME B 16.5 SS Eccentric Reducers', 'ASME B 16.5 Slip On Flanges', 'ASME B 16.5 Socket Flanges', 'ASME B 16.5 Weld Neck Raised Face Ring Type Joints'],

            'ASME B 16.5 45 Long Radius Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 90 Long Radius Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 90 Short Radius Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 As Built Elbows': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 Blind Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Flush Face Weld Neck Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Pipe': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Pulled Bends': ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],
            'ASME B 16.5 Raised Face Weld Neck Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 SS Concentric Reducers': ['3/4 x 1/2 inch', '3/4 x 3/8 inch', '1 x 3/4 inch', '1 x 1/2 inch', '1 x 3/8 inch', '1 1/4 x 1 inch', '1 1/4 x 3/4  inch', '1 1/4 x 1/2  inch', '1 1/2 x 1 1/4  inch', '1 1/2 x 1 inch', '1 1/2 x 3/4 inch', '1 1/2 x 1/2 inch', '2 x 1 1/2 inch', '2 x 1 1/4 inch', '2 x 1  inch', '2 x 3/4 inch', '2 1/2 x 2 inch', '2 1/2 x 1 1/2 inch', '2 1/2 x 1 1/4 inch', '2 1/2 x 1 inch', '3 x 2 1/2 inch', '3 x 2 inch', '3 x 1 1/2 inch', '3 x 1 1/4 inch', '3 1/2 x 3  inch', '3 1/2 x 2 1/2 inch', '3 1/2 x 2  inch', '3 1/2 x 1 1/2 inch', '3 1/2 x 1 1/4 inch', '4 x 3 1/4 inch', '4 x 3  inch', '4 x 2 1/2 inch', '4 x 2 inch', '4 x 1 1/2 inch', '5 x 4 inch', '5 x 3 1/2 inch', '5 x 3 inch', '5 x 2 1/2  inch', '5 x 2 inch', '6 x 5 inch', '6 x 4 inch', '6 x 3 1/2 inch', '6 x 3 inch', '6 x 2 1/2 inch', '8 x 6 inch', '8 x 5 inch', '8 x 4 inch', '8 x 3 1/2 inch', '10 x 8 inch', '10 x 6 inch', '10 x 5 inch', '10 x 4  inch', '12 x 10 inch', '12 x 8 inch', '12 x 6 inch', '12 x 5 inch', '14 x 12 inch', '14 x 10 inch', '14 x 8 inch', '14 x 6 inch', '16 x 14 inch', '16 x 12 inch', '16 x 10 inch', '16 x 8 inch', '18 x 16 inch', '18 x 14 inch', '18 x 12 inch', '18 x 10 inch', '20 x 18 inch', '20 x 16 inch', '20 x 14 inch', '20 x 12 inch', '22 x 20 inch', '22 x 18 inch', '22 x 16 inch', '22 x 14 inch', '24 x 22 inch', '24 x 20 inch', '24 x 18 inch', '24 x 16 inch'],
            'ASME B 16.5 SS Eccentric Reducers': ['3/4 x 1/2 inch', '3/4 x 3/8 inch', '1 x 3/4 inch', '1 x 1/2 inch', '1 x 3/8 inch', '1 1/4 x 1 inch', '1 1/4 x 3/4  inch', '1 1/4 x 1/2  inch', '1 1/2 x 1 1/4  inch', '1 1/2 x 1 inch', '1 1/2 x 3/4 inch', '1 1/2 x 1/2 inch', '2 x 1 1/2 inch', '2 x 1 1/4 inch', '2 x 1  inch', '2 x 3/4 inch', '2 1/2 x 2 inch', '2 1/2 x 1 1/2 inch', '2 1/2 x 1 1/4 inch', '2 1/2 x 1 inch', '3 x 2 1/2 inch', '3 x 2 inch', '3 x 1 1/2 inch', '3 x 1 1/4 inch', '3 1/2 x 3  inch', '3 1/2 x 2 1/2 inch', '3 1/2 x 2  inch', '3 1/2 x 1 1/2 inch', '3 1/2 x 1 1/4 inch', '4 x 3 1/4 inch', '4 x 3  inch', '4 x 2 1/2 inch', '4 x 2 inch', '4 x 1 1/2 inch', '5 x 4 inch', '5 x 3 1/2 inch', '5 x 3 inch', '5 x 2 1/2  inch', '5 x 2 inch', '6 x 5 inch', '6 x 4 inch', '6 x 3 1/2 inch', '6 x 3 inch', '6 x 2 1/2 inch', '8 x 6 inch', '8 x 5 inch', '8 x 4 inch', '8 x 3 1/2 inch', '10 x 8 inch', '10 x 6 inch', '10 x 5 inch', '10 x 4  inch', '12 x 10 inch', '12 x 8 inch', '12 x 6 inch', '12 x 5 inch', '14 x 12 inch', '14 x 10 inch', '14 x 8 inch', '14 x 6 inch', '16 x 14 inch', '16 x 12 inch', '16 x 10 inch', '16 x 8 inch', '18 x 16 inch', '18 x 14 inch', '18 x 12 inch', '18 x 10 inch', '20 x 18 inch', '20 x 16 inch', '20 x 14 inch', '20 x 12 inch', '22 x 20 inch', '22 x 18 inch', '22 x 16 inch', '22 x 14 inch', '24 x 22 inch', '24 x 20 inch', '24 x 18 inch', '24 x 16 inch'],
            'ASME B 16.5 Slip On Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Socket Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            'ASME B 16.5 Weld Neck Raised Face Ring Type Joints': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],



            "ASME B 16.47": ['ASME B 16.47 Raised Face Weld Neck Flanges'],

            'ASME B 16.47 Raised Face Weld Neck Flanges': ['150 lb Rating', '300 lb Rating', '400 lb Rating', '600 lb Rating', '900 lb Rating', '1500 lb Rating', '2500 lb Rating'],
            #220: [221, 222, 223],
            #230: [231, 232, 233],

            300: ['1 1/2 D Elbow', '1 D Elbow', '2 D Elbow', '3 D Elbow', '4 D Elbow', '5 D Elbow', '6 D Elbow'],

            '1 1/2 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '1 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '2 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '3 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '4 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '5 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '6 D Elbow': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],

            400: ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],

            '150 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '300 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '400 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '600 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '900 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '1500 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],
            '2500 lb Rating': ['1/4 inch', '3/8 inch', '1/2 inch', '3/4 inch', '1 inch', '1 1/4 inch', '1 1/2 inch', '2 inch', '2 1/2 inch', '3 inch', '3 1/2 inch', '4 inch', '5 inch', '6 inch', '8 inch', '10 inch', '12 inch', '14 inch', '16 inch', '18 inch', '20 inch', '22 inch', '24 inch'],

            500: ['3/4 x 1/2 inch', '3/4 x 3/8 inch', '1 x 3/4 inch', '1 x 1/2 inch', '1 x 3/8 inch', '1 1/4 x 1 inch', '1 1/4 x 3/4  inch', '1 1/4 x 1/2  inch', '1 1/2 x 1 1/4  inch', '1 1/2 x 1 inch', '1 1/2 x 3/4 inch', '1 1/2 x 1/2 inch', '2 x 1 1/2 inch', '2 x 1 1/4 inch', '2 x 1  inch', '2 x 3/4 inch', '2 1/2 x 2 inch', '2 1/2 x 1 1/2 inch', '2 1/2 x 1 1/4 inch', '2 1/2 x 1 inch', '3 x 2 1/2 inch', '3 x 2 inch', '3 x 1 1/2 inch', '3 x 1 1/4 inch', '3 1/2 x 3  inch', '3 1/2 x 2 1/2 inch', '3 1/2 x 2  inch', '3 1/2 x 1 1/2 inch', '3 1/2 x 1 1/4 inch', '4 x 3 1/4 inch', '4 x 3  inch', '4 x 2 1/2 inch', '4 x 2 inch', '4 x 1 1/2 inch', '5 x 4 inch', '5 x 3 1/2 inch', '5 x 3 inch', '5 x 2 1/2  inch', '5 x 2 inch', '6 x 5 inch', '6 x 4 inch', '6 x 3 1/2 inch', '6 x 3 inch', '6 x 2 1/2 inch', '8 x 6 inch', '8 x 5 inch', '8 x 4 inch', '8 x 3 1/2 inch', '10 x 8 inch', '10 x 6 inch', '10 x 5 inch', '10 x 4  inch', '12 x 10 inch', '12 x 8 inch', '12 x 6 inch', '12 x 5 inch', '14 x 12 inch', '14 x 10 inch', '14 x 8 inch', '14 x 6 inch', '16 x 14 inch', '16 x 12 inch', '16 x 10 inch', '16 x 8 inch', '18 x 16 inch', '18 x 14 inch', '18 x 12 inch', '18 x 10 inch', '20 x 18 inch', '20 x 16 inch', '20 x 14 inch', '20 x 12 inch', '22 x 20 inch', '22 x 18 inch', '22 x 16 inch', '22 x 14 inch', '24 x 22 inch', '24 x 20 inch', '24 x 18 inch', '24 x 16 inch'],

            '3/4 x 1/2 inch': ['N\A'],
            '3/4 x 3/8 inch': ['N\A'],
            '1 x 3/4 inch': ['N\A'],
            '1 x 1/2 inch': ['N\A'],
            '1 x 3/8 inch': ['N\A'],
            '1 1/4 x 1 inch' : ['N\A'],
            '1 1/4 x 3/4  inch' : ['N\A'],
            '1 1/4 x 1/2  inch' : ['N\A'],
            '1 1/2 x 1 1/4  inch' : ['N\A'],
            '1 1/2 x 1 1/4  inch': ['N\A'],
            '1 1/2 x 1 inch': ['N\A'],
            '1 1/2 x 3/4 inch': ['N\A'],
            '1 1/2 x 1/2 inch': ['N\A'],
            '2 x 1 1/2 inch': ['N\A'],
            '2 x 1 1/4 inch': ['N\A'],
            '2 x 1  inch': ['N\A'],
            '2 x 3/4 inch': ['N\A'],
            '2 1/2 x 2 inch': ['N\A'],
            '2 1/2 x 1 1/2 inch': ['N\A'],
            '2 1/2 x 1 1/4 inch': ['N\A'],
            '2 1/2 x 1 inch': ['N\A'],
            '3 x 2 1/2 inch': ['N\A'],
            '3 x 2 inch': ['N\A'],
            '3 x 1 1/2 inch': ['N\A'],
            '3 x 1 1/4 inch': ['N\A'],
            '3 1/2 x 3  inch': ['N\A'],
            '3 1/2 x 2 1/2 inch': ['N\A'],
            '3 1/2 x 2  inch': ['N\A'],
            '3 1/2 x 1 1/2 inch': ['N\A'],
            '3 1/2 x 1 1/4 inch': ['N\A'],
            '4 x 3 1/4 inch': ['N\A'],
            '4 x 3  inch': ['N\A'],
            '4 x 2 1/2 inch': ['N\A'],
            '4 x 2 inch': ['N\A'],
            '4 x 1 1/2 inch': ['N\A'],
            '5 x 4 inch': ['N\A'],
            '5 x 3 1/2 inch': ['N\A'],
            '5 x 3 inch': ['N\A'],
            '5 x 2 1/2  inch': ['N\A'],
            '5 x 2 inch': ['N\A'],
            '6 x 5 inch': ['N\A'],
            '6 x 4 inch': ['N\A'],
            '6 x 3 1/2 inch': ['N\A'],
            '6 x 3 inch': ['N\A'],
            '6 x 2 1/2 inch': ['N\A'],
            '8 x 6 inch': ['N\A'],
            '8 x 5 inch': ['N\A'],
            '8 x 4 inch': ['N\A'],
            '8 x 3 1/2 inch': ['N\A'],
            '10 x 8 inch': ['N\A'],
            '10 x 6 inch': ['N\A'],
            '10 x 5 inch': ['N\A'],
            '10 x 4  inch': ['N\A'],
            '12 x 10 inch': ['N\A'],
            '12 x 8 inch': ['N\A'],
            '12 x 6 inch': ['N\A'],
            '12 x 5 inch': ['N\A'],
            '14 x 12 inch': ['N\A'],
            '14 x 10 inch': ['N\A'],
            '14 x 8 inch': ['N\A'],
            '14 x 6 inch': ['N\A'],
            '16 x 14 inch': ['N\A'],
            '16 x 12 inch': ['N\A'],
            '16 x 10 inch': ['N\A'],
            '16 x 8 inch': ['N\A'],
            '18 x 16 inch': ['N\A'],
            '18 x 14 inch': ['N\A'],
            '18 x 12 inch': ['N\A'],
            '18 x 10 inch': ['N\A'],
            '20 x 18 inch': ['N\A'],
            '20 x 16 inch': ['N\A'],
            '20 x 14 inch': ['N\A'],
            '20 x 12 inch': ['N\A'],
            '22 x 20 inch': ['N\A'],
            '22 x 18 inch': ['N\A'],
            '22 x 16 inch': ['N\A'],
            '22 x 14 inch': ['N\A'],
            '24 x 22 inch': ['N\A'],
            '24 x 20 inch': ['N\A'],
            '24 x 18 inch': ['N\A'],
            '24 x 16 inch': ['N\A'],

        }

        # ObservableCollection will notify the UI of changes for us
        dd1_data = ObservableCollection[object]()
        dd1_data.Add("ASME B 16.5")
        dd1_data.Add("ASME B 16.47")
        #dd1_data.Add(300)
        #dd1_data.Add(400)
        dd2_data = ObservableCollection[object]()
        dd3_data = ObservableCollection[object]()
        dd4_data = ObservableCollection[object]()

        dd1 = DropDown()
        dd1.DataStore = dd1_data

        dd2 = DropDown()
        dd2.DataStore = dd2_data

        dd3 = DropDown()
        dd3.DataStore = dd3_data

        dd4 = DropDown()
        dd4.DataStore = dd4_data

        # Cache indexes to avoid unnecessary state updates which can be a bit crashy
        dialog.dd1_index = -1
        dialog.dd2_index = -1
        dialog.dd3_index = -1 #RD
        dialog.dd4_index = -1 #RD

        dialog.busy = False
        def update_state(sender, args):
            # Super safe busy check, prevents recursion!
            if (dialog.busy):
                return
            
            dialog.busy = True
            
            # Prevents crashing if there is no data, we should do this more, but I'm lazy
            if dd1.SelectedIndex == -1:
                return

            if (dd1.SelectedIndex != dialog.dd1_index):

                items1 = data[dd1.SelectedValue]
                
                # Note we don't set a NEW value, we use the same collection
                dd2_data.Clear()
                for i in items1:
                    dd2_data.Add(i)
                dd2.SelectedIndex = 0
                dd3.SelectedIndex = 0
                dd4.SelectedIndex = 0
                dialog.dd2_index = 0

            # This should run on 1 or 2 changing index
            if (dd2.SelectedIndex != dialog.dd2_index or
                dd1.SelectedIndex != dialog.dd1_index):
                items2 = data[dd2.SelectedValue]
                

            

                # Note we don't set a NEW value, we use the same collection
                dd3_data.Clear()
                for i in items2:
                    dd3_data.Add(i)
                dd3.SelectedIndex = 0

            if (dd3.SelectedIndex != dialog.dd3_index or
                dd2.SelectedIndex != dialog.dd2_index or
                dd1.SelectedIndex != dialog.dd1_index):

                dd4_data.Clear()
                if dd3.SelectedValue in data.keys():
                    items3 = data[dd3.SelectedValue]

                    # Note we don't set a NEW value, we use the same collection
                    for i in items3:
                        dd4_data.Add(i)
                    dd4.SelectedIndex = 0

            dialog.dd3_index = dd3.SelectedIndex
            dialog.dd2_index = dd2.SelectedIndex
            dialog.dd1_index = dd1.SelectedIndex

            

            
            # We are no longer busy!
            dialog.busy = False

        dd1.SelectedIndexChanged += update_state
        dd2.SelectedIndexChanged += update_state
        dd3.SelectedIndexChanged += update_state
        dd1.SelectedIndex = 0


        # Create the default button
        dialog.DefaultButton = forms.Button()
        dialog.DefaultButton.Text ='OK'
        #dialog.DefaultButton.Click += dialog.OnOKButtonClick

    
 
        # Create the abort button
        dialog.AbortButton = forms.Button()
        dialog.AbortButton.Text ='Cancel'
        dialog.AbortButton.Click += dialog.OnCloseButtonClick


        # Create a table layout and add all the controls
        #layout = forms.DynamicLayout()
        #layout.Spacing = drawing.Size(5, 5)

        
        # Nice way to set up a UI with equal spacing
        dynamic = forms.DynamicLayout()
        dynamic.Spacing = drawing.Size(4, 4) # Bit cramped otherwise
        dynamic.BeginHorizontal()
        dynamic.Add(dd1, True)
        dynamic.Add(dd2, True)
        dynamic.Add(dd3, True)
        dynamic.Add(dd4, True)
        dynamic.EndHorizontal()
        dynamic.AddRow(None) # spacer
        dynamic.AddRow(dialog.DefaultButton, dialog.AbortButton)

        # Set the dialog content
        #dialog.Content = dynamic
        #dialog.Load += dialog.OnFormLoad
        #dialog.Closing += dialog.OnFormClosing

        dialog.Content = dynamic

        parent = RhinoEtoApp.MainWindowForDocument(sc.doc)
        ##EtoExtensions.ShowSemiModal(dialog, sc.doc, parent)
        dialog.ShowModal(parent)

        # Close button click handler
        def OnCloseButtonClick(dialog, sender, e):
            dialog.Close(False)
    
        # OK button click handler
        def OnOKButtonClick(dialog, sender, e):
            dialog.Close(True)





# The script that will be using the dialog.
def Pipework():
    #rs.CurrentDimStyle("Default")
    
    #Utility function to show the dialog box
    dialog = GeoPipeworkDialog();
    
    #Open the dialogue

    #rc = dialog.ShowModal(Rhino.UI.RhinoEtoApp.MainWindow)
    #if not rc: return




    
    print ("End of Geo Pipework")
# Check to see if this file is being executed as the "main" python
# script instead of being used as a module by some other python script
# This allows us to use the module which ever way we want.
if __name__ == "__main__":
    rc = Pipework()type or paste code here

If you move this section,

        # Close button click handler
        def OnCloseButtonClick(dialog, sender, e):
            dialog.Close(False)
    
        # OK button click handler
        def OnOKButtonClick(dialog, sender, e):
            dialog.Close(True)

above this,

        dialog.AbortButton.Click += dialog.OnCloseButtonClick

and change it to this,

        dialog.AbortButton.Click += OnCloseButtonClick

It then runs nicely for me