Hi,
just for the challenge and fun
here is a solution with WPF + MVVM (with Revit 2025-2026 + PythonNet3),
import clr
import sys
import System
from System import Array
from System.Collections.Generic import List, IList, Dictionary
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
clr.AddReference('RevitAPIUI')
import Autodesk.Revit.UI as RUI
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
#Get Important vars
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
clr.AddReference("System.Xml")
clr.AddReference("PresentationFramework")
clr.AddReference("System.Xml")
clr.AddReference("PresentationCore")
clr.AddReference("System.Windows")
import System.Windows.Controls
from System.Windows.Controls import *
from System.IO import StringReader
from System.Xml import XmlReader
from System.Windows import LogicalTreeHelper
from System.Windows.Markup import XamlReader, XamlWriter
from System.Windows import Window, Application
from System.ComponentModel import INotifyPropertyChanged, PropertyChangedEventArgs
from System.ComponentModel import INotifyPropertyChanged, PropertyChangedEventArgs, ICollectionView
from System.Windows.Data import CollectionViewSource, CollectionView
import time
import traceback
import itertools
def get_LevelId(item):
val = None
if hasattr(item, "LevelId"):
return item.LevelId
if hasattr(item, "Level"):
val = item.Level
if val: return val.Id
if hasattr(item, "GenLevel"):
val = item.GenLevel
if val: return val.Id
if not val:
try: return item.get_Parameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM).AsElementId()
except:
try: return item.get_Parameter(BuiltInParameter.INSTANCE_SCHEDULE_ONLY_LEVEL_PARAM).AsElementId()
except: return ElementId.InvalidElementId
class ViewModel3(INotifyPropertyChanged):
__namespace__ = "ViewModel3_jAGfZcdpD" # rename it each edition class
def __init__(self, lst_elems, lst_lvl):
super().__init__()
self._lst_lvl = List[DB.Level]([x for x in lst_lvl])
self._SelectLvl = None
#
self._lst_elem = ObservableCollection[DB.Element](lst_elems)
# Create collection view for filtering
self._filteredItems = CollectionViewSource.GetDefaultView(self._lst_elem)
self._filteredItems.Filter = System.Predicate[System.Object](self.FilterItems)
#
self._property_changed_handlers = []
@clr.clrproperty(List[DB.Level])
def Levels(self):
return self._lst_lvl
def get_SelectLvl(self):
return self._SelectLvl
def set_SelectLvl(self, value):
try:
self._SelectLvl = value
self.OnPropertyChanged("SelectLvl")
self._filteredItems.Refresh()
except Exception as ex:
print(traceback.format_exc())
# Add SelectValue as a clr property
SelectLvl = clr.clrproperty(DB.Level, get_SelectLvl, set_SelectLvl)
@clr.clrproperty(ICollectionView)
def LstItems(self):
return self._filteredItems
def FilterItems(self, item):
"""Filters ComboBox items based on SearchText"""
try:
item_lvlId = get_LevelId(item)
if self._SelectLvl is not None:
return item_lvlId == self._SelectLvl.Id
else:
return True
except Exception as ex:
print(traceback.format_exc())
return True
def OnPropertyChanged(self, property_name):
event_args = PropertyChangedEventArgs(property_name)
for handler in self._property_changed_handlers:
handler(self, event_args)
# Implementation of add/remove_PropertyChanged
def add_PropertyChanged(self, handler):
if handler not in self._property_changed_handlers:
self._property_changed_handlers.append(handler)
def remove_PropertyChanged(self, handler):
if handler in self._property_changed_handlers:
self._property_changed_handlers.remove(handler)
class MainWindow(Window):
string_xaml = '''
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="Select Items" Width="520" Height="520"
WindowStartupLocation="CenterScreen">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<GroupBox Header="Select Level" Grid.Row="0" Margin="0,0,0,8">
<ComboBox x:Name="cbLvl" MinWidth="240" Margin="8"
ItemsSource="{Binding Levels}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectLvl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</GroupBox>
<ListView Name="checkedListBox1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
SelectionMode="Extended"
ItemsSource="{Binding LstItems}"
Grid.Row="1" Margin="5,5,5,5">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<CheckBox Name="familyCheck" VerticalAlignment="Center" Margin="0,0,0,0"
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}">
<CheckBox.Content>
<TextBlock>
<Run Text="Id : " />
<Run Text="{Binding Id.Value, Mode=OneWay, StringFormat=\{0\}}" />
<Run Text="-" />
<Run Text="{Binding Name}" />
</TextBlock>
</CheckBox.Content>
</CheckBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button x:Name="btnSelect" Grid.Row="2" Content="Select Checked Items" HorizontalAlignment="Right" Width="180" />
</Grid>
</Window>'''
def __init__(self,lst_Elems):
super().__init__()
self._lst_elems = lst_Elems
self._lst_lvls = FilteredElementCollector(doc).OfClass(DB.Level).WhereElementIsNotElementType()\
.OrderBy[DB.Element, System.Double](System.Func[DB.Element, System.Double](lambda x : x.ProjectElevation))\
.ToList()
#
xr = XmlReader.Create(StringReader(MainWindow.string_xaml))
self.winLoad = XamlReader.Load(xr)
#
self.vm = ViewModel3( self._lst_elems, self._lst_lvls)
self.InitializeComponent()
def InitializeComponent(self):
try:
self.winLoad.DataContext = self.vm
#
self.checkedListBox1 = LogicalTreeHelper.FindLogicalNode(self.winLoad, "checkedListBox1")
self.btnSelect = LogicalTreeHelper.FindLogicalNode(self.winLoad, "btnSelect")
self.btnSelect.Click += self.ButtonOKClick
#
except Exception as ex:
print(traceback.format_exc())
def ButtonOKClick(self, sender, e):
try:
selectIds = List[ElementId]([x.Id for x in self.checkedListBox1.SelectedItems])
uidoc.Selection.SetElementIds(selectIds)
except Exception as ex:
print(traceback.format_exc())
lst_Elems = List[DB.Element](UnwrapElement(IN[0]))
lst_Elems = lst_Elems.OrderBy[DB.Element, System.String](System.Func[DB.Element, System.String](lambda x : x.Name)).ToList()
objWindow = MainWindow(lst_Elems)
objWindow.winLoad.Show()
OUT = 0
This solution will probably seem complicated to beginners