I'm trying to create a Sheet generator in Revit, using Pyrevit Add in.
So by using Ironpython and WPF, I managed to create a datagrid with multiple combobox columns.
However, for the tool to be efficient, I want it to be able to select multiple rows and then with a change in one combo box, it applies that value to all the combo boxes down the column.
I tried setting the value in my python code.... I'm getting the print statements, but the values don't reflect/update in the datagrid.
Here's my code
class SheetData(object):
def __init__(self, sheet_name, sheet_number, levels, scope_boxes, view_types, view_templates):
self.SheetName = str(sheet_name)
self.SheetNumber = str(sheet_number)
self.Levels = levels
self.ScopeBoxes = list(scope_boxes) if scope_boxes else ["None"]
self.ViewTypes = view_types
self.ViewTemplates = list(view_templates.keys()) if view_templates else ["None"]
# Assign default values safely
self.SelectedLevel = self.get_best_matching_level() or self.Levels[0]
self.SelectedScopeBox = self.ScopeBoxes[0]
self.SelectedViewType = ""
self.SelectedViewTemplate = self.ViewTemplates[0]
def get_best_matching_level(self):
if not self.Levels:
return None
sheet_lower = self.SheetName.lower()
for level in self.Levels:
if any(word in sheet_lower for word in level.lower().split()):
return level # Return the first matching level
return None # No match found
class SheetListWindow(Window):
def __init__(self, sheet_names, sheet_numbers, levels, scope_boxes, view_types, view_templates):
xamlfile = script.get_bundle_file('ui2.xaml')
wpf.LoadComponent(self, xamlfile)
temp_list = List[SheetData]()
for name, number in zip(sheet_names, sheet_numbers):
temp_list.Add(SheetData(name, number, levels, scope_boxes, view_types, view_templates))
self.sheet_data_list = ObservableCollection[SheetData](temp_list)
self.sheets_lb.ItemsSource = self.sheet_data_list
@property
def selected_sheets(self):
return self.sheets_lb.SelectedItems
def ComboBox_SelectionChanged(self, sender, e):
# Temporarily disconnect event handler
sender.SelectionChanged -= self.ComboBox_SelectionChanged
selected_item = sender.SelectedItem
if selected_item:
print("New View Type Selected: {}".format(selected_item))
for sheet in self.selected_sheets:
if sheet.SelectedViewType != selected_item: # Prevent unnecessary updates
sheet.SelectedViewType = selected_item
print("Updated Sheet: {} -> {}".format(sheet.SheetName, selected_item))
# Reconnect event handler
sender.SelectionChanged += self.ComboBox_SelectionChanged
And here's my XAML.
<Window xmlns=";
xmlns:x=";
Title="Sheet List" Height="600" Width="1200"
WindowStartupLocation="CenterScreen"
Background="#f7f7f7"
ResizeMode="CanResizeWithGrip">
<Grid Margin="10">
<DataGrid x:Name="sheets_lb"
AutoGenerateColumns="False"
Margin="10,0,10,10"
BorderThickness="1"
RowHeaderWidth="0"
CanUserSortColumns="True"
HorizontalGridLinesBrush="#dedede"
VerticalGridLinesBrush="#dedede"
EnableColumnVirtualization="True"
EnableRowVirtualization="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling">
<DataGrid.Columns>
<DataGridTextColumn Header="Sheet Name"
Binding="{Binding SheetName}"
MinWidth="150"/>
<DataGridTextColumn Header="Sheet Number"
Binding="{Binding SheetNumber}"
MinWidth="100"/>
<DataGridTemplateColumn Header="Level" MinWidth="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Levels}"
SelectedItem="{Binding SelectedLevel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Padding="4"
BorderThickness="1"
BorderBrush="#ccc"
Background="White"
VerticalContentAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Scope Box" MinWidth="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ScopeBoxes}"
SelectedItem="{Binding SelectedScopeBox}"
Padding="4"
BorderThickness="1"
BorderBrush="#ccc"
Background="White"
VerticalContentAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="View Type" MinWidth="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name = "viewtype_cb" ItemsSource="{Binding ViewTypes}"
SelectedItem="{Binding SelectedViewType, Mode=TwoWay}"
Padding="4"
BorderThickness="1"
BorderBrush="#ccc"
Background="White"
VerticalContentAlignment="Center"
SelectionChanged="ComboBox_SelectionChanged"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="View Template" MinWidth="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ViewTemplates}"
SelectedItem="{Binding SelectedViewTemplate}"
Padding="4"
BorderThickness="1"
BorderBrush="#ccc"
Background="White"
VerticalContentAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>