Summary
Populate ListBox in WPF
Our WPF form is keep improving with each lesson, and now it's finally time to address <ListBox>.
For me personally, <ListBoxes>
were the main reason why I decided to learn WPF in the first place and I struggled with them a lot on my own. I had to try a lot of different ways and learn the hard way.
So, I want to teach you how to correctly work with <ListBox>
, so you can:
Add Revit API elements to choose from
Add
<CheckBoxes>
for user selectionGet Selected Elements
Create Interactive Select Buttons for ListBox
It's a bit tricky topic if you don't know where to start, but I will make sure that you know how to do it correctly from the beginning.
So, let's open Visual Studio and begin this lesson.
Setting Up the Project
Same as before I will begin by duplicating the code from previous code.
You can continue with your own code, or here is a copy so you can follow along from the previous lesson:
XAML
Python
Accessing the ListBox in Python Code
First of all, let's get the <ListBox>
in our python code. This control already has the x:Name
assigned from the previous lesson, so it will be easy to get it.
We will be able to get it inside our WPF class by using self.UI_listbox
Getting All Views from Revit API
Before we continue, we need to get some elements that we want to populate inside the <ListBox>
. I will get views with FilteredElementCollector
since it's quite easy to work with.
Also keep in mind that we might want to filter out Views from ViewTemplates.
This will get us a list of all Views.
Now, it's good idea to sort them in a dictionary, so we will have our view name as a key and the view itself as a value. This makes it easy to display and get correct items.
💡Also it's good to include ViewType
as part of the key since we can have the same View.Name
``for different view types like Ceiling, Floor, Area, Structural…
I will do that with dictionary comprehension to fit it in one-line. I highly recommend to get comfortable using comprehensions in python.
You can ask ChatGPT to break it down into multiple lines if you need to.
At this point, ensure that you are getting the right elements with your code by just printing the contents of your dictionary.
💡As you've seen in the video, even I made a typo here and didn't get any elements because I rushed. So, test if you get the right elements.
Populating the ListBox with Views
Now let's populate these items in our <ListBox>
.
To organize our code better we are going to create a separate method to make it more maintainable.
1️⃣ Firstly, since we used placeholders in the XAML code, it's good idea to Clear()
all the items from the <ListBox>
in case you forget to remove them.
2️⃣ Secondly, we need to create a <ListBoxItem>
that will be added to the list and we can provide the name of the view as its Content
.
Here is the code:
Also make sure you import WPF controls in your code.
Also make sure you import WPF controls in your code.
Testing the Code
Now it's a good step to test your code and see if you misspelled anything or everything works exactly like it should.
At this point you should see a form like this with View names inside the list. That's already a good progress but we are just getting started with this <ListBox>
.
Get Selected Item
Before we go too far, let me show you how would you get your selection from the current <ListBox>
, because later we will use another method for getting selection.
At this point we can easily reference the ListBox itself and look at its SelectedItem
property. And it will return you the <ListBoxItem>
You can add this part to your UIe_btn_run
handler.
Add CheckBoxes to ListBoxItems
Now in our case we want to do thing a little bit different.
Firstly, I want users to be able to select multiple options, and the best way to do that is to add <CheckBox>
for the <ListBoxItems>.
And to do that we will literally create a checkbox inside of the listbox item like this:
Now we need to do the same but in the python code.
We will do the following:
Clear
ListBox
Create
Checkbox
Store
View.Name
and theView
insideCheckBox
Add
CheckBox
insideListBoxItem
Add
ListBoxItem
to theListBox
.
Here is the code to do all that:
💡Notice that I use Tag
property to store an actual View
in the back-end.
This will be useful later on when we will be getting selected elements. Tag
property can be used to store any data you want without showing it to the user in the front-end.
And this should give you the following result:
How to get selected items?
Now let me show you how to get selected items. There are different ways to do that, and since we've added checkboxes, we need to reverse engineer the logic to check what was selected by the user.
We will just read in the reverse order how we added items:ListBox
-> Items
Property -> ListBoxItem
-> CheckBox
-> IsChecked
Property -> Tag
Property.
For now let's add the code inside the run button so we can get results when we submit the form.
This code will iterate through all the items inside the ListBox
and check what was selected by the user.
And if any item was selected we will get the view from Tag
property, which we used as a storage container and add it to the selected_views
list.
And this is what I see when I test this snippet:
Solving the Underscore Issue
During this lesson we've encountered a bug where underscores '_' have disappeared from front-end names in the form. That's an annoying bug when you put text in CheckBox.Content
.
There is a workaround by actually creating a TextBlock
control with the name and then adding this TextBlock
as a CheckBox.Content
.
It might sound confusing, but it's just one more step. Here is the code to solve this issue:
💡This will solve this bug with disappearing underscores '_'.
Create @property for Selected Items
Let's clean up the code a little and move the code for getting selected elements.
Similar to previous lessons, we will create a @property
to get selected items outside of class easier.
We just need to move the same code we wrote inside the Submit button.
Adding 'Select All' and 'Select None' Buttons
Lastly, let's also make [Select All] and [Select None] buttons work since they are made specifically for this <ListBox>
Firstly, we need to specify the Event in the XAML code for these buttons.
Then same as other Event Triggers, we need to create EventHandler methods in your class. And let's write logically the steps how these buttons should work:
Iterate through all Items in
<ListBox>
Get the
<CheckBox>
Set
IsChecked
Property to True/False
💡Also since it's the same logic, I will create a reusable method and only provide True/False argument depending on the EventHandler.
Here is the code:
And here is the final test in Revit.
Conclusion
Alright this was a big lesson, but hopefully you've learnt a lot of useful information.
By now you should know how to work with <ListBox>
control and how to populate any data you need inside of it. Also you've learnt how to add <CheckBoxes>
for multiple selection and how to get selected items out of your form.
This alone is what will allow you to create extremely powerful custom WPF forms.
Homework
But as you remember, the best way of learning anything is by doing.
So for your homework, firstly follow me along and just do what I did here in this lesson. And then I want you to try with other elements, try experimenting a little bit more.
Try to put your wall types or group names or window types inside the list box and try to get these values out of there. Whatever you feel is more relevant to you and your discipline.
And trust me, you will love list boxes once you will do it on your own. And if you have any issues, ask the community or ChatGPT.
And once you finish with your homework, you're ready for the next lesson. And we'll again focus on the list boxes, but this time we'll make it even more versatile by implementing a really powerful search text box. This will help you to sort the right elements and provide far better user experience.
I'll see you in the next lesson and I'll wish you Happy Coding.