Params.ParameterChanged eventhandler doesn't fire - for Outputs

In a C# script I’m trying to be clever - which seldom succeeds - I tried to get myself notified if an Output wire is connected or disconnected (as to optimize by skipping to produce or output any data to a disconnected output). However, the Params.ParameterChanged event handler (code below) doesn’t seem to be fired when changing the wires on the outputs.

Q1: Why not?

Q2: Is this perhaps related to my old and still (as of this writing) unanswered question on outputs?

private void RunScript(bool Run, ref object O) 
{
    // Subscribe to Params event (if disconnecting output params)
    this.Component.Params.ParameterChanged += this.OnParamsChanged;
}

// <Custom additional code> 
public void OnParamsChanged(object source, EventArgs e)
{
    Print("Event was fired! (An Input or Output was connected or disconnected)");
}

// Rolf

Since that event is triggered by GH_ComponentParamServer, I would bet that it happens when you change a parameter, when is removed or added (as in the Addition component). Nothing to do with the wires. There are several meanings of “parameter” and hence the confusion.

You can try to subscribe to the GH_Document.UndoStateChanged event and act when it is a wire action. I don’t know if there’s another way.

Hm, it seems the event isn’t fired even when the parameter value chnages (see “unanswered question on outputs”)?

I will have to try to respond to some of the other events yes, and then do the connected-check from there. I just tried GrasshopperDocument.SolutionStart += OnSolutionStart; but got no response from there either.

// Rolf

If I’m right, you’re misunderstanding the origin of the event. It does not happen when the parameter collects data, but when the parameter server makes a change (adds or removes a parameter). Parameter here means input or output, not the data coming in or out.

On your other question, I wouldn’t be at all surprised if the source component doesn’t update its recipient links when the connection happens, what need does it have to do that? This only requires knowing the recipient links when updating the status of their outputs, and this happens when the component expires. But well, I can’t affirm this, just speculate.

It doesn’t fire the event when connecting (adding) or disconnecting (removing) a wire (leading to a parameter). I don’t know of any other way of understanding this.

For optimization. If outputs are not connected, then no need for producing the output data (which no one is using).

I think I understand the difference between the data in the output param and it’s connections (Recipients), but changing either doesn’t fire the proposed event, at least not as far as I can se.

// Rolf

I hope you understand better with code than with words then. Try this out

this.Component.Params.ParameterChanged += (s,e) => RhinoApp.WriteLine("PARAM SERVER HAS CHANGED");

And change the type of access of an input. This event has nothing to do with the wires.

I don’t think you’ve thought twice about that. It is not optimal to have to expire the component when a recipient is plugged in, because there is no need. The output only changes when the inputs change (assuming there is no other mechanism to affect the process). The source component is not responsible for sending the data, it is the recipient component who reads the sources.

Wires are links between parameters. Sources (outputs) and recipients (inputs) are parameters. Parameters are spaces to place arguments to be readed (inputs) or writed (outputs) by the component. Arguments are the data or values that are communicated from one parameter to another through the wires (in a visual representation). GH does not have an event when the data of a parameter changes, because it is not easy to do it optimally I suppose.

It makes no sense for me to try to convince you, I can only give my point of view, and without any thanks this ends here for me.

yes, and i donä’t want to produce any data, nor output any data, if no downstream component is connected. That’s an optimization scheme used by some of the std grasshopper componetns as well.

And?

This is the code I use to test whether the output has recipients. (it is Inputs that has Sources, and Outputs has Recipients).

has_recipients = param_G.Recipients.Count > 0; // output is connected;

// Rolf

Only code can convince me.

In my code I read the Output Recipients as demonstrated below (and I also read “Output Sources”, which doesn’t exist, just to prove that it doesn’t exist - for Outputs) and I output the result of the check visibly in the picture below the code (the recipient counts).

I think the code below is rather convincing:

    // Optimize object's output
    var OUT_O = Component.Params.IndexOfOutputParam("O");
    var param_O = Component.Params.Output[OUT_O];

    // Optimize guid's output
    var OUT_G = Component.Params.IndexOfOutputParam("G");
    var param_G = Component.Params.Output[OUT_G];
    
    Print("O Recipients: " + param_O.Recipients.Count.ToString());
    Print("O Sources   : " + param_O.Sources.Count.ToString());
    
    Print("G Recipients: " + param_G.Recipients.Count.ToString());
    Print("G Sources   : " + param_G.Sources.Count.ToString());

Fig 1. Only the params.Output.Recipients return a value > 0 (due to the fact that a wire is connected)
bild

Why the expected events aren’t firing, though, is not explained by your take on “Input Receivers” and “Ourput Sources”, which obviously isn’t correctly paired (they need to be swapped).

But now the thread diverted into a completely irrelevant direction. Therefore may I suggest that you drop the Source/Recipient confusion and let someone answer who knows why the corresponding events are not fired. I can understand if the event for one (1) of the cases isn’t fired ((for value change, or for connecting wires, since the documentation isn’t 100% clear about whether it fires for either), but if not fireing for any of them then…

Well, that was my question (no event fired in any of the cases). And to be clear: This is not a question about whether it is a good idea or not to check the Output Recipients (it IS a good idea). My question is only about being notified when connecting/disconnecting happens. @DavidRutten would know more about this.

// Rolf

Now I have tested and double checked the original code which I posted in the first post (I only added writing also to the Rhino command line), and of course I’m doing the test-coding perfectly right. And if the problem wasn’t clear before Mr D. Abalde messed the whole thread up, this is the problem stated in correct and crystal clear terms:

  1. Changing the number of Output Recipients doesn’t fire the expected event, although…
  2. Changing the number of Input Sources does fire the event.

Of course anyone can run the code below, while adding or removing wires for Inputs and Outputs respectively, and find out that only when changing the Input wires the Params will fire its event “OnParamsChanged”:

So, the problem is there, and the original question remains - or perhaps better asked; will mcneel (@DavidRutten, @stevebaer) consider adding the firing of the events asked for in this post?

(And please disregard any confusion and “strong opinions” about the usefulness of being notified about the Output Recipients (wires) being changed. It is useful, but if there’s another way to achieve the same thing I could of course go for that other solution instead).

// Rolf

It seems obvious that, if adding events also for Outputs, that the events should be separate from the Inputs as to not break existing applications (by firing event’s that wasn’t there before).

The following (similar) events should be fired also for Output params:

bild

// Rolf

I was offline for four days (catching up since yesterday). I’ll get to this later today hopefully.

1 Like

@Dani_Abalde is correct. It’s related to changes to the parameter objects themselves. Adding or removing recipients is not considered something that affects any parameter.

There’s an additional problem doing this in a script component. When a parameter (be it input or output) is added, removed or renamed the script will be recompiled. So your event handler is now running inside an assembly which is no longer the one the script component cares about.

You can test whether a specific input parameter has its source list modified by handling the ObjectChanged event: parameter events.gh (6.3 KB)

There is no corollary for the recipient list.

Well, it affects parameters in the way I described it, namely that if there’s no recipient = then no need to process data, or to output any data. So there definitely are reasons to add events also when changing the connections to Outputs.

And this is also why I asked for the event, and I would have preferred staying on that particular topic (not Mr Abalde’s).

For some reason it also works with ParameterChanged (for inputs) but if ObjectChanged is preferred then thanks for the hint.



Edit: Problem is, when I commended away ParameterChanged and replaced it with ObjectChanged, then the update stopped working (no events firing). So I really don’t know what you guys are talking about. You are obviously not on my topic.

   // Component.Params.ParameterChanged += this.OnParamsChanged; 
   // :( Update no longer working.
   Component.Params.ObjectChanged += this.OnObjectChanged;   // Nope, doesn't work.

// Rolf

Here’s some code which allows you to keep track of changes to input sources and output recipients. There’s a lot of it sadly… topology events.gh (6.8 KB)

In my sharp code it works perfect. In the snippet above I only demonstrated which event I was talking about. This code works (only not for Outputs):

    this.Component.Params.ParameterChanged -= this.OnParamsChanged;
    try
    {
      // Do something
      // 
    }
    finally
    {
      this.Component.Params.ParameterChanged += this.OnParamsChanged;
    }

I disagree. You should always compute the data inside an output because it’ll be on screen and people will want to be able to see what’s in there using a tooltip even without anything connected. If an output is often unused yet takes a long time to compute, you should either create two versions of the component (one with, one without, same as the Area and Volume components), or make that specific output removable via the variable parameter interface (which would be very undiscoverable).

Yes I think even though it breaks the principle of least privilege or whatever-its-called, for symmetry’s sake it probably makes sense to add events for both source and recipient changes.

I looked into your code, and yes, I see the strategy. A bit verbose for that little thing, but so what, it works. :slight_smile:

It depends very much on what the component is doing. Also I didn’t say I would always skip preocessing the solution altogether but I have several cases where writing to an output is optional, but increases the execution time with almost 50%. One example was a component checking for nearest point for a number of breps. A thousand points took 24 ms and has 2 mandatory outputs, A third (optional) output increased execution time to 32 ms. That’s a typical case where removing a wire (would have made) a huge difference.

// Rolf