Hello!
I’m trying to write a simple Inventory System, but I have a problem with ReorderableList which I want to implement in EditorWindow (not in the Editor).
I read the article aboud ReorderableLists from this article: Unity: make your lists functional with ReorderableList
and I know that instead of OnInspectorGUI function, I have OnGUI method, but when I’m implementing this, I’m able to see only the empty ReorderableList in my window (even if data source for list isn’t empty),when I click this, the list disappears and I’m getting the hundreds of NullReferenceExceptions.
I would be very grateful if someone could give me a simple code snippet about using those lists in the EditorWindows (Additionaly I need the drawElementcallback)
That article has a complete, working example. There’s a pastebin link at the bottom with the full source code. In the article, and in the source code, you’ll see that you need to initialize the list first, usually in an OnEnable method.
@TonyLi
Yes yes,but as I said earlier, this article is only about the Editor, but I need an example on EditorWindow.
I have solved a half of problem,because Now I’m displaying in my window the ReorderableList properly, I can even add and remove Items, but When I will close and open again my window, I’m getting NullReferenceException, and the list disappears, but when I reload the Unity, the list (and the Items) looks just like I want.
In your OnEnable method, you still need to initialize your list and assign callback methods. The article author uses anonymous methods, but you can just as easily assign named methods. You can use a static variable to keep track of the current selection, or check Selection.
For example, say your editor window works on the currently-selected GameObject, and it edits a list inside a script named Inventory:
public class Inventory : MonoBehaviour {
public List<Item> items;
You need an OnEnable like this example:
ReorderableList list = null;
void OnEnable() {
var inventory = (Selection.activeGameObject != null) ? Selection.activeGameObject.GetComponent<Inventory>() : null;
if (inventory != null) {
list = new ReorderableList(inventory.items, typeof(item), true, true, true, true);
// (Assign your callbacks here if needed.)
}
}
void OnGUI() {
if (list != null) {
list.DoLayoutList();
} else {
EditorGUILayout.Label("Select a GameObject with an Inventory component.");
}
}
@TonyLi
It doesn’t work.
Here is my complete source code of the Window:
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections;
using System;
public class InventoryEditorWindow : EditorWindow
{
ItemDatabaseObject _DatabaseObject;
SerializedObject so;
public ReorderableList list = null;
public static InventoryEditorWindow Instance { get;set; }
public static bool IsOpened
{
get { return Instance != null; }
}
public static void ShowWindow(ItemDatabaseObject _itemDatabaseObject)
{
GetWindow<InventoryEditorWindow>("InventoryEditor");
Instance._DatabaseObject = _itemDatabaseObject;
}
void OnEnable()
{
Instance = this;
so = new SerializedObject(_DatabaseObject);
list = new ReorderableList(so, so.FindProperty("ItemList"));
list.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = list.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.PropertyField(
new Rect(rect.x, rect.y, 60, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("Name"), GUIContent.none);
};
}
void OnDisable()
{
}
void OnGUI()
{
so.Update();
list.DoLayoutList();
so.ApplyModifiedProperties();
}
}
The ItemDatabaseObject is just an ScriptableObject which is holding the Items.
As I mentioned, the ReorderableList is looking fine, but when I close it,and then open again, It disappears until I will reload the script, but the Items of the List are saved just like I want.
It’s just an execution order problem. You shouldn’t reference Instance in ShowWindow because it won’t have been set correctly yet. It gets set afterward in OnEnable. Try something like this, which makes DatabaseObject static and sets it in ShowWindow:
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections;
using System;
public class InventoryEditorWindow : EditorWindow
{
public static ItemDatabaseObject DatabaseObject { get; private set; }
SerializedObject so;
public ReorderableList list = null;
public static InventoryEditorWindow Instance { get;set; }
public static bool IsOpened
{
get { return Instance != null; }
}
public static void ShowWindow(ItemDatabaseObject _itemDatabaseObject)
{
DatabaseObject = _itemDatabaseObject;
GetWindow<InventoryEditorWindow>("InventoryEditor");
//Instance._DatabaseObject = _itemDatabaseObject;
}
void OnEnable()
{
Instance = this;
so = new SerializedObject(DatabaseObject);
list = new ReorderableList(so, so.FindProperty("ItemList"));
list.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = list.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
EditorGUI.PropertyField(
new Rect(rect.x, rect.y, 60, EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("Name"), GUIContent.none);
};
}
void OnDisable()
{
}
void OnGUI()
{
so.Update();
list.DoLayoutList();
so.ApplyModifiedProperties();
}
}
@TonyLi
At first, your solution wasn’t helpful, because after saving the code, and reloading the Unity, everything were the same, I don’t know, maybe It’s Visual Studio’s fault, but now everything works and I hope It will work forever.
Thank you for your help .
@TonyLi
I’m sorry but I have to ask another question, but also about ReorderableLists.
I want to display in ReorderableList fields of ItemProperty, which has the Item Selected in the another ReorderableList.
I’m initializing the new ReorderableList like this:
itemDataPropertyList = new ReorderableList(EditedItem.Properties, typeof(ItemProperty), true, true, true, true);
But I’m getting the NullReferenceExceptions (again, I really hate them), and the ReorderableList doesn’t display.
I also need to Reinitialize the ReorderableList, but you said that I have to do this in OnEnable();
(EditedItem is null at the beginning, but It’s getting a value when I will select some item from another ReorderableList)
if (0 <= itemDataPropertyList.index && itemDataPropertyList.index < itemDataPropertyList.count)
{
var element = itemDataPropertyList.serializedProperty.GetArrayElementAtIndex(index);
}