ghdoc.ExpireSolution required after modifying input NumberSlider?

So, I made a C# component that can reset an input slider value to a desired value. But do I really have to expire the entire solution after modifying the slider? What happens if I’m not? Would it be possible to expire only downstreams objects? Aso.

See last row in the code below :

        var slider = M_AngleDeg.Sources[0];
        var guid = slider.InstanceGuid;
        // get script interface
        var plug = RhinoApp.GetPlugInObject("GrassHopper");
        var scr = (Grasshopper.Plugin.GH_RhinoScriptInterface) plug;
        // reset slider to predefined reset angle
        scr.SetSliderValue(guid.ToString(), ResetAngle);

        GrasshopperDocument.ExpireSolution();  "# <--???

// Rolf

I’ve been trying different approaches but I can’t really find out which approach is preferred, so bare with me on this one:

If I modify the upstream slider (M_AngleSlider) in a delegated ScheduleSolution method (by first persisting a value for the slider in the SolveInstance/RunScript method) I would still like the modification to happen asap. Is the following the best appraoch?

Q1: Is it then a correct approach to simply exit (return) the SolveInstance/RunScript method
Q2: and ExpireSolution(false) in the Callback method?
Q3: And which ExpireSolution method is preferred of the two in my code below?

Preparing a value in the main solver (the “m_sticky_resetangle” variable):

private void RunScript(double AngleDeg, ... double ResetAngle, bool Reset, bool GlobalReset)
    // RESET (angle slider)
    if ((Reset || GlobalReset) && AngleDeg_IsConnected)
      // reset slider input
      if (M_AngleSlider.Sources.Count > 0)
        // persist the reset value for the scheduled callback to use
        m_sticky_resetangle = ResetAngle;

        // Schedule the actual change
        var gh_delegate = new GH_Document.GH_ScheduleDelegate(this.Callback);
        GrasshopperDocument.ScheduleSolution(1, gh_delegate);

        return; // ... and hope for a prompt update (?)

… and then modify the input slider in the Callback method:

  private void Callback(GH_Document doc)
    // get slider's object id
    var slider = M_AngleSlider.Sources[0];
    var id = slider.InstanceGuid;
    // get script interface scr
    var plobj = RhinoApp.GetPlugInObject("GrassHopper");
    var scr = (Grasshopper.Plugin.GH_RhinoScriptInterface) plobj;
    // reset the input slider to the predefined reset angle
    scr.SetSliderValue(id.ToString(), m_sticky_resetangle);
    Component.ExpireSolution(false);  "<-- which one?" (here)
    slider.ExpireSolution(false);     "<-- which one?" (upstreams)

For slider automation I always use GH_NumberSlider.TrySetSliderValue() instead of SetSliderValue, for whatever reason it seems to work and expire downstream objects without needing to wrap it in a delegate or manually call ExpireSolution
Although I’m not sure if it’s the safest way to do things either, would be nice to find out more :slight_smile:

Yes, hopefully @DavidRutten can give some advice about which approach is preferred, and why.

Thanks for the hint about TrySetSliderValue! Forgot about that one,

// Rolf

I found an old post by @DavidRutten on this. I don’t know if the approach mentioned below is “preferred” over any other approach, but it seems to be a valid option :


if you’re doing this [manipulating an upstream slider] from code which is triggered by a solution … you have to:

* Schedule a new solution and register a callback, then do nothing.
* When the scheduled solution is about to begin, your callback will be invoked and this is where you modify the sliders (but be careful, do not recompute them, only expire them).
* If you want to run more solutions, now would be a good time to schedule the next solution, but you can also do this from within RunScript, depends on the specifics of the case.

// Rolf

Sorry for the late response, I was out last week.

You definitely do not need to and should not expire more than absolutely necessary. Sliders are a bit more complicated than most objects because they host another slider control inside of them whose events will automatically trigger an expiration+update event. If you want to modify a slider without an immediate solution, you’ll want to use a more careful approach.

I think TrySetSliderValue is not what you are after, it’s distinguishing feature is that it will try and backsolve the expression if there is one. For example if your slider has a numeric range from 0 to 1 and a post-process expression 10*x^2, then calling TrySetSliderValue(2.5) will assign the actual value of 0.5 to the slider since 10 \cdot 0.5^2 = 2.5

I think almost always you’ll want to use SetSliderValue(). It doesn’t backsolve, but it does ensure everything downstream is expired without a new solution kicking off right away. You have to eventually trigger that new solution yourself when you are done making changes, probably just by calling NewSolution(false) on the document.

1 Like