Access persistent data

Hi guys, I am trying to access the value from an input to a remote component via C#. But the PersistentData property is giving me an empty structure for some reason.

here is my code:

  GH_Component comp = null;
    for (int i = 0; i < GrasshopperDocument.Objects.Count; i++)
    {
      if(GrasshopperDocument.Objects[i].Name == "Environment Dimension ")
      {
        try
        {
          comp = GrasshopperDocument.Objects[i] as GH_Component;
          Print("Component name:" + " " + comp.Name);
          var param = comp.Params.Input[0].Sources[0] as GH_PersistentParam<GH_Integer>;
          
          //Print("imput type:" + " " + param.ToString());
          GH_Structure<GH_Integer> persistentData = param.PersistentData;
          
         // var data = persistentData[0]; ---> Should be 0 !
          
          Print(persistentData.ToString());
          break;
        }
        
        catch(Exception ex)
        {
          throw new ArgumentException(ex.ToString());
          
        }
      }
    }

Any ideas why this is happening?

Maybe the order of computation matters. What if you (pseudo) connect the c# component somewhere behind the int param?
I mean right now it’s undetermined whats first for you as the user

That parameter might not have persistent data. It is being fed data by a slider, meaning it only definitely has volatile data. If the parameter didn’t have any sources, then its persistent data would be copied into the volatile data.

In addition to that, and as @TomTom said, order of computation does matter. If your script runs first, and the parameter has expired, even the volatile data will be null. You’ll need to make sure the parameter solves itself before you try and harvest its values.

@DavidRutten and @TomTom thanks for your replies.

I tried modifying my code to listen listen to when the input parameter has expired but, the event does not seem to be triggering, and I guess that is do to the fact of the order of computation both of you have mentioned. So does this check have to be async?

Here is the new code


 private void RunScript()
  {


    GH_Component comp = null;
    for (int i = 0; i < GrasshopperDocument.Objects.Count; i++)
    {
      if(GrasshopperDocument.Objects[i].Name == "Environment Dimension ")
      {

        comp = GrasshopperDocument.Objects[i] as GH_Component;
        Print("Component name:" + " " + comp.Name);
        param = comp.Params.Input[0].Sources[0] as GH_PersistentParam<GH_Integer>;
        Print(param.Name);

        // subscribe event
        param.SolutionExpired += Param_SolutionExpired;
        

        break;

      }
    }



  }

  // <Custom additional code> 
  GH_PersistentParam<GH_Integer> param = null;

  GH_Structure<GH_Integer> persistentData = null;



  private void Param_SolutionExpired(IGH_DocumentObject sender, GH_SolutionExpiredEventArgs e)
  {
    // Assign persistent data value
    persistentData = param.PersistentData;
    Print(persistentData.ToString());
    Component.ExpireSolution(true);
  }

Also just as a prove of concept I generated a small event handling code to just make sure I was not missing something obvious. As soon as it recognizes an input value of 2 it will fire the event.

 private void RunScript(int x, ref object A)
  {
    RecogniseNum2 rec = new RecogniseNum2();

    rec.foundNumber2 += rec_checking;
    rec.Check(x);

  }

  // <Custom additional code> 

  private void rec_checking(object sender, EventArgs e)
  {
    Print("Found number 2");
  }

  public class RecogniseNum2
  {
    public event EventHandler foundNumber2;

    public void Check(int x)
    {

      if ((x == 2) && (foundNumber2 != null))
      {
        foundNumber2(this, EventArgs.Empty);
      }

    }
  }

So what I am suspecting is that maybe its something along the lines of async event patterns?
if it is I have not yet dealt with async programming, just read some stuff about it.

Well events in scripts is something you should avoid. If you subscribe to an existing event you at least need to make sure to unsubscribe when your computations finished otherwise you get weirdo behaviour and potentially a memory leak. Since everytime you recompile a script, you loose the ability to unsubscribe with the handlers still being active. What you can do, is unsubscribing within your handler in the last line. This is possible. I might give you an example later…