Inputs in a nodeModel

ok i am going grazy. i know how to access the inputs in a node model and pass it to a static function and it is all good

   newInputs = new List<AssociativeNode>();
                newInputs.Add(AstFactory.BuildFunctionCall(
                    func,
                    new List<AssociativeNode>
                    {
                        inputAstNodes[0],
                        inputAstNodes[1],
                        inputAstNodes[2],
                        inputAstNodes[3]
                    }));

that all works fine. BUT HOW DO I GET inputAstNode[0] inside the node so i can use the data elsewhere. for instance i know inputAstNode[0] is a string[] but i cannot access that data anywhere unless i run it through the function…there has to be a way to get the data of an input

if it worked the way i wanted it it would be something like

string[] theInput = inputAsNode[0].Value ;

this would return an error if the inputAsNode was not TypeOf string[] or List

small thought, there is obviously some unpacking going on because between me passing inputAstNodes[0] in the buildfuctioncall into my function func and it arriving at the function it comes in as string[], string[], string[], string[] as expected. so where/how do i unpack the ast into a native string[] , int, …whatever without having to pass it outside my node and into a static function.

Hi @Robert_Cervellione,

I just had an exact same question recently and the answer is that you need to schedule an asynch task with the node model scheduler. The example to look at is the ColorRange node: https://github.com/DynamoDS/Dynamo/blob/e1944bcba7590f49e2860645a2d92f6d07f6fd97/src/Libraries/CoreNodeModelsWpf/NodeViewCustomizations/ColorRange.cs specifically look at the UpdateColorRange() method. The input value can be accessed using the mirror.GetData().Data and a great example of that is the Customization Class for the Coor Range found here: https://github.com/DynamoDS/Dynamo/blob/91b07ded895995b24728ed076b07da1964893d2a/src/Libraries/CoreNodeModels/ColorRange.cs

Good luck!

1 Like

I am not sure what exactly you are trying to do, but Keith Alfaro who’s worked on a plug-in called Hydra (open source), also has a good piece of code that will illustrate how to get the data from inputs using the mirror method. https://github.com/HydraShare/hydra-dynamo/blob/master/src/Hydra-0.9.0/src/SampleLibraryUI/Examples/HydraNode.cs

His using it a little bit differently as its hooked onto an event that fires when a button is pressed, but you get the idea. :slight_smile:

Konrad thanks, this is a LOT of code to get one variable, crazy

//_fileName Input
var fileNamenode = model.InPorts[0].Connectors[0].Start.Owner;
var fileNameIndex = model.InPorts[0].Connectors[0].Start.Index;
var fileNameId = fileNamenode.GetAstIdentifierForOutputIndex(fileNameIndex).Name;
var fileNameMirror = nodeView.ViewModel.DynamoViewModel.Model.EngineController.GetMirror(fileNameId);
var fileName = fileNameMirror.GetData().Data as string;

Hahaha, well as I understand it, we are not “supposed to want” to access these input values directly. :wink: Anyways, a lot of code was setting up the actual asynch and all accompanying events…its a little involved just to get an input value. Well, it is what it is.

“not supposed to want” the inputs…lol… if all i needed to do was something simple with the inputs i wouldent be meesing with a nodeModel and just do it as a zero touch, the entire point of useing a nodemodel is to controll the flow of data yourself…including what i want to do with inputs.

this example you sowed is perfect, it atleast unpack it into the data type expected just by substituting color with what ever you expect. i think i will try to write a generic function to handle all types and cases. i will post here. THANKS AGAIN THIS REFERENCE WAS PERFECT

 private static List<Color> GetColorsFromMirrorData(RuntimeMirror colorsMirror)
    {
        var colors = new List<Color>();

        if (colorsMirror == null || colorsMirror.GetData() == null) return colors;

        var data = colorsMirror.GetData();
        if (data != null)
        {
            if (data.IsCollection)
            {
                colors.AddRange(data.GetElements().Select(e => e.Data).OfType<Color>());
            }
            else
            {
                var color = data.Data as Color;
                if (color != null)
                    colors.Add(color);
            }
        }

        return colors;
    }

Well, “not supposed to want inputs” was meant to mean that we are not really supposed to be accessing input values directly but rather via the ASTFactory model where they get unpacked for us in a safe environment. The way it was presented to me is that when we access inputs directly we are running into risks like invalid casts or null values so we always have to check those. That’s at least how I understand it…I could be wrong.

Cheers!

conrad thanks so much your info solved something that has been bugging me for a while

so i dont know if this is what you did but i managed to wrap all the dirty stuff in a generic function so that getting an input is just 1 line of code like this

//run the getNodeInputs in async
getInputDelegate getInput = new getInputDelegate(this.getNodeInputs);

        //setup list to hold elements
        List<string> inZeroAsString = new List<string>();
        List<double> inoneAsString = new List<double>();
        //get the inputs
        if (HasConnectedInput(0))
            inZeroAsString = getInput(0).OfType<string>().ToList();
        if (HasConnectedInput(1))
            inoneAsString = getInput(1).OfType<double>().ToList();

with the function looking like this

internal List getNodeInputs(int inputNum)
{
var inputNamenode = nodeModel.InPorts[inputNum].Connectors[0].Start.Owner;
var inputNameIndex = nodeModel.InPorts[inputNum].Connectors[0].Start.Index;
var inputNameId = inputNamenode.GetAstIdentifierForOutputIndex(inputNameIndex).Name;
var inputNameMirror = nodeView.ViewModel.DynamoViewModel.Model.EngineController.GetMirror(inputNameId);
// var inputName = inputNameMirror.GetData().Data as string;

        var input = new List<object>();
        if (inputNameMirror == null || inputNameMirror.GetData() == null) return input;
        var data = inputNameMirror.GetData();
        if (data != null)
        {
            if (data.IsCollection)
            {
                input.AddRange(data.GetElements().Select(e => e.Data).OfType<object>());
            }
            else
            {
                var inData = data.Data as Object;
                if (inData != null)
                    input.Add(inData);
            }
        }
        return input;
    }
4 Likes

Hey, This post was very helpful for accessing the inputs of the node. My code appears to work fine with at list of for that input. However, I know that my input will have a nested list structure. Like shown here:
image
The length of the nested list will vary. Once my code reaches the index 1 of the list one, it returns null. It appears it has to do with the lamda expression “e.Data” but I am not sure how to I would change this to read those nested elements. In the end, I would like to have nodeMetaList be a nested list list of the same structure.

var styleNode = model.InPorts[1].Connectors[0].Start.Owner;
var styleIndex = model.InPorts[1].Connectors[0].Start.Index;
var styleId = styleNode.GetAstIdentifierForOutputIndex(styleIndex).Name;
var styleMirror = nodeView.ViewModel.DynamoViewModel.Model.EngineController.GetMirror(styleId);
var styledata = styleMirror.GetData();
                
object nodeMetaNodeName;
var nodeMetaInputs = new List<object>();
List<List<object>>nodeMetaList= new List<List<object>>(); 
if (styledata.IsCollection)
{
 nodeMetaNodeName=styledata.Data as string;

  var elements = styledata.GetElements().Select(e => e.Data);
  foreach (var element in elements)
  {
  nodeMetaNodeName = element;
  nodeMetaInputs.Add(nodeMetaNodeName);      
  }
 }
 else
 {
 }