Hi guys, I'm doing offline async procedural modelling (similar to grasshopper) that I’m trying to add to the group after it’s done. It's a long running task and I'm switching back to the UI context to access the Revit APIs and do the selection.
The background loads a window for final customization.
I'm guessing after loss of focus that the ActiveUIDocument becomes non graphical?
The code
let sel = app.ActiveUIDocument.Selection
let ref = sel.PickObject(ObjectType.Element, "Please select a group")
Produces the error.
"The active view is non-graphical and does not support capture of the focus for pick operations."
Is there any way for me to get the graphical ui document via the UIApplication or some global?
Cheers,
Matt
Solved! Go to Solution.
Hi guys, I'm doing offline async procedural modelling (similar to grasshopper) that I’m trying to add to the group after it’s done. It's a long running task and I'm switching back to the UI context to access the Revit APIs and do the selection.
The background loads a window for final customization.
I'm guessing after loss of focus that the ActiveUIDocument becomes non graphical?
The code
let sel = app.ActiveUIDocument.Selection
let ref = sel.PickObject(ObjectType.Element, "Please select a group")
Produces the error.
"The active view is non-graphical and does not support capture of the focus for pick operations."
Is there any way for me to get the graphical ui document via the UIApplication or some global?
Cheers,
Matt
Solved! Go to Solution.
Solved by jeremytammik. Go to Solution.
Dear Matt,
You definitely earn lots of extra points for submitting one of the most intriguing and cryptical question explanations.
I have no idea what you are talking about or what you might mean with your explanation.
All I can pick up on is the last line, asking whether you can activate a graphical view when some other non-graphical view is currently active.
Yes, you can set the active view using the UIDocument ActiveView property:
uidoc.ActiveView = view;
Cf. http://thebuildingcoder.typepad.com/blog/2011/09/activate-a-3d-view.html
I hope this helps.
Cheers,
Jeremy
Dear Matt,
You definitely earn lots of extra points for submitting one of the most intriguing and cryptical question explanations.
I have no idea what you are talking about or what you might mean with your explanation.
All I can pick up on is the last line, asking whether you can activate a graphical view when some other non-graphical view is currently active.
Yes, you can set the active view using the UIDocument ActiveView property:
uidoc.ActiveView = view;
Cf. http://thebuildingcoder.typepad.com/blog/2011/09/activate-a-3d-view.html
I hope this helps.
Cheers,
Jeremy
G'day Jeremey, thanks. Your help is greatly apprecitaed.
The 'general' problem I'm trying to solve is the the running of new functions defined interactivly at runtime using the F# compiler service.
I think this approach has a lot of advantages.
It would allow me to to build this but for Revit. https://www.youtube.com/watch?v=McJKA9OODyk&feature=youtu.be
I'm getting a managed exception thrown message when I try to set the view.
#r @"C:\Program Files\Autodesk\Revit 2016\RevitAPI.dll"
#r @"C:\Program Files\Autodesk\Revit 2016\RevitAPIUI.dll"
#r @"C:\EE\Git\Tsunami-main\bin\Debug\Tsunami.IDEDesktop.dll"
open Autodesk.Revit
open Autodesk.Revit.UI
open System
open System.Collections.Generic
open Autodesk.Revit.DB
open Autodesk.Revit.DB.Architecture
open Autodesk.Revit.UI
open Autodesk.Revit.UI.Selection
open Autodesk.Revit.ApplicationServices
open Autodesk.Revit.Attributes
let mutable app = Plugin.Mantis.Global.App
let mutable doc = Plugin.Mantis.Global.Document
module Seq =
let tryHead (xs:'a seq) =
let ys = xs.GetEnumerator()
if ys.MoveNext() then Some(ys.Current) else None
try
let getView =
use xs = new FilteredElementCollector(doc);
xs.OfClass(typeof<View3D>)
|> Seq.tryHead
|> function
| None -> ()
| Some(view) ->
let uiDoc = app.ActiveUIDocument
uiDoc.ActiveView <- view
let sel = uiDoc.Selection
let ref = sel.PickObject(ObjectType.Element, "Please select a group")
let elem = doc.GetElement(ref.ElementId);
Windows.Forms.MessageBox.Show(ref.ElementId.ToString()) |> ignore
with
| e -> Windows.Forms.MessageBox.Show(e.Message) |> ignore
This is after setting it up with a normal plugin...
interface IExternalCommand with
member this.Execute(commandData : ExternalCommandData, message: byref<string>, element : ElementSet) =
Plugin.Mantis.Global.App <- commandData.Application
Plugin.Mantis.Global.Document <- commandData.Application.ActiveUIDocument.Document
let win = Windows.Window()
Mantis.window <- Some(win)
let cont = runControl()
win.Content <- cont
win.Show();
Result.Succeeded
G'day Jeremey, thanks. Your help is greatly apprecitaed.
The 'general' problem I'm trying to solve is the the running of new functions defined interactivly at runtime using the F# compiler service.
I think this approach has a lot of advantages.
It would allow me to to build this but for Revit. https://www.youtube.com/watch?v=McJKA9OODyk&feature=youtu.be
I'm getting a managed exception thrown message when I try to set the view.
#r @"C:\Program Files\Autodesk\Revit 2016\RevitAPI.dll"
#r @"C:\Program Files\Autodesk\Revit 2016\RevitAPIUI.dll"
#r @"C:\EE\Git\Tsunami-main\bin\Debug\Tsunami.IDEDesktop.dll"
open Autodesk.Revit
open Autodesk.Revit.UI
open System
open System.Collections.Generic
open Autodesk.Revit.DB
open Autodesk.Revit.DB.Architecture
open Autodesk.Revit.UI
open Autodesk.Revit.UI.Selection
open Autodesk.Revit.ApplicationServices
open Autodesk.Revit.Attributes
let mutable app = Plugin.Mantis.Global.App
let mutable doc = Plugin.Mantis.Global.Document
module Seq =
let tryHead (xs:'a seq) =
let ys = xs.GetEnumerator()
if ys.MoveNext() then Some(ys.Current) else None
try
let getView =
use xs = new FilteredElementCollector(doc);
xs.OfClass(typeof<View3D>)
|> Seq.tryHead
|> function
| None -> ()
| Some(view) ->
let uiDoc = app.ActiveUIDocument
uiDoc.ActiveView <- view
let sel = uiDoc.Selection
let ref = sel.PickObject(ObjectType.Element, "Please select a group")
let elem = doc.GetElement(ref.ElementId);
Windows.Forms.MessageBox.Show(ref.ElementId.ToString()) |> ignore
with
| e -> Windows.Forms.MessageBox.Show(e.Message) |> ignore
This is after setting it up with a normal plugin...
interface IExternalCommand with
member this.Execute(commandData : ExternalCommandData, message: byref<string>, element : ElementSet) =
Plugin.Mantis.Global.App <- commandData.Application
Plugin.Mantis.Global.Document <- commandData.Application.ActiveUIDocument.Document
let win = Windows.Window()
Mantis.window <- Some(win)
let cont = runControl()
win.Content <- cont
win.Show();
Result.Succeeded
Aha!
"new functions defined interactivly at runtime"... that sounds very interesting.
Thank you also for the YouTube video link.
Too long for me to watch, but I get the idea 🙂
Have you written about this?
I would be happy to share your project on The Building Coder, if you are interested and when you are ready for it.
A lot of people have explored numerous methods to define Revit command at runtime, most often in order to enable realtime debugging, similar to the Visual Studio 'Edit and Continue' functionality.
Search The Building Coder for that term.
On second thoughts, I created a new topic group, just for you, to point you to some of the related discussions:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.49
Are you sure you are in a valid Revit API context?
If you don't know, then here is some more reading for you. Go through that before you get to the main topic:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.28
You really need to understand that concept.
I hope this helps.
Please let us know what you come up with.
Looking forward to hearing from you.
Good luck!
Cheers,
Jeremy
Aha!
"new functions defined interactivly at runtime"... that sounds very interesting.
Thank you also for the YouTube video link.
Too long for me to watch, but I get the idea 🙂
Have you written about this?
I would be happy to share your project on The Building Coder, if you are interested and when you are ready for it.
A lot of people have explored numerous methods to define Revit command at runtime, most often in order to enable realtime debugging, similar to the Visual Studio 'Edit and Continue' functionality.
Search The Building Coder for that term.
On second thoughts, I created a new topic group, just for you, to point you to some of the related discussions:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.49
Are you sure you are in a valid Revit API context?
If you don't know, then here is some more reading for you. Go through that before you get to the main topic:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.28
You really need to understand that concept.
I hope this helps.
Please let us know what you come up with.
Looking forward to hearing from you.
Good luck!
Cheers,
Jeremy
Thanks, those links have been helpful.
The Python interface gave me the idea of using the following line to get the UIApplication when using an ExternalApplication.
let fi = application.GetType().GetField("m_application", System.Reflection.BindingFlags.NonPublic ||| System.Reflection.BindingFlags.Instance);
And I needed a Rivit API Context via the Idle or ExternalEvent.
The PickObject is blocking and wont continue. When I constantly re-run the function in the idle event it will works when I click on the 3D model and then pick an object. I'm assuming the model pane has to be focused. Is there anyway to force the focus or to check if it has focus? Either way will work for me. Setting the active view on the doc to the View3D via FilteredElementCollector did not work.
Once I've got that figured out I think I could be pretty happy with the API. It's simply a matter of running a lambda 🙂
Mantis.run (fun (app:UIApplication) ->
let ref = app.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Please select a group")
Windows.Forms.MessageBox.Show(ref.ElementId.ToString()) |> ignore)
I'd love to show it around when it's ready. I've added you on skype, would love to pick your brain on whether such functionality is actually in much demand. I think it should be but I'm not an architect 🙂
Thanks, those links have been helpful.
The Python interface gave me the idea of using the following line to get the UIApplication when using an ExternalApplication.
let fi = application.GetType().GetField("m_application", System.Reflection.BindingFlags.NonPublic ||| System.Reflection.BindingFlags.Instance);
And I needed a Rivit API Context via the Idle or ExternalEvent.
The PickObject is blocking and wont continue. When I constantly re-run the function in the idle event it will works when I click on the 3D model and then pick an object. I'm assuming the model pane has to be focused. Is there anyway to force the focus or to check if it has focus? Either way will work for me. Setting the active view on the doc to the View3D via FilteredElementCollector did not work.
Once I've got that figured out I think I could be pretty happy with the API. It's simply a matter of running a lambda 🙂
Mantis.run (fun (app:UIApplication) ->
let ref = app.ActiveUIDocument.Selection.PickObject(ObjectType.Element, "Please select a group")
Windows.Forms.MessageBox.Show(ref.ElementId.ToString()) |> ignore)
I'd love to show it around when it's ready. I've added you on skype, would love to pick your brain on whether such functionality is actually in much demand. I think it should be but I'm not an architect 🙂
moloneymb:
you ought not need to use reflection to get an instance of Revit API Application object. In fact, you pretty much must not do it, since it cannot be used outside of a Revit API context anyway. The only way to get the application is within an API context, such as during an event (either standard or external), external command, external service, updater, etc. All of these contexts give access to the application one way or another, e.g. through method's arguments. Once you have that instance you can use it to access the API, which, however, you may only access while inside the current API context. Once you return control back to Revit you may not access the application regardles of whether you still hold [a pointer to] the instance or not. Although the application object is technically a singleton, many of its methods will throw exception (or worse, will fail or do something unpredictable) in an attempt to access it outside of a valid API context.
Thank you
moloneymb:
you ought not need to use reflection to get an instance of Revit API Application object. In fact, you pretty much must not do it, since it cannot be used outside of a Revit API context anyway. The only way to get the application is within an API context, such as during an event (either standard or external), external command, external service, updater, etc. All of these contexts give access to the application one way or another, e.g. through method's arguments. Once you have that instance you can use it to access the API, which, however, you may only access while inside the current API context. Once you return control back to Revit you may not access the application regardles of whether you still hold [a pointer to] the instance or not. Although the application object is technically a singleton, many of its methods will throw exception (or worse, will fail or do something unpredictable) in an attempt to access it outside of a valid API context.
Thank you
So I'm now able to initate pickobject from the REPL which is great!!
The only problem is the weird quirk that setting the ActiveView only works if that view is not currently active. So the property has some side effect that causes the focuse. Is there a way that I can always invoke the focus directly without using ActiveView for its side effect?
In reply;
Thanks, I don't use it for the Extenal Event so I'll remove the reflection.
It turns out I assumed the PickObject was blocking but it just through the "non-graphical" error and the error was silently handled.
Setting the view didn't work with the idle event but does work with the external event.
I made the mistake of not filtering out views by non templates which raised a different error that was also silently handled.
let view = x.OfClass(typeof<View3D>) |> Seq.map (fun x -> x :?> View3D) |> Seq.filter (fun v -> not v.IsTemplate) |> Seq.head
So I'm now able to initate pickobject from the REPL which is great!!
The only problem is the weird quirk that setting the ActiveView only works if that view is not currently active. So the property has some side effect that causes the focuse. Is there a way that I can always invoke the focus directly without using ActiveView for its side effect?
In reply;
Thanks, I don't use it for the Extenal Event so I'll remove the reflection.
It turns out I assumed the PickObject was blocking but it just through the "non-graphical" error and the error was silently handled.
Setting the view didn't work with the idle event but does work with the external event.
I made the mistake of not filtering out views by non templates which raised a different error that was also silently handled.
let view = x.OfClass(typeof<View3D>) |> Seq.map (fun x -> x :?> View3D) |> Seq.filter (fun v -> not v.IsTemplate) |> Seq.head
Background info on Matt's project:
Background info on Matt's project:
Can't find what you're looking for? Ask the community or share your knowledge.