RhinoDoc.ActiveDoc Best Practices

Hi everyone,

If you use RhinoDoc.ActiveDoc in the .Net environment there is a BIG Warning that I better don’t use it, because of MAC compatibility.

So far I was pretty much ignoring it (Nobody working with a Mac Version at our office anyway).
However –when writing code from now on I think it would be good to at least be aware of it and may do it right from now on – you never know. Maybe Rhino Windows will be MultiDoc someday as well.

So my first question is:
When working with Mac – what exactly has to happen to have a change in the ActiveDoc. Meaning – what does the user have to do? When does “the problem” occur?
Is it possible to have the active doc change while executing a command?
I have a bunch of (static) functions which create Rhino Geometry within them. I would prefer not to pass the Doc as a parameter each time – if that’s possible.
Does anyone have experience with this.

In Rhino Python there is “scriptcontext”
How would I implement something like this in the .Net environment? Also are there any plans to provide a solution for this via RhinoCommon – something like a “ActiveDocAtCommandStart Property”

Thanks
Martin

P.S.: When working with RhinoMac – how do I connect to opened, but not active docs?

1 Like

In Rhino for Mac you can have multiple documents open at the same time. When the user switches document during a command, the ActiveDoc will change.

ActiveDocAtCommandStart is already given in the command function signature RunCommand(RhinoDoc doc, RunMode mode) the doc parameter is the active one at command start.

Thank you,

the “problem” is that I don’t want to pass the “doc” given in the command down to all my functions.

If I create a function called “AddLayer” I would have to pass something like "AddLayer(string layerName, RhinoDoc doc)"
It would be much nicer not to have to do that and I would be able to connect to it without having to pass it on.
— Not sure if this is even possible —

That wouldn’t be too much trouble, If I called everything from the “command” directly - but if some function way down the programm wants to know if a layer exists, I will have to pass the “doc” through all my functions.

I guess I could use a class, create a property and assign the doc to it. Was just wondering how other people handle it.

Is there an event that is triggered, if the active document is changed? Is there a way to temporarily disable the ability to change the document for the MAC Version?
In the end it doesn’t make sense to let a user select one curve from one document and another one from a different document and then loft them.

Thanks
Martin

Yes, passing the doc reference directly or as part of a “Settings” class is the way I do this. I don’t find this to be too much hassle to be honest. Also it adheres to the principle of dependency injection where it is clear in a function signature what external dependencies it has.

1 Like

I concur with Menno. It’s not that big a deal to add a doc argument to functions that modify a document. If you find yourself passing several things to all functions (say, a RhinoDoc, a DisplayPipeline and a Viewport) you can wrap them up in a small context class that gets passed around instead.

Well , I guess that makes sense then.
Didn’t think of dependency injection.

Good to know how you would approach it. Thanks
Martin

So the easiest way to do this is make a public variable (rhinoDoc) that will update when a Command is Triggered?
This way it will update from different doc’s?

No. Well, maybe. Static (Shared in Visual Basic) variables should be avoided if at all possible. They make code very unthreadsafe. If your command creates a new instance of a class which does all the heavy lifting, then it’s ok to put a RhinoDoc member variable on that class. If your RunCommand method only calls a bunch of other methods, then adding a RhinoDoc argument to those methods is the preferred solution.

Oke so a direct “link” like:

Private Function MyFunction (byval doc as RhinoDoc)

`todo

End Function

Indeed.

If you put your logic in a separate class, then you can use a class level variable as well:

Public Class MyFunctionality
  Private Readonly _document As RhinoDoc

  Public Sub New(doc As RhinoDoc)
    _document = doc
  End Sub

  Public Function MyFunction() As SomethingOrOther
    _document.Objects.AddSomething()
  End Function
End Class

And in this case the code inside RunCommand will look a bit like:

Dim func As New MyFunctionality(doc)
func.MyFunction()

But obviously you cannot recycle that class instance later as it then might refer to the wrong document.

a bit off topic but i’ve tried something similar just to see what happens… (start drawing a curve in one document then finish in another.)
it just cancels the command in doc1 and switches focus to doc2.