Skip to content

Instantly share code, notes, and snippets.

@karljj1
Last active February 13, 2024 14:04
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save karljj1/74f444e0a2810f6dabba85f44cf6f77f to your computer and use it in GitHub Desktop.
Save karljj1/74f444e0a2810f6dabba85f44cf6f77f to your computer and use it in GitHub Desktop.
Serializing a Dictionary in a VisualElement (Unity 2023.2.0a9)
using System;
using System.Collections.Generic;
using UnityEngine.UIElements;
[Serializable]
class DictItem
{
public int key;
public string value;
}
[Serializable]
class MyDictionary : Dictionary<int, string>
{
// Shown in the inspector
public List<DictItem> dictItems = new List<DictItem>();
}
// Use the dictionary in an element
[UxmlElement]
public partial class DictionaryExample : VisualElement
{
[UxmlAttribute]
internal MyDictionary myDictionary
{
get;
set;
}
}
using System;
using System.Collections.Generic;
using System.Text;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using Random = UnityEngine.Random;
// Convert to and from UXML
class DictConverter : UxmlAttributeConverter<MyDictionary>
{
public override MyDictionary FromString(string value)
{
var d = new MyDictionary();
var items = value.Split(',', StringSplitOptions.RemoveEmptyEntries);
foreach (var item in items)
{
var fields = item.Split('|');
var fieldKey = int.Parse(fields[0]);
var fieldValue = fields[1];
// For serializing in the inspector
d.dictItems.Add(new DictItem
{
key = fieldKey,
value = fieldValue
});
// For the actual dictionary
d[fieldKey] = fieldValue;
}
return d;
}
public override string ToString(MyDictionary value)
{
var sb = new StringBuilder();
foreach(var kvp in value.dictItems)
{
sb.Append(kvp.key);
sb.Append("|");
sb.Append(kvp.value);
sb.Append(',');
}
return sb.ToString();
}
}
[CustomPropertyDrawer(typeof(MyDictionary))]
class MyCustomDrawerPropertyDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var items = property.FindPropertyRelative("dictItems");
var list = new ListView();
list.headerTitle = "My Dict";
list.showFoldoutHeader = true;
list.showAddRemoveFooter = true;
list.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight;
list.makeItem = () =>
{
var row = new VisualElement { style = { flexDirection = FlexDirection.Row } };
row.Add(new IntegerField { name = "key", style = { flexGrow = 1 } });
row.Add(new TextField { style = { flexGrow = 1 } });
row.Q<IntegerField>().RegisterValueChangedCallback(evt =>
{
var keys = list.Query<IntegerField>("key").ToList();
// Reset and collect duplicates
var allKeys = new Dictionary<int, List<VisualElement>>();
foreach (var key in keys)
{
key.parent.style.backgroundColor = StyleKeyword.Initial;
if (!allKeys.TryGetValue(key.value, out var list))
{
list = new List<VisualElement>();
allKeys.Add(key.value, list);
}
list.Add(key.parent);
}
// Mark duplicates
foreach (var kvp in allKeys)
{
if (kvp.Value.Count > 1)
{
Random.InitState(kvp.Key);
var color = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
foreach (var key in kvp.Value)
{
key.style.backgroundColor = color;
}
}
}
});
return row;
};
list.bindItem += (ve, i) =>
{
var prop = items.GetArrayElementAtIndex(i);
ve.Q<IntegerField>()?.BindProperty(prop.FindPropertyRelative("key"));
ve.Q<TextField>()?.BindProperty(prop.FindPropertyRelative("value"));
};
list.BindProperty(items);
return list;
}
}
@karljj1
Copy link
Author

karljj1 commented Mar 27, 2023

This example shows how a dictionary can be serialized into a UxmlAttribute.
Note this requires Unity 2023.2.0a9+

Dictionary example

@karljj1
Copy link
Author

karljj1 commented Mar 31, 2023

dict

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment