Hi All, @c.poupin
Referring to my post Set footings Type using WPF - #7 by REDO10, I’m following the same logic to implement a tool that allows assigning a ColumnType
instance to each created column at each level.
When I click the Add Type
button to add an instance, new instances are add to LstTypes
and this later is updated, as shown in the console print below. However, I’m facing an issue in the XAML part, where I’m struggling to correctly bind LstTypes
to the ComboBoxes in each level tab within the DataGrid, where the added instances are not displayed in the view.
here my code:
Columns.7z (1.6 KB)
columns
import clr
import sys
sys.path.append(r"C:\Users\nono\OneDrive\Desktop\Columns\lib")
import System
import math
from System import Array
from System.Collections.Generic import List, KeyValuePair
from System.Collections.ObjectModel import ObservableCollection
# Import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB.Structure import StructuralType
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
clr.AddReference("IronPython.Wpf")
clr.AddReference('System.Core')
clr.AddReference('System.Xml')
clr.AddReference('PresentationCore')
clr.AddReference('PresentationFramework')
clr.AddReference('System.Windows.Forms') # For MessageBox
from System.IO import StringReader
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
from System.ComponentModel import INotifyPropertyChanged
from System.ComponentModel import PropertyChangedEventArgs
from System.Windows import Window
from System.Windows.Forms import MessageBox
import wpf
import itertools
import traceback
from _mySymbols import ColumnType
from _myMaterials import ConcreteMaterial, get_or_create_concrete_material
class ViewModelBase(INotifyPropertyChanged):
def __init__(self):
self._property_changed = None
def add_PropertyChanged(self, handler):
self._property_changed = handler
def remove_PropertyChanged(self, handler):
self._property_changed = None
def notify_property_changed(self, property_name):
if self._property_changed:
self._property_changed(self, PropertyChangedEventArgs(property_name))
class Columns_VM(ViewModelBase):
def __init__(self, level, symbols):
super(Columns_VM, self).__init__()
self._level = level
self._symbols = ObservableCollection[str](symbols)
self._types = ObservableCollection[ColumnType]()
default_type = ColumnType(0, 0)
self._types.Add(default_type)
self.notify_property_changed('LstTypes')
self._selected_type = default_type
self._assignments = {sym: default_type for sym in symbols}
@property
def Level(self):
return self._level
@property
def Symbols(self):
return self._symbols
@property
def LstTypes(self):
return self._types
@property
def SelectedType(self):
return self._selected_type
@property
def Assignments(self):
return self._assignments
@SelectedType.setter
def SelectedType(self, value):
self._selected_type = value
self.notify_property_changed('SelectedType')
def AddType(self, column_type):
if column_type not in self._types:
self._types.Add(column_type)
self.notify_property_changed('LstTypes')
def AssignTypeToSymbol(self, symbol, column_type):
if symbol in self._assignments:
self._assignments[symbol] = column_type
self.notify_property_changed('Assignments')
def _grids_symbols():
symbols = []
grids = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Grids) \
.WhereElementIsNotElementType().ToElements()
for gd_a, gd_b in itertools.combinations(grids, 2):
symA = gd_a.Name
symB = gd_b.Name
if gd_a.Curve.Intersect(gd_b.Curve) == SetComparisonResult.Overlap:
if symA.isalpha() and symB.isdigit():
symbol = "{}-{}".format(symA, symB)
symbols.append(symbol)
else:
symbol = "{}-{}".format(symB, symA)
symbols.append(symbol)
return sorted(symbols)
class MyWindow(Window):
xaml_str = '''
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Columns"
Height="Auto" Width="470"
SizeToContent="Height"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Dimension Input -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
<Label Content="Dimensions (cm):" VerticalAlignment="Center"/>
<TextBox x:Name="dim1_value" Width="50" Margin="5,0"/>
<Label Content="x" VerticalAlignment="Center"/>
<TextBox x:Name="dim2_value" Width="50" Margin="5,0"/>
<Button Content="Add Type" Click="btnAdd_Click" Margin="10,0" Padding="10,2"/>
</StackPanel>
<!-- Level Tabs -->
<TabControl x:Name="tab_control" Grid.Row="1">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Level.Name}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Symbols}"
AutoGenerateColumns="False"
CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Grid Intersection"
Binding="{Binding}"
Width="*"/>
<DataGridTemplateColumn Header="Column Type" Width="2*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding LstTypes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Assignments[.], Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
<!-- Action Buttons -->
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Apply" Click="btnApply_Click" Width="80" Margin="0,0,10,0"/>
<Button Content="Close" Click="btnClose_Click" Width="80"/>
</StackPanel>
</Grid>
</Window>
'''
def __init__(self):
wpf.LoadComponent(self, StringReader(MyWindow.xaml_str))
self.DataLevels = ObservableCollection[Columns_VM]()
levels = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels) \
.WhereElementIsNotElementType().ToElements()
for level in sorted(levels, key=lambda l: l.Elevation):
self.symbols = _grids_symbols()
vm = Columns_VM(level, self.symbols)
self.DataLevels.Add(vm)
self.DataContext = self
self.tab_control.ItemsSource = self.DataLevels
def btnAdd_Click(self, sender, e):
try:
d1 = float(self.dim1_value.Text)
d2 = float(self.dim2_value.Text)
new_type = ColumnType(d1, d2)
for vm in self.DataLevels:
vm.AddType(new_type)
#vm.notify_property_changed('LstTypes')
print("Final LstTypes:", [t.Name for t in self.DataLevels[0].LstTypes])
self.dim1_value.Clear()
self.dim2_value.Clear()
except ValueError:
forms.alert("Please enter valid numeric values")
def btnApply_Click(self, sender, e):
pass
def btnClose_Click(self, sender, e):
self.Close()
column = MyWindow()
column.ShowDialog()
OUT = 0
Thanks.