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()
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()
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()