Lesson 03.06

How to Reuse Flex TextForm

Let me help you make the Flex TextForm from previous lesson reusable.

Lesson 03.06

How to Reuse Flex TextForm

Let me help you make the Flex TextForm from previous lesson reusable.

Summary

Intro

let me help you with the homework I left in Lesson 03.05. I want to make sure you know how to make that Flex TextForm reusable.

So, let's have a look together.

Copying Files to Your Lib

Firstly, we need to copy our code to lib folder, and remember that we don't need xaml, since we made everything with Behind-Code.

So, copy the python file and rename to something like FlexTextForm.py

Cleaning Up the Code

Now, it's great time to actually clean up your code.

  • Go through the python code and remove all unnecessary comments, and remove the code example on the bottom.


  • Also, it will be really useful to make a doc string so we can always reference on how to use this form and leave an example.


  • And I will rename my classes a little, so they have my ef_ prefix in the beginning.


Here is my code after clean-up:

# -*- coding: utf-8 -*-

# ╦╔╦╗╔═╗╔═╗╦═╗╔╦╗╔═╗
# ║║║║╠═╝║ ║╠╦╝ ║ ╚═╗
# ╩╩ ╩╩  ╚═╝╩╚═ ╩ ╚═╝ IMPORTS
#====================================================================================================
from Autodesk.Revit.DB import *
from pyrevit import forms   # By importing forms you also get references to WPF package! IT'S 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 Window, FontWeights, Thickness, WindowStartupLocation, SizeToContent
from System.Windows.Controls import StackPanel, DockPanel, TextBox, TextBlock, Dock, Button, Separator


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


# ╔╦╗╔═╗╦╔╗╔  ╔═╗╔═╗╦═╗╔╦╗
# ║║║╠═╣║║║║  ╠╣ ║ ║╠╦╝║║║
# ╩ ╩╩ ╩╩╝╚╝  ╚  ╚═╝╩╚═╩ ╩ MAIN FORM
#====================================================================================================

class ef_TextDock():
    """Custom Class for generating a DockPanel that has TextBlock and TextBox with defined values."""
    def __init__(self,key, label, default_value=""):
        self.key           = key
        self.label         = label
        self.default_value = default_value

    @property
    def control(self):
        # 🟧 Create DockPanel
        dock        = DockPanel()
        dock.Margin = Thickness(0, 0, 0, 10)

        # 🟧 Create TextBlock (Label)
        text_block            = TextBlock()
        text_block.Text       = self.label
        text_block.FontWeight = FontWeights.Bold
        text_block.Margin     = Thickness(0, 0, 5, 0)

        # 🟧 Create TextBox
        self.textbox      = TextBox()
        self.textbox.Text = self.default_value

        # ⬇️ Add items to DockPanel
        dock.Children.Add(text_block)
        dock.Children.Add(self.textbox)

        return dock


    @property
    def value(self):
        return self.textbox.Text



class ef_FlexTextForm(Window):
    """ Flexible Text Form to take any numbers of text user inputs.

    e.g.
    from ef_forms import ef_TextDock, ef_FlexTextForm

    components = [ef_TextDock(key='username', label = 'User Name:',  default_value='Erik'),
                  ef_TextDock(key='lastname', label = 'User LastName'),
                  ef_TextDock(key = 'H',      label = 'El Height'),
                  ef_TextDock(key = 'W',      label = 'El Width')]

    UI          = ef_FlexTextForm(components)
    dict_values = UI.values

    username = dict_values['username']
    lastname = dict_values['lastname']
    height   = dict_values['H']
    width    = dict_values['W']"""

    text_controls = {}
    values        = {}

    def __init__(self, components):
        self.components = components

        #🟦 Define WPF Controls
        self.set_window_properties()
        self.populate_wpf_controls()


        self.ShowDialog()

    def set_window_properties(self):

        #🔴 Define Window Attributes
        self.Title                 = 'EF-FlexTextForm'
        self.Width                 = 300
        self.MinHeight             = 125
        self.WindowStartupLocation = WindowStartupLocation.CenterScreen
        self.ResizeMode            = 0  # NoResize
        self.SizeToContent         = SizeToContent.Height  # Automatically adjust the height based on content

    def populate_wpf_controls(self):
        # 🟧 Create Main Stack for the form
        self.stack = StackPanel(Margin=Thickness(10))

        # 🟦 Add Components to StackPanel
        for item in self.components:
            self.text_controls[item.key] = item
            self.stack.Children.Add(item.control)

        # 🟧 Create Separator
        sep = Separator()
        sep.Margin = Thickness(0, 0, 0, 10)

        # 🟧 Create Button
        button = Button()
        button.Content = 'Submit!'
        button.Click += self.UIe_btn_run

        self.stack.Children.Add(sep)
        self.stack.Children.Add(button)

        # ⬇️ Add StackPanel to WindowForm
        self.Content = self.stack


    # ╔╗ ╦ ╦╔╦╗╔╦╗╔═╗╔╗╔╔═╗
    # ╠╩╗║ ║ ║  ║ ║ ║║║║╚═╗
    # ╚═╝╚═╝ ╩  ╩ ╚═╝╝╚╝╚═╝ BUTTONS
    #==================================================
    def UIe_btn_run(self, sender, e):
        """Button action: Rename view with given """
        for key, text_control in self.text_controls.items():
            self.values[key] = text_control.value
        self.Close()

Import in __init__.py

Same as before, let's import this class inside of __init__ file so we can import directly from ef_forms module (or however you called your folder).

from FlexTextForm import ef_TextDock, ef_FlexTextForm
Using the Reusable Flex Text Form

And now we can import and test it from any file in our extension.

Here is an example with a few text inputs:

from ef_forms import ef_TextDock, ef_FlexTextForm

components = [ef_TextDock(key='wall_type', label = 'WallType::'),
              ef_TextDock(key='level_name', label = 'Level Name:'),
              ef_TextDock(key = 'H', label = 'El Height'),
              ef_TextDock(key = 'W', label = 'El Width')]

UI          = ef_FlexTextForm(components)
dict_values = UI.values

wall_type  = dict_values['wall_type']
level_name = dict_values['level_name']
height     = dict_values['H']
width      = dict_values['W']

print(wall_type  )
print(level_name )
print(height     )
print(width      )
Conclusion

I hope it helped you to make this class reusable, and now you are ready for the next module - Styling in WPF.

I wish you Happy Coding and I will see you soon.

🙋‍♂️ See you in the next lesson.
- EF

🙋‍♂️ See you in the next lesson.
- EF

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.