DynamoDS / Dynamo

Open Source Graphical Programming for Design
https://dynamobim.org
Other
1.67k stars 622 forks source link

Get value of input in dropdown (C#) #5903

Closed NicklasOestergaard closed 8 years ago

NicklasOestergaard commented 8 years ago

I have created a dropdown that has inputs. Have do i "get" the cleand value of the inputs?

NicklasOestergaard commented 8 years ago

My current code looks like this:

using System.Collections.Generic;
using System.Linq;
using DSCoreNodesUI;
using Dynamo.Nodes;
using Dynamo.Utilities;
using ProtoCore.AST.AssociativeAST;
using Dynamo.Models;
using System;
using Dynamo.Engine;

namespace BIMSharkDynamoTools.GETCalls
{
    [NodeName("GET All Your BS Projects")]
    [NodeDescription("GET a list of all your BS projects")]
    [IsDesignScriptCompatible]
    public class BIMSharkDynamoToolsGETProjects : DSDropDownBase
    {
        private RestService.Rest rest;
        private string apiKey = "";

        //public static string apiKey;
        internal EngineController EngineController { get; set; }

        //test
        //public BIMSharkDynamoToolsGETProjects()
        //    : base("item")
        //{
        //    this.AddPort(PortType.Input, new PortData("BS ApiKey", "ToolTip"), 0);
        //    this.PropertyChanged += OnPropertyChanged;
        //}

        public BIMSharkDynamoToolsGETProjects()
            : base("Project(s)")
        {
            InPortData.Add(new PortData("BS ApiKey", "ToolTip"));

            RegisterAllPorts();

            this.PropertyChanged += OnPropertyChanged;
        }

        void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName != "CachedValue")
                return;

            if (InPorts.Any(x => x.Connectors.Count == 0))
                return;

            PopulateItems();

        }

        public override void PopulateItems()
        {

            try
           {
                List<string> BSAPIKeys = new List<string>();
                string AllBSAPIKeys = "";
                BSAPIKeys.Clear();

                var urls = InputNodes.Values.ToArray();
                foreach (var url in urls)
                {
                    if (InPorts.Any(x => x.PortName == "BS ApiKey"))
                    {
                        BSAPIKeys.Add(((Dynamo.Nodes.CodeBlockNodeModel)url.Item2).Code);
                    }
                }
                AllBSAPIKeys = string.Join(", ", BSAPIKeys.ToArray());
                apiKey = AllBSAPIKeys.Replace(";", "").Replace("/", "").Replace("\"", "");
                Items.Clear();
            }
            catch
            {
            }

            if (apiKey.Length > 20)
            {
                try
                {
                    // The Items collection contains the elements
                    // that appear in the list. For this example, we
                    // clear the list before adding new items, but you
                    // can also use the PopulateItems method to add items
                    // to the list.

                    rest = new RestService.Rest(apiKey);
                    //Items.Clear();

                    // Create a number of DynamoDropDownItem objects 
                    // to store the items that we want to appear in our list.
                    rest.GetProjects();

                    var newItems = new List<DynamoDropDownItem>();
                    foreach (RestService.Project p in rest.projects)
                    {
                        string text = "(" + p.id.ToString() + ")  " + p.project_name.ToString();

                        string value = p.id.ToString();
                        //int value = int.Parse(p.id);

                        //CB_Projects.Items.Add("(" + p.id + ")  " + p.project_name);
                        //new DynamoDropDownItem("(" + d.id + ")  " + d.title, d.id)),
                        Items.Add(new DynamoDropDownItem(text, value));
                    }

                    //set up the collection
                    //var newItems = new List<DynamoDropDownItem>();

                    //set up the collection
                    //Items.AddRange(newItems);

                    // Set the selected index to something other
                    // than -1, the default, so that your list
                    // has a pre-selection.
                    SelectedIndex = 0;
                    return;
                }
                catch
                {
                }

            }
            else
            {
                try
                {
                    // The Items collection contains the elements
                    // that appear in the list. For this example, we
                    // clear the list before adding new items, but you
                    // can also use the PopulateItems method to add items
                    // to the list.

                    Items.Clear();

                    // Create a number of DynamoDropDownItem objects 
                    // to store the items that we want to appear in our list.

                    var newItems = new List<DynamoDropDownItem>()
                    {
                        new DynamoDropDownItem("No Project found", 0),
                    };

                    //set up the collection
                    //var newItems = new List<DynamoDropDownItem>();

                    //set up the collection
                    //Items.AddRange(newItems);

                    // Set the selected index to something other
                    // than -1, the default, so that your list
                    // has a pre-selection.
                    SelectedIndex = 0;
                }
                catch
                {
                }
            }
        }

        public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
        {
            //var intNode = AstFactory.BuildIntNode((int)Items[SelectedIndex].Item);
            //var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), intNode);
            //return new List<AssociativeNode> { assign };

            // If there the dropdown is still empty try to populate it again
            if (Items.Count == 0 || Items.Count == -1)
            {
                PopulateItems();
            }

            // get the selected items name
            var stringNode = AstFactory.BuildStringNode((string)Items[SelectedIndex].Item);

            // assign the selected name to an actual enumeration value
            var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), stringNode);

            // return the enumeration value
            return new List<AssociativeNode> { assign };
        }
    }
}
mjkkirschner commented 8 years ago

@NicklasOestergaard what do you mean by cleaned?

NicklasOestergaard commented 8 years ago

If the input comes form a codeblock with comments I get the comments as well and not only the value from the string.

mjkkirschner commented 8 years ago

@NicklasOestergaard I see, how you are accessing the code from the code block is not how you should access the value of a node. The code property is the text string. Unless you are not actually interested in the value of the node? By value I mean the computed values of a port on a node. (an output)

what you should do is either use engine and get mirror() to access the value of the node's port at runtime (NOT RECOMMENDED) ... only do this if you need to use the value to update the UI of the node.

or better the inputAstNodes value in the BuildOutputAST() method allow you to access the AST representation of the inputs to the node. So that list will contain an object that represents the value coming in on the input of your node. You could then pass this to your populate method.

NicklasOestergaard commented 8 years ago

I have tried to use the get mirror () but I think that I'm missing a using statement and I can not figure out which dll file I must refer to. I tell me more about how to use inputAstNodes?

NicklasOestergaard commented 8 years ago

This weekend I had one more look at my code but I had no luck in getting it working. The only "sample" I can find is "Get Family Parameter" in DynamoRevit/src/Libraries/RevitNodesUI/RevitDropDown.cs.

Code private Element GetInputElement() { var inputNode = InPorts[0].Connectors[0].Start.Owner; var index = InPorts[0].Connectors[0].Start.Index;

        var identifier = inputNode.GetAstIdentifierForOutputIndex(index).Name;

        if (EngineController == null) return null;
        var data = this.EngineController.GetMirror(identifier).GetData();

        object family = data.IsCollection ? 
            data.GetElements().FirstOrDefault() : 
            data.Data;

        var elem = family as Revit.Elements.Element;

        return null == elem ? null : elem.InternalElement;
      }

when I try to do the same I do not get any usefull data i return.

mjkkirschner commented 8 years ago

@NicklasOestergaard check these two samples: https://github.com/DynamoDS/Dynamo/wiki/How-To-Create-Your-Own-Nodes scroll down the bottom to see use of mirror in color range node.

see the DynamoSamples https://github.com/DynamoDS/DynamoSamples

for some UI nodes which show BuildOutputAST method being used to compute some simple results based on the AST of the input nodes.

NicklasOestergaard commented 8 years ago

@mjkkirschner Thank you. That was just what I was looking for. Where do I find the .dll's for "using Dynamo.Graph.Nodes;" and "using Dynamo.Graph.Nodes;"?

mjkkirschner commented 8 years ago

If you open the dynamo solution with visual studio you can see that the Dynamo.Graph.Nodes namespace is inside of the project DynamoCore - most of the projects in the solution compile to .dlls with the same name I believe.

NicklasOestergaard commented 8 years ago

@mjkkirschner When I add a reference to C:\Program Files\Dynamo 0.9\DynamoCore.dll I stil get this error "The type or namespace name 'Graph' does not exist in the namespace 'Dynamo' (are you missing an assembly reference?)". Samething if I load dynamocore.dll from DynamoSamples-0.9.0\src\packages\DynamoVisualProgramming.Core.0.9.0-beta1\lib\net45.

If i loade from DynamoSamples-master\src\packages\DynamoVisualProgramming.Core.0.9.1-beta1\lib\net45\DynamoCore.dll Then I have Dynamo.Graph.Nodes but I then I get this error "Reference to type 'NodeModel' claims it is defined in 'DynamoCore', but it could not be found" How can I fix the error?

mjkkirschner commented 8 years ago

hi @NicklasOestergaard check this document: https://github.com/DynamoDS/Dynamo/wiki/API-Changes

you must be mixing versions of Dynamo / Dynamo assemblies . In .91 we performed a number of namespace changes so NodeModel moved from DynamoCore to Dynamo.Graph.Nodes... you need to use the correct version of the Dynamo assemblies for the version of Dynamo that you are targeting.

NicklasOestergaard commented 8 years ago

@mjkkirschner I deleted all my code and started all over again. I found out that I needed to implemented a Customization class from here http://dynamobim.org/forums/topic/no-output-in-dropdown-c/ Now it work. Thak you for your help.