Beginner to the revit api, I am trying to prompt my user to select objects with a selection box in revit.
I am using this line of code:
public void GatherRevitBeams(object sender, RoutedEventArgs e, Document doc, UIDocument uidoc, ref List<CustomLine> RevitBeams)
{
//we will pass in doc and uidoc becuase these are already being accessed in the mainwindow xaml code
IList<Reference> pickedObjs = uidoc.Selection.PickObjects(ObjectType.Element, "Select Elements");
I have this GatherRevitBeams function in a separate C sharp class (RevitInfo) from that of my MainWindow.xaml.cs file and I think this might be part of my trouble. Pressing the GatherRevitBeams button will fire, switching the screen over to the selection mode, but I am unable to draw a window to select or do anything. Clicking on the screen yields a "windows beep" noise and I am unable to progress in my code.
Any ideas where I am going wrong? I think I may need to start up the IExternal Command as shown in this video, but I am bit unclear on how to do this in a c sharp class that is separated from the MainWindow.xaml.cs file.
Full code on github if you want to take a look.
Appreciate you help!
Solved! Go to Solution.
Beginner to the revit api, I am trying to prompt my user to select objects with a selection box in revit.
I am using this line of code:
public void GatherRevitBeams(object sender, RoutedEventArgs e, Document doc, UIDocument uidoc, ref List<CustomLine> RevitBeams)
{
//we will pass in doc and uidoc becuase these are already being accessed in the mainwindow xaml code
IList<Reference> pickedObjs = uidoc.Selection.PickObjects(ObjectType.Element, "Select Elements");
I have this GatherRevitBeams function in a separate C sharp class (RevitInfo) from that of my MainWindow.xaml.cs file and I think this might be part of my trouble. Pressing the GatherRevitBeams button will fire, switching the screen over to the selection mode, but I am unable to draw a window to select or do anything. Clicking on the screen yields a "windows beep" noise and I am unable to progress in my code.
Any ideas where I am going wrong? I think I may need to start up the IExternal Command as shown in this video, but I am bit unclear on how to do this in a c sharp class that is separated from the MainWindow.xaml.cs file.
Full code on github if you want to take a look.
Appreciate you help!
Solved! Go to Solution.
Solved by ricaun. Go to Solution.
I have played a little bit with this, but still not working. Seems like I need to start up a new class with that inherits from IExternalCommand,
namespace rebarBenderMulti
{
[Transaction(TransactionMode.Manual)]
public class YourCommandName : IExternalCommand, IExternalEventHandler
{
private ExternalEvent externalEvent;
// Add a property to store the count of pickedObjs
public int PickedObjectsCount { get; private set; }
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements
)
{
// Retrieve the active UIDocument and Document
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
// Create an instance of MainWindow
MainWindow mainWindow = new MainWindow(uidoc);
// Create an ExternalEvent passing this instance as the handler
externalEvent = ExternalEvent.Create(this);
//we will pass in doc and uidoc because these are already being accessed in the mainwindow xaml code
IList<Reference> pickedObjs = uidoc.Selection.PickObjects(ObjectType.Element, "Select Elements");
// Store the count of pickedObjs in the property
PickedObjectsCount = pickedObjs.Count;
// Trigger the ExternalEvent
externalEvent.Raise();
// Returning Result.Succeeded here means that the command is completed
return Result.Succeeded;
}
public void Execute(UIApplication app)
{
}
public string GetName()
{
return "YourCommandName";
}
}
}
I then implemented this onto the button click
private void GatherBeamsButton_Click(object sender, RoutedEventArgs e)
{
// Create an instance of YourCommandName
YourCommandName command = new YourCommandName();
// Execute the ExternalCommand
command.Execute(uidoc.Application);
// Access the value of x (PickedObjectsCount)
int x = command.PickedObjectsCount;
Same error though, never able to select anything.
I have played a little bit with this, but still not working. Seems like I need to start up a new class with that inherits from IExternalCommand,
namespace rebarBenderMulti
{
[Transaction(TransactionMode.Manual)]
public class YourCommandName : IExternalCommand, IExternalEventHandler
{
private ExternalEvent externalEvent;
// Add a property to store the count of pickedObjs
public int PickedObjectsCount { get; private set; }
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements
)
{
// Retrieve the active UIDocument and Document
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
// Create an instance of MainWindow
MainWindow mainWindow = new MainWindow(uidoc);
// Create an ExternalEvent passing this instance as the handler
externalEvent = ExternalEvent.Create(this);
//we will pass in doc and uidoc because these are already being accessed in the mainwindow xaml code
IList<Reference> pickedObjs = uidoc.Selection.PickObjects(ObjectType.Element, "Select Elements");
// Store the count of pickedObjs in the property
PickedObjectsCount = pickedObjs.Count;
// Trigger the ExternalEvent
externalEvent.Raise();
// Returning Result.Succeeded here means that the command is completed
return Result.Succeeded;
}
public void Execute(UIApplication app)
{
}
public string GetName()
{
return "YourCommandName";
}
}
}
I then implemented this onto the button click
private void GatherBeamsButton_Click(object sender, RoutedEventArgs e)
{
// Create an instance of YourCommandName
YourCommandName command = new YourCommandName();
// Execute the ExternalCommand
command.Execute(uidoc.Application);
// Access the value of x (PickedObjectsCount)
int x = command.PickedObjectsCount;
Same error though, never able to select anything.
I believe your problem is in the way you are showing your window.
Using ShowDialog gonna block Revit until you close/hide your Window.
One way would be to Hide your Window before you run the selection, and ShowDialog after the selection.
public partial class MainView : Window
{
private readonly UIApplication uiapp;
public MainView(UIApplication uiapp)
{
InitializeComponent();
this.uiapp = uiapp;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
UIDocument uidoc = uiapp.ActiveUIDocument;
this.Hide();
try
{
var elements = uidoc.Selection.PickObjects(ObjectType.Element, "Select Elements");
Console.WriteLine(elements.Count);
}
catch (Exception)
{
}
this.ShowDialog();
}
}
[Transaction(TransactionMode.Manual)]
public class Command : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet)
{
UIApplication uiapp = commandData.Application;
new MainView(uiapp).ShowDialog();
return Result.Succeeded;
}
}
Another way would be to use modeless windows, using the Show that does not block Revit. Is a more advanced way to work with Windows and by looking at your code everything gonna break, so use Hide/ShowDialog 😀
I believe your problem is in the way you are showing your window.
Using ShowDialog gonna block Revit until you close/hide your Window.
One way would be to Hide your Window before you run the selection, and ShowDialog after the selection.
public partial class MainView : Window
{
private readonly UIApplication uiapp;
public MainView(UIApplication uiapp)
{
InitializeComponent();
this.uiapp = uiapp;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
UIDocument uidoc = uiapp.ActiveUIDocument;
this.Hide();
try
{
var elements = uidoc.Selection.PickObjects(ObjectType.Element, "Select Elements");
Console.WriteLine(elements.Count);
}
catch (Exception)
{
}
this.ShowDialog();
}
}
[Transaction(TransactionMode.Manual)]
public class Command : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet)
{
UIApplication uiapp = commandData.Application;
new MainView(uiapp).ShowDialog();
return Result.Succeeded;
}
}
Another way would be to use modeless windows, using the Show that does not block Revit. Is a more advanced way to work with Windows and by looking at your code everything gonna break, so use Hide/ShowDialog 😀
@ricaun, thanks, this seems to do the trick, appreciate your help.
I ended up forgoing the second way, with the IExternalCommand and just placed the code in the button press.
Is there any benefits to firing up the separate IExternalCommand? Any best practices to follow here?
I also noticed with my application being up, the user cannot interact with Revit at all, it's basically locked down. Is this due to the ShowDialog/Show you mentioned? I would like for the user to interact with the revit model with the application up. Would modeless solve this problem? Let me know if there are any good resources that cover revit states, I need to do some more reading to better understand this.
@ricaun, thanks, this seems to do the trick, appreciate your help.
I ended up forgoing the second way, with the IExternalCommand and just placed the code in the button press.
Is there any benefits to firing up the separate IExternalCommand? Any best practices to follow here?
I also noticed with my application being up, the user cannot interact with Revit at all, it's basically locked down. Is this due to the ShowDialog/Show you mentioned? I would like for the user to interact with the revit model with the application up. Would modeless solve this problem? Let me know if there are any good resources that cover revit states, I need to do some more reading to better understand this.
The `IExternalCommand` is designed for Revit when the user interacts with some Revit UI, usually PushButton.
I usually create a class with the UIApplication in the constructor, and I can reuse this class in the `IExternalCommand` or `IExternalEventHandler`.
The `IExternalEventHandler` is used by the modeless windows, to execute Revit code. By default Revit is not allowed to run Revit code at any time, only in the Revit time or in Revit Context, `IExternalEventHandler` gonna ensure the Revit Context.
I have this sample RevitAddin.ExternalEventExample with the implementation to delete elements using modeless windows and ExternalEvent.
Yes, using Show gonna make your Windows modeless and you gonna need to use `IExternalEventHandler` to run Revit code.
The `IExternalCommand` is designed for Revit when the user interacts with some Revit UI, usually PushButton.
I usually create a class with the UIApplication in the constructor, and I can reuse this class in the `IExternalCommand` or `IExternalEventHandler`.
The `IExternalEventHandler` is used by the modeless windows, to execute Revit code. By default Revit is not allowed to run Revit code at any time, only in the Revit time or in Revit Context, `IExternalEventHandler` gonna ensure the Revit Context.
I have this sample RevitAddin.ExternalEventExample with the implementation to delete elements using modeless windows and ExternalEvent.
Yes, using Show gonna make your Windows modeless and you gonna need to use `IExternalEventHandler` to run Revit code.
Can't find what you're looking for? Ask the community or share your knowledge.