WPF Sample Form

Here is another form I created as an example in WPF Course:


Intro

Create the following files:

  • script.py

  • FormUI.xaml


Python

# -*- coding: utf-8 -*-
__title__   = "Code Samples: WPF Form Sample"
__doc__ = """Version = 1.0
Date    = 15.07.2024
_____________________________________________________________________
Description:
Example of using WPF Form.
Keep in mind that WPF forms need a .xaml file that has the form design.
_____________________________________________________________________
How-To:
- Click the Button
_____________________________________________________________________
Last update:
- [15.07.2024] - V1.0 RELEASE
_____________________________________________________________________
Author: Erik Frits from LearnRevitAPI.com"""


# ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗╔═╗
# ║║║║╠═╝║ ║╠╦╝ ╚═╗
# ╩╩ ╩╩  ╚═╝╩╚═ ╚═╝ IMPORTS
#====================================================================================================
from Autodesk.Revit.DB import *
from pyrevit import forms   # By importing forms you also get references to WPF package! Very IMPORTANT
import wpf, os, clr         # wpf can be imported only after pyrevit.forms!

# .NET Imports
clr.AddReference("System")
from System.Collections.Generic import List
from System.Windows import Application, Window, ResourceDictionary
from System.Windows.Controls import CheckBox, Button, TextBox, ListBoxItem



# ╦╔═╗╦═╗╦╔═╗╔╗ ╔═╗╔═╗
# ╚╗╔╝╠═╣╠╦╝║╠═╣╠╩╗║  ║╣ ╚═╗
#  ╚╝ ╩╩╚═╩╩ ╩╚═╝╩═╝╚═╝╚═╝ VARIABLES
#====================================================================================================
PATH_SCRIPT = os.path.dirname(__file__)
uidoc   = __revit__.ActiveUIDocument
app     = __revit__.Application
doc     = __revit__.ActiveUIDocument.Document #type: Document




# ╔═╗╦  ╔═╗╔═╗╔═╗╔═╗╔═╗
# ╠═╣╚═╗╚═╗║╣ ╚═╗
# ╚═╝╩═╝╩ ╩╚═╝╚═╝╚═╝╚═╝
#====================================================================================================
class ListItem:
    """Helper Class for defining items in the ListBox."""
    def __init__(self,  Name='Unnamed', element = None, checked = False):
        self.Name       = Name
        self.IsChecked  = checked
        self.element    = element

    def __str__(self):
        return self.Name

# ╔╦╗╔═╗╦╔╗╔  ╔═╗╔═╗╦═╗╔╦╗
# ║║║╠═╣║║║║  ╠╣ ║╠╦╝║║║
# ╩╩ ╩╩╝╚╝  ╚═╝╩╚═╩ MAIN FORM
#====================================================================================================
class SimpleForm(Window):

    def __init__(self):
        # Connect to .xaml File (in same folder)
        path_xaml_file = os.path.join(PATH_SCRIPT, 'FormUI.xaml')
        wpf.LoadComponent(self, path_xaml_file)

        # Define items for ListBox
        self.items = self.generate_listbox_items()
        self.UI_listbox.ItemsSource = self.items

        # Show Form
        self.ShowDialog()


    # ╔╦╗╔═╗╔╦╗╦ ╦╔═╗╔╦╗╔═╗
    # ║║║║╣  ╠═╣║ ║║╚═╗
    # ╩╚═╝ ╩╚═╝═╩╝╚═╝
    def generate_listbox_items(self):
        """Function to create a ICollection to pass to ListBox in GUI"""
        # Define Elements for ListBox (WallTypes)
        wall_types      = FilteredElementCollector(doc).OfClass(WallType).ToElements()
        dict_wall_types = {Element.Name.GetValue(wt): wt for wt in wall_types}

        # check_box = False
        # for item_name, item in sorted(dict_wall_types.items()):
        #     check_box = CheckBox(Content=item_name)
        #     list_box_item = ListBoxItem(Content=check_box)
        #     self.UI_listbox.Items.Add(list_box_item)


        # # Prepare List of Items
        # list_of_items = List[type(ListBoxItem())]()
        # for item_name, item in sorted(dict_wall_types.items()):
        #
        #
        #     list_of_items.Add(ListBoxItem(Content=item_name, ))

        # Prepare List of Items
        list_of_items = List[type(ListItem())]()
        for item_name, item in sorted(dict_wall_types.items()):
            list_of_items.Add(ListItem(item_name, item, False))

        return list_of_items



    # ╔═╗╦═╗╔═╗╔═╗╔═╗╦═╗╔╦╗╦╔═╗╔═╗
    # ╠═╝╠╦╝║ ║╠═╝║╣ ╠╦╝ ║║╣ ╚═╗
    # ╩╚═╚═╝╩  ╚═╝╩╚═ ╩╚═╝╚═╝
    #====================================================================================================
    ef_comment = """You can access all the components in your .xaml form by their x:Name property"""

    # Read Textboxes and Checkboxes values from Form

    @property
    def textbox_1(self):
        return self.UI_textbox_1.Text

    @property
    def textbox_2(self):
        return self.UI_textbox_2.Text

    @property
    def checkbox_1(self):
        return self.UI_checkbox_1.IsChecked

    @property
    def checkbox_2(self):
        return self.UI_checkbox_2.IsChecked

    @property
    def checkbox_3(self):
        return self.UI_checkbox_3.IsChecked


    @property
    def search(self):
        return self.UI_search.IsChecked


    # ╔═╗╦  ╦╔═╗╔╗╔╔╦╗╔═╗
    # ║╣ ╚╗╔╝║╣ ║║║ ╚═╗
    # ╚═╝ ╚╝ ╚═╝╝╚╝ ╚═╝
    #====================================================================================================
    def UIe_search_changed(self, sender, e):
        """Function to filter items in the main_ListBox."""
        filtered_list_of_items = List[type(ListItem())]()
        filter_keyword = self.UI_search.Text

        #RESTORE ORIGINAL LIST
        if not filter_keyword:
            self.UI_listbox.ItemsSource = self.items
            return

        # FILTER ITEMS
        for item in self.items:
            if filter_keyword.lower() in item.Name.lower():
                filtered_list_of_items.Add(item)

        # UPDATE LIST OF ITEMS
        self.UI_listbox.ItemsSource = filtered_list_of_items


    # ╔╗ ╦╔╦╗╔╦╗╔═╗╔╗╔╔═╗
    # ╠╩╗║ ║║║║╚═╗
    # ╚═╝╚═╝ ╚═╝╝╚╝╚═╝ BUTTONS
    #==================================================
    def UIe_button_run(self, sender, e):
        """Button action: Rename view with given """
        self.Close()
        # You can do something here when button is clicked



# ╦╔═╗╔═╗  ╔═╗╔═╗╦═╗╔╦╗
# ║╚═╗║╣   ╠╣ ║╠╦╝║║║
# ╚═╝╚═╝╚═╝  ╚═╝╩╚═╩ 


# Show form to the user
UI = SimpleForm()

# Read Form Values


text_1 = UI.textbox_1
text_2 = UI.textbox_2

check_1 = UI.checkbox_1
check_2 = UI.checkbox_2
check_3 = UI.checkbox_3

sel_combo_item   = UI.UI_combobox.SelectedItem

text_search      = UI.UI_search.Text
sel_listbox_item = UI.UI_listbox.SelectedItem

# Print Results

from pyrevit import script
output = script.get_output()

output.print_md('## Selected Values in EF-WPF Form:')
output.print_md('**TextBox 1:** {}'.format(text_1))
output.print_md('**TextBox 2:** {}'.format(text_2))

output.print_md('**CheckBox 1:** {}'.format(check_1))
output.print_md('**CheckBox 2:** {}'.format(check_2))
output.print_md('**CheckBox 3:** {}'.format(check_3))

output.print_md('**ComboBox Selected Item:** {}'.format(sel_combo_item))

output.print_md('**Search TextBox:** {}'.format(text_search))
output.print_md('**ListBox Selected Item:** {}'.format(sel_listbox_item))

XAML

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:av="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="av"
        Title="EF-WPF Sample Form" 
        Height="700" Width="300">

    <StackPanel Margin="10">

        <!-- Image -->
        <Image Source="https://framerusercontent.com/images/LRmkkOk8c7TWErBSS6H9jhFklU.png" Height="50" Width="200" HorizontalAlignment="Center" Margin="0,0,0,10"/>

        <!-- Card-like Box -->
        <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="5" Padding="10" Margin="0,0,0,0">
            <StackPanel>
                <TextBlock Text="EF-WPF Sample Form" FontSize="14" FontWeight="Bold" Margin="0,0,0,10"/>
                <TextBlock TextWrapping="Wrap"><Run Text="This example illustrates a WPF form. "/><LineBreak/><Run Text="In WPF, you define the user interface in a "/><Run Text=".xaml file"/><Run Text="(front-end) and then it needs to be connected inside python script to manage behaviour and logic."/></TextBlock>
            </StackPanel>
        </Border>

        <!-- Separator -->
        <Separator Margin="0,10,0,10"/>

        <!-- Label and TextBox -->
        <DockPanel Margin="0,0,0,10">
            <Label Content="Enter Text:" Height="25" DockPanel.Dock="Left"/>
            <TextBox x:Name="UI_textbox_1" Height="25" Width="Auto" />
        </DockPanel>

        <!-- Label and TextBox -->
        <DockPanel Margin="0,0,0,10">
            <Label Content="Enter Text:" Height="25" DockPanel.Dock="Left"/>
            <TextBox x:Name="UI_textbox_2" Height="25" Width="Auto" />
        </DockPanel>

        <!-- CheckBox -->
        <StackPanel Orientation="Horizontal">
            <CheckBox x:Name="UI_checkbox_1" Content="Check me!" Margin="0,0,10,0"/>
            <CheckBox x:Name="UI_checkbox_2" Content="Check me!" Margin="0,0,10,0"/>
            <CheckBox x:Name="UI_checkbox_3" Content="Check me!" Margin="0,0,10,0"/>
        </StackPanel>


        <!-- Separator -->
        <Separator Margin="0,10,0,5"/>

        <!-- ComboBox -->
        <Label Content="Choose an option:"/>
        <ComboBox x:Name="UI_combobox" HorizontalAlignment="Stretch" Margin="0,0,0,10">
            <ComboBoxItem Content="Option 1"/>
            <ComboBoxItem Content="Option 2"/>
            <ComboBoxItem Content="Option 3"/>
        </ComboBox>

        <!-- Separator -->
        <Separator Margin="0,10,0,5"/>

        <!-- Header3 -->
        <TextBlock Text="EF WPF-Form Sample"  FontSize="12                    " FontWeight="Bold" Margin="0,0,0,10"/>

        <!-- Search Box for ListBox-->
        <DockPanel Margin="0,0,0,10">
            <Label Content="🔍Filter:" Height="25" DockPanel.Dock="Left"/>
            <TextBox x:Name="UI_search" Height="25" Width="Auto" HorizontalAlignment="Stretch" TextChanged="UIe_search_changed"/>
        </DockPanel>
        <!-- ListBox with CheckBoxes -->
        <ListBox x:Name="UI_listbox" HorizontalAlignment="Stretch" Height="150" SelectionMode="Single">
        </ListBox>



        <!-- Select All / Deselect All Buttons -->


        <!-- Separator -->
        <Separator Margin="0,10,0,10"/>


        <!-- Button -->
        <Button Click="UIe_button_run" Content="Submit!" Width="75" Height="25" Margin="0,0,0,10"/>

    </StackPanel>


</Window>

⌨️ Happy Coding!
Erik Frits