Convert IDictionary to Dictionary for ZeroTouchNode

Hi i’m trying to create a ZeroTouchNode that takes Dictionary as an input, and displays the keys as a dropdown combo box, and the values from the selected key in textboxes under.

I know that firslty the type from dynamo (IDictionary) needs to be translated to Dictionary for windows system.

As i referred from existing forum post: Input a dictionary from dynamo (DesignScript.Builtin.Dictionary) to a custom ZeroTouch node - Developers - Dynamo (dynamobim.com)

this is what i have so far:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.DesignScript.Runtime;
using Autodesk.DesignScript.Interfaces;


namespace PrintedGeometryGUI
{
    public class PrintingFormNode
    {
        public List<object> UI(IDictionary<string, List<int>> MaterialComposition)
        {
            List<object> listReturn = new List<object>();
            Dictionary<string, List<int>> materialComposition = DictionaryUtility.ConvertToDictionary(MaterialComposition);

            PrintingForm window = new PrintingForm(materialComposition);
            var res = window.ShowDialog();

            if (res.HasValue && res.Value)
            {
                string selectedKey = window.comboBox_material.SelectedItem.ToString();
                if (materialComposition.TryGetValue(selectedKey, out List<int> values))
                {
                    listReturn.Add(selectedKey);
                    listReturn.Add(values[0]); 
                    listReturn.Add(values[1]); 
                    listReturn.Add(values[2]); 
                }
            }

            return listReturn;
        }
    }
}

To which this is to convert the dictionary type:

using System.Collections.Generic;
using System.Linq;

namespace PrintedGeometryGUI
{
    public static class DictionaryUtility
    {
        public static Dictionary<string, List<int>> ConvertToDictionary(IDictionary<string, List<int>> inputDictionary)
        {
            Dictionary<string, List<int>> convertedDictionary = new Dictionary<string, List<int>>();

            foreach(var entry in inputDictionary) 
            { 
                convertedDictionary[(string)entry.Key] = (List<int>)entry.Value; 
            }
            return convertedDictionary;
        }

    }
}

And my windows form class:

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;


namespace PrintedGeometryGUI
{
    /// <summary>
    /// Interaktionslogik für UserControl1.xaml
    /// </summary>
    public partial class PrintingForm : Window
    {
        private Dictionary<string, List<int>> materialComposition;

        public PrintingForm(Dictionary<string, List<int>> materialComposition)
        {
            InitializeComponent();
            this.materialComposition = materialComposition;
            comboBox_material.ItemsSource = materialComposition.Keys;
        }

        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (comboBox_material.SelectedItem != null)
            {
                string selectedKey = comboBox_material.SelectedItem.ToString();
                if (materialComposition.TryGetValue(selectedKey, out List<int> values))
                {
                    
                    if (values.Count >= 3)
                    {
                        densityTextBox.Text = values[0].ToString();
                        initialYieldStressTextBox.Text = values[1].ToString();
                        structuralBuildUpRateTextBox.Text = values[2].ToString();
                    }
                }
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
        }

        private void cancel_button_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
            Close();
        }
    }
}

My node is giving an error saying “At least one element from source array could not be converted to target array type.”

Would appreciate any insights and help!

Are all your list values integer type?

1 Like

I would suggest to implement more checks on your ConvertToDictionary method. You can try something like this to see if the error is related with your input list:

public static Dictionary<string, List<int>> ConvertToDictionary(IDictionary<string, List<int>> inputDictionary)
        {
            var convertedDictionary = new Dictionary<string, List<int>>();

            // Check if inputDictionary is null
            if (inputDictionary == null)
            {
                throw new ArgumentNullException(nameof(inputDictionary), "Input dictionary cannot be null.");
            }

            // Iterate over the input dictionary and check types
            foreach (var entry in inputDictionary)
            {
                if (!(entry.Key is string))
                {
                    throw new InvalidCastException($"Key '{entry.Key}' is not of type string.");
                }

                if (!(entry.Value is List<int>))
                {
                    throw new InvalidCastException($"Value for key '{entry.Key}' is not of type List<int>.");
                }

                convertedDictionary[entry.Key] = entry.Value;
            }

            return convertedDictionary;
        }

I’m not a C# expert, but the urge to test the implementation of the MVVM pattern on a ZT node was too great.

And this topic is ideal for this exercise

here’s my solution with MVVM

2 Likes

hello there,
first, can you specifically show which line is causing the error? and instead of just showing the error from the node… without identifying which line is causing the error, it is a little bit hard to pinpoint the actual mistake.

second, you can use new Dictionary<string, List<int>>(MaterialComposition) to convert it into a Dictionary class instead of using your converter. Still, from your use case, I don’t see a need to convert it into a Dictionary class since there is no merit to it. (you are just using key and value which can be accessed via the IDictionary interface)

third, you should be using Class and ICollection instead of IDictionary for a better “best practice” when doing WPF-related stuff. By using List<Material>, where Material is a class that contains your custom property, conversion ain’t required which means no error will happen :smiley:
Example:

public class Material
{
    public string Name;
    public int Property1;
    public int Property2;
    public int Property3;
}
public Material UI(IDictionary<string, List<int>> MaterialComposition)
{
    List<Material> materials = new List<Material>();
    foreach(var item in MaterialComposition)
    {
        var value = item .Value;
        Material material = new Material()
        {
            Name = item.Key,
            Property1 = value[0],
            Property2 = value[1],
            Property3 = value[2],
        };
        materials.Add(material);
    }
    PrintingForm window = new PrintingForm(materials);
    //Continue to do your things
    ...
    ...
    ...
    //Finish doing your thing
    Material selectedItem = window.comboBox_material.SelectedItem;
    return selectedItem;
}

lastly, I would use a MultiReturn instead of List for your node (looks nicer and neater :slight_smile: )