I am experiencing confusion over the differences between Editor and EditorWindow when working with UIElements. I was working through Example_09 to try and breakdown how ListViews work, and while I managed to get a logically similar script functioning for an EditorWindow, when I modified the script slightly to be a scriptable object everything worked but the list view. The only differences are moving the initialization logic from OnEnabled (for the EditorWindow) to CreateInspectorGUI (for the scriptable Object) and in the ScriptableObject/Editor version a new visual element is created for the root, where in the EditorWindow root is assigned to the built in “rootVisualElement” I’m not fully certain if this is a bug or if there is an oversight in my understanding of how this all works, but some clarification would be appreciated.
This is the EditorWindow
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
#endif
public class ItemCollection : ScriptableObject
{
public ItemDescription[] Items = new ItemDescription[0];
}
[System.Serializable]
public class ItemDescription
{
public string Name;
public Texture Icon;
}
#if UNITY_EDITOR
[CustomEditor(typeof(ItemCollection))]
public class ItemDescriptionEditor : EditorWindow
{
VisualElement root;
VisualTreeAsset visualTree;
StyleSheet styleSheet;
ListView wow;
public ItemDescription[] Items = { new ItemDescription(), new ItemDescription() };
[MenuItem("Window/ItemCollection")]
public static void getWin()
{
GetWindow<ItemDescriptionEditor>();
}
public void OnEnable()
{
visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/Editor/ItemCollection.uxml");
styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Examples/Editor/styles.uss");
root = rootVisualElement;
root.style.flexDirection = FlexDirection.Row;
VisualElement visualTreeElement = visualTree.CloneTree();
wow = visualTreeElement.Query<ListView>("Items");
InitListView(wow);
wow.itemsSource = Items;//((ItemCollection)target).Items;
wow.bindItem = BindItem;
wow.makeItem = MakeItem;
root.schedule.Execute(Refresh);
AddListView(wow);
}
public void Refresh()
{
wow.Refresh();
}
private void InitListView(ListView listView)
{
listView.selectionType = SelectionType.Multiple;
listView.styleSheets.Add(styleSheet);
listView.onItemChosen += obj => Debug.Log(obj);
listView.onSelectionChanged += objects => Debug.Log(objects);
listView.style.flexGrow = 1f;
listView.style.flexShrink = 0f;
listView.style.flexBasis = 0f;
}
private void AddListView(ListView listView)
{
var col = new VisualElement();
col.style.flexGrow = 1f;
col.style.flexShrink = 0f;
col.style.flexBasis = 0f;
col.Add(new Label() { text = listView.viewDataKey });
col.Add(listView);
root.Add(col);
}
[MenuItem("Assets/CreateObject/ItemDescription")]
public static void Create()
{
Vivi.Utilities.UtilityScriptableObject.CreateAsset<ItemCollection>();
}
public void BindItem(VisualElement element, int index)
{
(element.ElementAt(0) as Label).text = "Wow";
element.viewDataKey = "box" + index;
}
public VisualElement MakeItem()
{
var box = new VisualElement();
box.style.flexDirection = FlexDirection.Row;
box.style.flexGrow = 1f;
box.style.flexShrink = 0f;
box.style.flexBasis = 0f;
box.Add(new Label("Wow"));
box.Add(new Button(() => { }) { text = "Button" });
return box;
}
}
#endif
Vs the ScriptableObject and it’s Editor
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
#endif
public class ItemCollection : ScriptableObject
{
public ItemDescription[] Items = new ItemDescription[0];
}
[System.Serializable]
public class ItemDescription
{
public string Name;
public Texture Icon;
}
#if UNITY_EDITOR
[CustomEditor(typeof(ItemCollection))]
public class ItemDescriptionEditor : Editor
{
VisualElement root;
VisualTreeAsset visualTree;
StyleSheet styleSheet;
ListView wow;
public ItemDescription[] Items = { new ItemDescription(), new ItemDescription() };
public override VisualElement CreateInspectorGUI()
{
visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/Editor/ItemCollection.uxml");
styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Examples/Editor/styles.uss");
root = new VisualElement();
root.style.flexDirection = FlexDirection.Row;
VisualElement visualTreeElement = visualTree.CloneTree();
wow = visualTreeElement.Query<ListView>("Items");
InitListView(wow);
wow.itemsSource = Items;//((ItemCollection)target).Items;
wow.bindItem = BindItem;
wow.makeItem = MakeItem;
root.schedule.Execute(Refresh);
AddListView(wow);
return root;
}
public void Refresh()
{
wow.Refresh();
}
private void InitListView(ListView listView)
{
listView.selectionType = SelectionType.Multiple;
listView.styleSheets.Add(styleSheet);
listView.onItemChosen += obj => Debug.Log(obj);
listView.onSelectionChanged += objects => Debug.Log(objects);
listView.style.flexGrow = 1f;
listView.style.flexShrink = 0f;
listView.style.flexBasis = 0f;
}
private void AddListView(ListView listView)
{
var col = new VisualElement();
col.style.flexGrow = 1f;
col.style.flexShrink = 0f;
col.style.flexBasis = 0f;
col.Add(new Label() { text = listView.viewDataKey });
col.Add(listView);
root.Add(col);
}
[MenuItem("Assets/CreateObject/ItemDescription")]
public static void Create()
{
Vivi.Utilities.UtilityScriptableObject.CreateAsset<ItemCollection>();
}
public void BindItem(VisualElement element, int index)
{
(element.ElementAt(0) as Label).text = "Wow";
element.viewDataKey = "box" + index;
}
public VisualElement MakeItem()
{
var box = new VisualElement();
box.style.flexDirection = FlexDirection.Row;
box.style.flexGrow = 1f;
box.style.flexShrink = 0f;
box.style.flexBasis = 0f;
box.Add(new Label("Wow"));
box.Add(new Button(() => { }) { text = "Button" });
return box;
}
}
#endif