Last active
February 13, 2024 14:04
-
-
Save karljj1/74f444e0a2810f6dabba85f44cf6f77f to your computer and use it in GitHub Desktop.
Serializing a Dictionary in a VisualElement (Unity 2023.2.0a9)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This example shows how a dictionary can be serialized into a UxmlAttribute.
Note this requires Unity 2023.2.0a9+