How can I create an event?

How can I create an event class, respectively eventargs methods that I can later access from a python script?

  • Do I need to do this with C#?
  • Does it need to be a compiled plugin?
  • Is there an example?

Thanks in advance.

No! An event is basically a predefined programming pattern encapsulated in some obvious keywords. You can use the dotnet implementation but obviously you can use your own implementation as well.

All it does is using function pointer/references aka ā€ždelegateā€œ (in dot.netlanguage) to execute methods on predefined spots on your code.

So imagine a program runs a loop of finding prime numbers. Whenever it finds one you say execute all functions stored in ā€žFoundPrimeNumberEventā€œ. On code definition its undefined what happens in there, because you need to pass these functions on initialization. In Python you can pass a function just as variable. These are called ā€žsubscriptionā€œ or ā€žcallbackā€œ methods.

So picture FindPrimeNumbers holds a list of any Function matching its signature. Usually you call a matching functionality OnFoundPrimeNumber.The C# syntax would be FoundPrimeNumberEvent += (append) OnFoundPrimeNumber. Thatā€™s basically all it does. No magic involvedā€¦

EventArgs are additional informations passed as well, so it might be of interest to pass a reference of the sender object and some other useful information.

However you need to make sure not to loose references in a scripting context if you plan to implement it asynchron. When you change your script you basically create new subscription methods even if named the same. So you may loose reference to your old ones making it hard to unsubscribe them. This is why it is not recommended to use events in a scripting context. Not cleanly destroying an event mechanism can lead to weird behavior which is hard to debug.

1 Like

Hi @TomTom,

Thanks for the reply.

The question is not so much what an event is, but rather how can I get my own custom event not currently existing in RhinoCommon to work inside Rhino and accessing it with Python.

Do I need to create Event delegate OnEvent and EventArgs with C# and create a plugin for Rhino in order to get access to them? Or I can also do this within PythonEngineā€™s scope?

You can make an event with pyevent. I used it a while back to do some stuff with eto forms:

It seemed to work within the scope of a singular script.

1 Like

No this is what I was saying. An event is rather a pattern not a specific language feature. You are free to use dotnet events but its not wrong to use a python or an custom made implementation. Subscribing to an existing one is another deal.

Just google ā€žcallbackā€œ . An event is a variation of this.

Thanks for this link @nathancoatney,

Iā€™ll try to use it as a starting point.

@TomTom, I have googled callback and event, and I understand the concept.
What I am missing is creating my own event inside Rhino-IronPython context. Then accessing this event.

So far what Iā€™ve tried and succeeded is subscribing to Windows and RhinoCommon events. But never succeeded creating my own event class with eventargs methods. I think of Rhino(RhinoCommon+IronPythonEngine) as an isolated ecosystem. Question was how can I infiltrate that eco system and create my own stuff.

As an example. Say I wanna create an event that fires every time a point enters a Brep. There is a RhinoCommon method IsPointInside, but thereā€™s no such Event in RhinoCommon. Do I need to create a custom class deriving from Point class or Brep class that will include my event there?
Respectively I then donā€™t instantiate a normal point but I instantiate my custom point class.

This is not directly possible, since you would need to be the one implementing the ā€œadd pointā€ command. It would be the responsibilty of McNeel to provide such event in this case. Maybe there even is, donā€™t know about this. There are workarounds:
A). You can implement your own ā€œadd pointā€ command.
On success, you fire an event. This command could be a simple wrapper command with an event notification in it
B.) Another workaround could be to observe the command history, and whenever a desired command shows up you fire an CommandXOccuredEvent (or any name suited for such event). There might be already a command notifying on change, if not you simply create an infinite loop in another thread constantly checking for change.

The idea behind a event driven concept is to notify the user about some occurence leaving it open to him what happends as a response to it. But as a plugin user, you are not in responsibity to give notifications of the parent app. You usually just subscribe. Workarounds excludedā€¦

This is not what I am looking for.

I donā€™t want to notify the user, but notify another custom command to react on event firing.

That leaves option A:
McNeel may not be interested implementing customer-requested events. So If the script from @nathancoatney does exactly that thenā€¦we have a winner :slight_smile:

Still havenā€™t cleared myself the question about the RhinoCommon vs. custom class.

For your point on brep example, I would think you are still going to have to listen to a rhino doc event to know when your point moves, do the test for your event when that listen is triggered, then emit your event with args when the test is true (point is on brep).

If you havenā€™t already experimented with this, here is the Rhino sample on how to listen to the doc:

Iā€™m not sure how one tracks the point but certainly it must be possible.

This is an McNeel Event, the question was on how to implement an own event, not just subscribing to an existing one. These are two different pairs of shoes in my oppinion. But these events are maybe exactly what Ivelin is looking for.

1 Like

I bet the object added is passed as an argument. Simply cast to the expected type and do whatever you like to doā€¦ On an event you always get the sender and an argument, which surely holds a reference to the geometry added!

It helps to read the documentation :slight_smile:

https://developer.rhino3d.com/api/RhinoCommon/html/E_Rhino_RhinoDoc_AddRhinoObject.htm

@TomTom: Pretty sure we are on the same page. I mentioned subscribing to the doc events because of the example Ivelin described. One would have to know when the point moved somehow. Doc events could provide this, or perhaps the script is moving the point and the doc events are not needed. At any rate once the point has moved, test it, if conditions met then emit custom event.

@nathanletwory:
Iā€™ve not yet had the need to use these events so Iā€™ve not RTM, but I have faith the RhinoCommon architects provide what is needed!

It helps to read the caption of this thread :ghost: Iā€˜m just getting angry with myself giving any answer in this forum again. :exploding_head:

You were doing a great job, no complaints about any of that!

I was simply replying to:

where I meant that you donā€™t have to bet (:

I know how to use RhinoCommon event when object is created.

Question is not using RhinoCommon events, I want to use my own event independent from them.

Perhaps my example wasnā€™t appropriate, Iā€™ll think of another.

Ok, @nathanletwory, @nathancoatney, @TomTom,

Coming back to the is point inside brep example.

Currently using only RhinoCommon events I have to:

  1. Subscribe to object(point) add to document event.
  2. Every time the event fires, I have to run the method that checks if the point is inside the brep.

Supposed scenario:

  1. Create Event that watches if point enters a brep
  2. hook to this event by specifying which event is to be ā€œwatchedā€.

Questions:

  1. Where does this event resides?
    ā€“ Inside a custom Brep class containing the event and eventargs?
    ā€“ Inside a custom Point class (although I think not, as it will have to run everytime this point moves which is the rhinocommon approach)
    ā€“ or somewhere else, an independent class of a sort?
  2. Do I have to run two scripts?
    ā€“ one containing the event
    ā€“ one containing the hook to the event
    ā€“ or can it run in the same script?
  3. Is there a different way to implement such checks, like for example using object.dictionary (you know the hidden UserText that allows objects to be added not only strings)

You should be able to run all that in one script.

Do you intend to have the event available to outside code? Usable from other scripts and plug-ins?

I think the safest and most robust way to do that is through a separate assembly that you consume yourself as well.

In that case youā€™d have a class that itself subscribes to the RhinoDoc.AddRhinoObject event. That class also would publish an event, say PointInsideBrepFound. Your implementation would indeed trigger that with the event args you deem necessary (point ID and brep ID, I guess).

Others (including you) can then reference the assembly, get an instance of your class and subscribe to its PointInsideBrepFound event.

I am guessing you probably could do all that from a Python script in Rhino, but I think with a separate assembly itā€™d be a bit easier to manage in the long run.

yes, that is what I want.

By Assembly, do you mean DLL or a plugin for rhino?

Yes.

1 Like