PickPoint and UI crashing Revit

Hi there!

I am developing a pyRevit extension with its own UI in xaml. When button is clicked the active view is changed to elevation view, my UI is hidden and user is prompted to pick a point with the UI.Selection.PickPoint() function. Then a generic tag family is placed on that spot and the UI is shown again. When I click the same button again (without closing same UI) or any other button from the same custom UI, the UI is hidden and Revit crashes.

I would really appreciate some help!

Below is the code that makes up the extension. I narrowed down the issues to just the PickPoint by removing all other code and leaving only the picking capability and only this created crashes.

xaml
<Button Content="Place on View" Click="place_on_view"/>

script.py function nr1

def place_on_view(self, sender, e):
        self.Hide()
        selected_reference = self.cb_references.SelectedItem.ToString()
        location = revit.uidoc.Selection.PickPoint("Please pick a point to place the annotation symbol.")
        blueprint_utils.place_reference(self.state, "reference here", VIEW_NAME[0], REFERENCES[selected_reference], "A2.2", None)
        self.count_references += 1
        self.Show()

script.py function nr2

def place_reference(state, reference, elevation_name, note_number, note_text, location):
    """Prompt user to place chosen reference bubble on the elevation with the given name."""
    doc = get_doc(state)
    elevation = get_elevation_by_name(state, elevation_name)
    if not elevation:
        TaskDialog.Show(
            'Error', 'Elevation {} not found. Please create the sheet first.'.format(elevation_name))
        return
    symbols = FilteredElementCollector(doc).OfCategory(
        BuiltInCategory.OST_GenericAnnotation).OfClass(FamilySymbol)
    # typeId from the detail group of interest
    symbol = next((s for s in symbols if hasattr(s, 'Name')
                  and s.Name == "BubbleReferences"), None)
    symbol = [i for i in symbols if i.FamilyName == "BubbleReferences"][0]
    revit.uidoc.ActiveView = elevation
    t = Transaction(doc, "Place Group")
    t.Start()
    origin = XYZ.Zero
    basisX = XYZ.BasisY
    basisY = XYZ.BasisZ
    plane = Plane.CreateByOriginAndBasis(origin, basisX, basisY)
    sketch_plane = SketchPlane.Create(doc, plane)
    elevation.SketchPlane = sketch_plane
    location = revit.uidoc.Selection.PickPoint("Please pick a point to place the annotation symbol.")
    new_tag = doc.Create.NewFamilyInstance(
        location, symbol, doc.ActiveView)
    note_number_param = new_tag.LookupParameter('Note Number')
    note_text_param = new_tag.LookupParameter('Note Text')
    note_number_param.Set(note_number)
    note_text_param.Set(note_text)
    t.Commit()

Have a look at this post
[Need help with my first xaml file - #4 by hoss53]
you need to use external event handler when interacting with revit (ie selecting object / picking point)

2 Likes

Thank you for that. I tried to implement it using the whole event.py and calling it just like you did for my whole place_reference function but code behaves exactly the same (first placing of reference works perfectly and when i try to do the second one with same UI it crashes Revit)
Am I somehow wrong in my implementation?

from event import CustomizableEvent

class ReferencesManager:
    def __init__(self, window):
        self.window = window
        self.customizable_event = CustomizableEvent()  # Create an instance of CustomizableEvent

  def place_on_view(self, sender, e, view_type):
          self.window.Hide()
          if view_type == "front":
              selected_reference = self.cb_references_front.SelectedItem.ToString()
              view_name = VIEW_NAME[1]
              self.customizable_event.raise_event(blueprint_utils.place_reference(self.window.state, view_name, REFERENCES[selected_reference][1], REFERENCES[selected_reference][0]))
          elif view_type == "rear":
              selected_reference = self.cb_references_rear.SelectedItem.ToString()
              view_name = VIEW_NAME[0]
              self.customizable_event.raise_event(blueprint_utils.place_reference(self.window.state, view_name, REFERENCES[selected_reference][1], REFERENCES[selected_reference][0]))
          self.window.Show()

This is far from the example @hoss53 provided.
Please do provide the whole code to make sure we have the context to answer properly

Jean-Marc beat me to it, I was about to ask same thing
Please share whole of your code for script / xaml file and lovely people here will be able to help / guide you

Okay, thank you!
Here is all relevant code, the full thing is way too complicated to share.

So I have event.py in my folder from @hoss53 example:

Then xaml file is quite complicated because I feed it from python partly. But the relevant structure looks like so:

<StackPanel Margin="20">
		<TabControl>
			<TabItem Header="A3.0 Front/Rear Elevations">
				<StackPanel Margin="20">
					<TextBlock Text="Rear Elevation" />
						<Expander Header="References">
							<StackPanel x:Name="references_stack_panel" Margin="20,0,0,0">
								<StackPanel Orientation="Horizontal">
									<ComboBox x:Name="cb_references_rear" SelectionChanged="cb_references_SelectionChanged_rear">
										<!-- The ComboBox items will be added dynamically here from the Python code -->
									</ComboBox>
									<Button Content="Place on View" Click="place_on_view_rear"/>
								</StackPanel>
							</StackPanel>
						</Expander>
					</StackPanel>
			</TabItem>
		</TabControl>
	</StackPanel>
</Window>

script.py for my pyrevit button: (it has needed imports)

class MyWindow(blueprint.BlueprintFunctionality.BlueprintFunctionality):
    def __init__(self):
        wpf.LoadComponent(self, xamlfile)
        self.references_manager = ReferencesManager(self)
        self.references_manager.init_references(REFERENCES)

    """References functions are taken from references_ui.py file."""
    def cb_references_SelectionChanged_front(self, sender, args):
        self.references_manager.cb_references_SelectionChanged_front(sender, args)

    def cb_references_SelectionChanged_rear(self, sender, args):
        self.references_manager.cb_references_SelectionChanged_rear(sender, args)
    

    def place_on_view_front(self, sender, e):
        self.references_manager.place_on_view(sender, e, "front")

    def place_on_view_rear(self, sender, e):
        self.references_manager.place_on_view(sender, e, "rear")

Here is references_ui.py

import clr
clr.AddReference('PresentationFramework')
from System import Windows
from System.Windows import Controls
from event import CustomizableEvent
from pyrevit import UI, revit

class ReferencesManager:
    def __init__(self, window):
        self.window = window
        self.customizable_event = CustomizableEvent()  # Create an instance of CustomizableEvent
  
    def init_references(self, references):
        self.references = list(references.keys())
        self.references_stack_panel = self.window.FindName("references_stack_panel")
        self.cb_references_front = self.window.FindName("cb_references_front")
        self.cb_references_rear = self.window.FindName("cb_references_rear")
        for reference in self.references:
            self.cb_references_front.Items.Add(reference)
            self.cb_references_rear.Items.Add(reference)
        if self.references:
            self.cb_references_front.SelectedItem = self.references[0]
            self.cb_references_rear.SelectedItem = self.references[0]
    
    
    def cb_references_SelectionChanged_front(self, sender, args):
        # For getting the reference selected by the user
        selected_reference = self.cb_references_front.SelectedItem


    def cb_references_SelectionChanged_rear(self, sender, args):
        # For getting the reference selected by the user
        selected_reference = self.cb_references_rear.SelectedItem


    def place_on_view(self, sender, e, view_type):
        self.window.Hide()
        if view_type == "front":
            selected_reference = self.cb_references_front.SelectedItem.ToString()
            view_name = VIEW_NAME[1]
            self.customizable_event.raise_event(blueprint_utils.place_reference(self.window.state, view_name, REFERENCES[selected_reference][1], REFERENCES[selected_reference][0]))
        elif view_type == "rear":
            selected_reference = self.cb_references_rear.SelectedItem.ToString()
            view_name = VIEW_NAME[0]
            self.customizable_event.raise_event(blueprint_utils.place_reference(self.window.state, view_name, REFERENCES[selected_reference][1], REFERENCES[selected_reference][0]))
        self.window.Show()

And now blueprint_utils.py fragment:

def place_reference(state, elevation_name, note_number, note_text):
    doc = get_doc(state)
    elevation = get_elevation_by_name(state, elevation_name)
    if not elevation:
        TaskDialog.Show(
            'Error', 'Elevation {} not found. Please create the sheet first.'.format(elevation_name))
        return
    symbols = FilteredElementCollector(doc).OfCategory(
        BuiltInCategory.OST_GenericAnnotation).OfClass(FamilySymbol)
    # typeId from the detail group of interest
    symbol = next((s for s in symbols if hasattr(s, 'Name')
                  and s.Name == "BubbleReferences"), None)
    symbol = [i for i in symbols if i.FamilyName == "BubbleReferences"][0]
    revit.uidoc.ActiveView = elevation
    t = Transaction(doc, "Place Group")
    t.Start()
    origin = XYZ.Zero
    basisX = XYZ.BasisY
    basisY = XYZ.BasisZ
    plane = Plane.CreateByOriginAndBasis(origin, basisX, basisY)
    sketch_plane = SketchPlane.Create(doc, plane)
    elevation.SketchPlane = sketch_plane
    location = revit.uidoc.Selection.PickPoint("Please pick a point to place the annotation symbol.")
    new_tag = doc.Create.NewFamilyInstance(
        location, symbol, doc.ActiveView)
    note_number_param = new_tag.LookupParameter('Note Number')
    note_text_param = new_tag.LookupParameter('Note Text')
    note_number_param.Set(note_number)
    note_text_param.Set(note_text)
    t.Commit()

This is all thats relevant I think.