Windows Form in Dynamo and IronPython 2.7

Good morning.
I am trying and trying to understand a little about “Forms”.
I have developed the following code in dynamo “PYHTON SCRIPT” of revit 2020 that handles IRON PYTHON 2.7 and so far everything was going well until I am trying to implement in the code the “BOMCOLIST” in each of the cells of the “Covering” column where I can show the default value of the “covering other faces” and when clicking on said cell it shows me the other covering configurations that exist in the document, in this way I can select and change the type of covering through my DATA GRID VIEW.
I share the code that is in dynamo.
Thank you very much for your time.



WindowsForm.dyn (9.9 KB)

Hi,
you need to implement an DataGridViewComboBoxColumn, I recently shared an example of this here

1 Like

I have the following problem:
What happens is that the Data Grid View only shows me 26 elements when I have 400 elements in IN[0]. What is the reason for this?

import clr
import sys
import System
from System.Collections.Generic import List

# Importar Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
import System.Drawing
import System.Windows.Forms

from System.Drawing import *
from System.Windows.Forms import *

clr.AddReference('System.Data')
from System.Data import *

# Importar transactionManager y DocumentManager (RevitServices es específico de Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Obtener el documento actual de Revit
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
sdkNumber = int(app.VersionNumber)

class FormSetWkset2(Form):
    def __init__(self, lst_elems, lst_wkset, recubrimientos, recubrimiento_valores):
        self._lst_wkset = lst_wkset
        self._lst_elems = lst_elems
        self._recubrimientos = recubrimientos
        self._recubrimiento_valores = recubrimiento_valores
        self._set_elemTypeId = set(x.GetTypeId() for x in lst_elems)
        self._lst_elemType = [doc.GetElement(xId) for xId in self._set_elemTypeId if xId != ElementId.InvalidElementId]
        self._wksetTable = doc.GetWorksetTable()
        self._lst_elemType = sorted(self._lst_elemType, key=lambda x: x.FamilyName)
        self._tableDataType = DataTable("ElementType")
        self._tableDataType.Columns.Add("Element", DB.Element)
        self._tableDataType.Columns.Add("FamilyName", System.String)
        self._tableDataType.Columns.Add("Name", System.String)
        self._tableDataType.Columns.Add("Categorie", System.String)
        for x in self._lst_elemType:
            self._tableDataType.Rows.Add(x, x.FamilyName, Element.Name.GetValue(x), x.Category.Name)
        self._tableDataWkset = DataTable("Wkset")
        self._tableDataWkset.Columns.Add("Workset", DB.Workset)
        self._tableDataWkset.Columns.Add("Name", System.String)
        for x in self._lst_wkset:
            self._tableDataWkset.Rows.Add(x, x.Name)
        self.pairLst = []
        self.InitializeComponent()

    def InitializeComponent(self):
        dataGridViewCellStyle11 = System.Windows.Forms.DataGridViewCellStyle()
        self._buttonOK = System.Windows.Forms.Button()
        self._dataGridView1 = System.Windows.Forms.DataGridView()
        self._groupBox1 = System.Windows.Forms.GroupBox()
        self._ComboBoxValue = System.Windows.Forms.DataGridViewComboBoxColumn()
        self._dataGridView1.BeginInit()
        self._groupBox1.SuspendLayout()
        self.SuspendLayout()
        self.Shown += self.Form1_Shown
        self._buttonOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right
        self._buttonOK.Location = System.Drawing.Point(1090, 480)
        self._buttonOK.Name = "buttonOK"
        self._buttonOK.Size = System.Drawing.Size(95, 35)
        self._buttonOK.TabIndex = 2
        self._buttonOK.Text = "OK"
        self._buttonOK.UseVisualStyleBackColor = True
        self._buttonOK.Click += self.ButtonOKClick
        dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft
        dataGridViewCellStyle11.BackColor = System.Drawing.SystemColors.Control
        dataGridViewCellStyle11.Font = System.Drawing.Font("Microsoft Sans Serif", 8.25, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, 0)
        dataGridViewCellStyle11.ForeColor = System.Drawing.SystemColors.WindowText
        dataGridViewCellStyle11.SelectionBackColor = System.Drawing.SystemColors.Highlight
        dataGridViewCellStyle11.SelectionForeColor = System.Drawing.SystemColors.HighlightText
        dataGridViewCellStyle11.WrapMode = getattr(System.Windows.Forms.DataGridViewTriState, "True")
        self._dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle11
        self._dataGridView1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
        self._dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
        self._dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter
        self._dataGridView1.AllowUserToAddRows = False
        self._dataGridView1.Location = System.Drawing.Point(6, 28)
        self._dataGridView1.Name = "dataGridView1"
        self._dataGridView1.Size = System.Drawing.Size(1160, 420)
        self._dataGridView1.TabIndex = 3
        self._dataGridView1.DataSource = self._tableDataType
        self._dataGridView1.DataError += self.DataGridViewError
        self._ComboBoxValue.HeaderText = "Recubrimiento"
        self._ComboBoxValue.Name = "Recubrimiento"
        self._ComboBoxValue.Width = 200
        self._groupBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
        self._groupBox1.Controls.Add(self._dataGridView1)
        self._groupBox1.Location = System.Drawing.Point(12, 12)
        self._groupBox1.Name = "groupBox1"
        self._groupBox1.Size = System.Drawing.Size(1180, 460)
        self._groupBox1.TabIndex = 4
        self._groupBox1.TabStop = False
        self._groupBox1.Text = "Detalles de Elementos"
        self.ClientSize = System.Drawing.Size(1200, 530)
        self.MinimumSize = self.ClientSize + System.Drawing.Size(20, 20)
        self.Controls.Add(self._groupBox1)
        self.Controls.Add(self._buttonOK)
        self.Name = "Form27"
        self.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show
        self.Text = "Asignar Recubrimiento"
        self._dataGridView1.EndInit()
        self._groupBox1.ResumeLayout(False)
        self.ResumeLayout(False)

    def Form1_Shown(self, sender, e):
        self.SetCellComboBoxItems()

    def SetCellComboBoxItems(self):
        self._dataGridView1.Columns.Add(self._ComboBoxValue)
        for i in range(self._dataGridView1.Rows.Count):
            dgvcbc = self._dataGridView1.Rows[i].Cells[4]
            dgvcbc.DataSource = self._recubrimiento_valores
            # Establecer el valor predeterminado de la celda
            dgvcbc.Value = self._recubrimientos[i]
        self._dataGridView1.Columns["Element"].Visible = False
        for idx, col in enumerate(self._dataGridView1.Columns):
            if idx >= 3:
                col.Width = 200
            else:
                col.Width = 250

    def DataGridViewError(self, sender, e):
        print(e.Exception)

    def ButtonOKClick(self, sender, e):
        self.pairLst = []
        for i in range(self._dataGridView1.Rows.Count):
            elem_symbol = self._dataGridView1.Rows[i].Cells[0].Value
            wkset_name = self._dataGridView1.Rows[i].Cells[4].Value
            if elem_symbol is not None and wkset_name is not None:
                strDataExpression = "[Name] = '" + wkset_name + "'"
                filterP = System.Predicate[DataRow](lambda x: x is not None)
                dtRowA = System.Array.Find[DataRow](self._tableDataWkset.Select(strDataExpression), filterP)
                wkset = dtRowA["Workset"]
                if elem_symbol is not None:
                    self.pairLst.append([elem_symbol, wkset])
        self.Close()

lst_Elements = UnwrapElement(IN[0])
lst_Wkset = FilteredWorksetCollector(doc).OfKind(WorksetKind.UserWorkset).ToWorksets()

# Obtener valores de recubrimiento actuales para cada elemento
recubrimientos = []
for e in lst_Elements:
    para = e.get_Parameter(BuiltInParameter.CLEAR_COVER_OTHER)
    recubrimiento = None
    if para is None:
        recubrimiento = "Error"
    else:
        idd = para.AsElementId()
        if idd.IntegerValue == -1:
            recubrimiento = "Sin asignar"
        else:
            rec = doc.GetElement(idd).CoverDistance * 0.3048
            recubrimiento = rec
    recubrimientos.append(recubrimiento)

# Obtener todos los valores posibles de recubrimiento para la lista desplegable
Recubrimientos = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_CoverType)
rec_nombre = []
for i in Recubrimientos:
    nom = i.get_Parameter(BuiltInParameter.COVER_TYPE_NAME).AsString()
    rec_nombre.append(nom)

form = FormSetWkset2(lst_Elements, lst_Wkset, recubrimientos, rec_nombre)
form.ShowDialog()

OUT = form.pairLst

because in this example, I use Elements Type instead of instances

see this lines

Thanks for pointing out the problem, thank you,
Now it happens that I have my form as I wish and the ONLY thing I WANT is to be able to move the Overlay column after Category and when I try to do so it closes or an index error appears… could you please help me with being able to move my column to the position I want? I wish

import clr
import sys
import System
from System.Collections.Generic import List

# Importar Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
import System.Drawing
import System.Windows.Forms

from System.Drawing import *
from System.Windows.Forms import *

clr.AddReference('System.Data')
from System.Data import *

# Importar transactionManager y DocumentManager (RevitServices es específico de Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Obtener el documento actual de Revit
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
sdkNumber = int(app.VersionNumber)

class FormSetCover(Form):
    def __init__(self, lst_elems, recubrimientos, recubrimiento_valores):
        self._lst_elems = lst_elems  # Lista de elementos de Revit
        self._recubrimientos = recubrimientos
        self._recubrimiento_valores = recubrimiento_valores

        # Crear la tabla con las instancias individuales
        self._tableDataType = DataTable("ElementType")
        self._tableDataType.Columns.Add("Element", DB.Element)
        self._tableDataType.Columns.Add("FamilyName", System.String)
        self._tableDataType.Columns.Add("Name", System.String)
        self._tableDataType.Columns.Add("Categorie", System.String)

        # Añadir cada instancia a la tabla
        for elem, rec in zip(self._lst_elems, self._recubrimientos):
            self._tableDataType.Rows.Add(
                elem,
                elem.Symbol.FamilyName if hasattr(elem, "Symbol") else "N/A",
                Element.Name.GetValue(elem),
                elem.Category.Name if elem.Category else "N/A"
            )
        
        self.pairLst = []  # Para almacenar resultados
        self.InitializeComponent()

    def InitializeComponent(self):
        dataGridViewCellStyle11 = System.Windows.Forms.DataGridViewCellStyle()
        self._buttonOK = System.Windows.Forms.Button()
        self._dataGridView1 = System.Windows.Forms.DataGridView()
        self._groupBox1 = System.Windows.Forms.GroupBox()
        self._ComboBoxValue = System.Windows.Forms.DataGridViewComboBoxColumn()

        self._dataGridView1.BeginInit()
        self._groupBox1.SuspendLayout()
        self.SuspendLayout()
        self.Shown += self.Form1_Shown

        # Botón OK
        self._buttonOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right
        self._buttonOK.Location = System.Drawing.Point(1090, 480)
        self._buttonOK.Name = "buttonOK"
        self._buttonOK.Size = System.Drawing.Size(95, 35)
        self._buttonOK.TabIndex = 2
        self._buttonOK.Text = "OK"
        self._buttonOK.UseVisualStyleBackColor = True
        self._buttonOK.Click += self.ButtonOKClick

        # Configuración de DataGridView
        dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft
        dataGridViewCellStyle11.BackColor = System.Drawing.SystemColors.Control
        dataGridViewCellStyle11.Font = System.Drawing.Font("Microsoft Sans Serif", 8.25, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, 0)
        dataGridViewCellStyle11.ForeColor = System.Drawing.SystemColors.WindowText
        dataGridViewCellStyle11.SelectionBackColor = System.Drawing.SystemColors.Highlight
        dataGridViewCellStyle11.SelectionForeColor = System.Drawing.SystemColors.HighlightText
        dataGridViewCellStyle11.WrapMode = getattr(System.Windows.Forms.DataGridViewTriState, "True")
        self._dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle11
        self._dataGridView1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
        self._dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
        self._dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter
        self._dataGridView1.AllowUserToAddRows = False
        self._dataGridView1.Location = System.Drawing.Point(6, 28)
        self._dataGridView1.Name = "dataGridView1"
        self._dataGridView1.Size = System.Drawing.Size(1160, 420)
        self._dataGridView1.TabIndex = 3
        self._dataGridView1.DataSource = self._tableDataType
        self._dataGridView1.DataError += self.DataGridViewError

        # Añadir la columna ComboBox
        self._ComboBoxValue.HeaderText = "Recubrimiento"
        self._ComboBoxValue.Name = "Recubrimiento"
        self._ComboBoxValue.Width = 200
        self._ComboBoxValue.DataSource = self._recubrimiento_valores
        self._dataGridView1.Columns.Add(self._ComboBoxValue)

        # Grupo para DataGridView
        self._groupBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
        self._groupBox1.Controls.Add(self._dataGridView1)
        self._groupBox1.Location = System.Drawing.Point(12, 12)
        self._groupBox1.Name = "groupBox1"
        self._groupBox1.Size = System.Drawing.Size(1180, 460)
        self._groupBox1.TabIndex = 4
        self._groupBox1.TabStop = False
        self._groupBox1.Text = "Detalles de Elementos"

        # Configuración de la ventana principal
        self.ClientSize = System.Drawing.Size(1200, 530)
        self.MinimumSize = self.ClientSize + System.Drawing.Size(20, 20)
        self.Controls.Add(self._groupBox1)
        self.Controls.Add(self._buttonOK)
        self.Name = "Form27"
        self.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show
        self.Text = "Asignar Recubrimiento"

        self._dataGridView1.EndInit()
        self._groupBox1.ResumeLayout(False)
        self.ResumeLayout(False)

    def Form1_Shown(self, sender, e):
        self.SetCellComboBoxItems()

    def SetCellComboBoxItems(self):
        for i in range(self._dataGridView1.Rows.Count):
            dgvcbc = self._dataGridView1.Rows[i].Cells["Recubrimiento"]
            dgvcbc.Value = self._recubrimientos[i]
        self._dataGridView1.Columns["Element"].Visible = False

    def DataGridViewError(self, sender, e):
        print(e.Exception)

    def ButtonOKClick(self, sender, e):
        self.pairLst = [
            [self._dataGridView1.Rows[i].Cells[0].Value, self._dataGridView1.Rows[i].Cells["Recubrimiento"].Value]
            for i in range(self._dataGridView1.Rows.Count)
            if self._dataGridView1.Rows[i].Cells["Recubrimiento"].Value is not None
        ]
        self.Close()

# Lista de elementos y valores de recubrimiento actuales
lst_Elements = UnwrapElement(IN[0])

# Obtener valores de recubrimiento actuales en los elementos los cuales se deberan de mostrar por defectos una vez se inicie la ejecucion del codigo
Recu_actual = []
for e in lst_Elements:
    para = e.get_Parameter(BuiltInParameter.CLEAR_COVER_OTHER)
    recubrimiento = None
    if para is None:
        recubrimiento = "Error"
    else:
        idd = para.AsElementId()
        if idd.IntegerValue == -1:
            recubrimiento = "Sin asignar"
        else:
            rec = doc.GetElement(idd)
            nom = rec.get_Parameter(BuiltInParameter.COVER_TYPE_NAME).AsString()
            recubrimiento = nom
    Recu_actual.append(recubrimiento)

# Obtener todos los valores posibles de recubrimiento en el documento
todos_recubrimientos = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_CoverType).ToElements()
recu_valores = [r.get_Parameter(BuiltInParameter.COVER_TYPE_NAME).AsString() for r in todos_recubrimientos]

form = FormSetCover(lst_Elements, Recu_actual, recu_valores)
form.ShowDialog()

OUT = form.pairLst

Add the DataGridViewComboBoxColumn after the DataGridView generation

Following the recommendation, I have placed the line of code but it has returned an error and at the same time you can see that the “Coating” columna has not moved.

did you remove this one?

The DataGridViewComboBoxColumn (self._ComboBoxValue) can only be added once (in SetCellComboBoxItems method)

as an alternative, you can also try WPF + MVVM

1 Like

Good day
Could you recommend how I can learn from scratch to work with WindowsForm and IronPython so I can see what things I can do or what you would recommend. I am very interested in creating this type of windows and even much more personalized and advanced ones.

here’s an example of a course, but it’s quite old

https://www.udemy.com/course/windows-programming-with-ironpython