Wpf DataGrid IN pyrevit GETS crashed

I am currently working on WPF data grids. I managed to create the basic form with headers, but when I began populating it with some sample data, it crashed, along with Revit.

@J.Sharma If you need specific help, provide details about your issue and a code sample, it does not have to be the whole thing, but enough for us to reproduce and understand your question

from pyrevit import forms
from System.Windows import Window, ResizeMode
from System.Windows.Controls import DataGrid

class SimpleUI(forms.WPFWindow):
    def __init__(self, item_name, value, is_active):
        self.Width = 500
        self.Height = 400
        self.Title = "Simple DataGrid Example"
        self.ResizeMode = ResizeMode.NoResize
        
        self.ItemName = item_name
        self.Value = value
        self.IsActive = is_active
        
        self.datagrid = DataGrid()
        self.Content = self.datagrid
        
        self.populate_data()

    def populate_data(self):
        data = [
            SimpleUI("Item 1", 100, True),
            SimpleUI("Item 2", 200, False),
            SimpleUI("Item 3", 300, True)
        ]
        self.datagrid.ItemsSource = data

# Run the script
if __name__ == '__main__':
    SimpleUI("Default Item Name", 0, False).ShowDialog()

I think you have created an infinite loop, because you are calling SimpleUI inside the populate_data.

Try:

    def populate_data(self):
        data = [
            ItemData("Item 1", 100, True),
            ItemData("Item 2", 200, False),
            ItemData("Item 3", 300, True)
        ]
        self.datagrid.ItemsSource = data

ChatGPT in da house:

It looks like the main issue in your code stems from the way you’re initializing the SimpleUI class within its own populate_data() method, which causes an infinite recursion. When you create instances of SimpleUI inside the populate_data() method, each instance again calls populate_data(), leading to an endless loop of object creation.

You should define a separate data class (or a simple object) for the items that you’re populating in the DataGrid, instead of using the SimpleUI class itself as the data source.

Here’s a corrected version of the code:

from pyrevit import forms
from System.Windows import Window, ResizeMode
from System.Windows.Controls import DataGrid

# Define a class to represent the data for each row
class Item:
    def __init__(self, item_name, value, is_active):
        self.ItemName = item_name
        self.Value = value
        self.IsActive = is_active

class SimpleUI(forms.WPFWindow):
    def __init__(self, item_name, value, is_active):
        self.Width = 500
        self.Height = 400
        self.Title = "Simple DataGrid Example"
        self.ResizeMode = ResizeMode.NoResize
        
        # Store parameters
        self.ItemName = item_name
        self.Value = value
        self.IsActive = is_active
        
        # Initialize the DataGrid
        self.datagrid = DataGrid()
        self.Content = self.datagrid
        
        # Populate the DataGrid with data
        self.populate_data()

    def populate_data(self):
        # Create a list of Item objects to populate the DataGrid
        data = [
            Item("Item 1", 100, True),
            Item("Item 2", 200, False),
            Item("Item 3", 300, True)
        ]
        
        # Set the ItemsSource property of the DataGrid to the list of data
        self.datagrid.ItemsSource = data

# Run the script
if __name__ == '__main__':
    SimpleUI("Default Item Name", 0, False).ShowDialog()

Changes made:

  1. Data Class: Created a new Item class to represent each row of data in the DataGrid.
  2. populate_data method: Replaced SimpleUI instances with Item instances.
  3. Infinite Recursion Fix: Avoided calling SimpleUI recursively inside its own method.

This should fix the issues with your code and properly populate the DataGrid with items.

1 Like

Jean i am getting additional columns init,doc,module

I went super lazy and use chatGPT:
From the screenshot, I see that the columns have been duplicated, which likely stems from two issues:

  1. Auto-Generated Columns: The DataGrid by default automatically generates columns for all public properties of the objects in its ItemsSource. This includes the columns that you have explicitly added in setup_columns, resulting in duplication.

  2. Property Names: The additional columns (__module__, __init__) are still being shown because the DataGrid is automatically generating columns for all properties of the Item class.

To solve this, you need to disable the AutoGenerateColumns property of the DataGrid and rely only on the columns that you explicitly add.

Here’s the updated version of the code:

from pyrevit import forms
from System.Windows import ResizeMode
from System.Windows.Controls import DataGrid, DataGridTextColumn
from System.Windows.Data import Binding

# Define a class to represent the data for each row
class Item:
    def __init__(self, item_name, value, is_active):
        self.ItemName = item_name
        self.Value = value
        self.IsActive = is_active

class SimpleUI(forms.WPFWindow):
    def __init__(self, item_name, value, is_active):
        self.Width = 500
        self.Height = 400
        self.Title = "Simple DataGrid Example"
        self.ResizeMode = ResizeMode.NoResize
        
        # Store parameters
        self.ItemName = item_name
        self.Value = value
        self.IsActive = is_active
        
        # Initialize the DataGrid
        self.datagrid = DataGrid()
        self.datagrid.AutoGenerateColumns = False  # Disable automatic column generation
        self.Content = self.datagrid
        
        # Configure the columns to show only the properties you want
        self.setup_columns()

        # Populate the DataGrid with data
        self.populate_data()

    def setup_columns(self):
        # Create and add columns for the properties you want to display
        name_column = DataGridTextColumn()
        name_column.Header = "Item Name"
        name_column.Binding = Binding("ItemName")
        self.datagrid.Columns.Add(name_column)

        value_column = DataGridTextColumn()
        value_column.Header = "Value"
        value_column.Binding = Binding("Value")
        self.datagrid.Columns.Add(value_column)

        is_active_column = DataGridTextColumn()
        is_active_column.Header = "Is Active"
        is_active_column.Binding = Binding("IsActive")
        self.datagrid.Columns.Add(is_active_column)

    def populate_data(self):
        # Create a list of Item objects to populate the DataGrid
        data = [
            Item("Item 1", 100, True),
            Item("Item 2", 200, False),
            Item("Item 3", 300, True)
        ]
        
        # Set the ItemsSource property of the DataGrid to the list of data
        self.datagrid.ItemsSource = data

# Run the script
if __name__ == '__main__':
    SimpleUI("Default Item Name", 0, False).ShowDialog()

Key Fix:

  1. Disabling Auto-Generated Columns: Set self.datagrid.AutoGenerateColumns = False. This prevents the DataGrid from automatically generating columns for all public properties of the Item class. Now, only the columns defined in the setup_columns() method will be shown.

This should resolve the issue of duplicate columns and unnecessary internal properties showing up in the DataGrid.