Why can't I query the listview element?

I’m using UIToolkit to draw a serialized dictionary. I can see the listview element using the UI Toolkit debugfer, but I can’t query it in the code. How can I get a reference to the listview?

using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

namespace Attributes.Editor
{
    [CustomPropertyDrawer(typeof(SerializedDictionary<,>))]
    public class SerializedDictionaryDrawer : PropertyDrawer
    {
        private PropertyField elem;
        
        public override VisualElement CreatePropertyGUI(SerializedProperty property)
        {
            elem = new PropertyField(property);
            elem.name = "test";
            elem.RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
            
            void OnAttachToPanel(AttachToPanelEvent evt)
            {
                var listview = elem.Q<ListView>();
                Debug.Log($"listview:{listview == null}");
            }
            
            return elem;
        }
        
        

        private void OnItemIndexChanged(int id1, int id2)
        {
            Debug.Log($"id1:{id1},id2:{id2}");
        }
    }
}

I want to make a serialized dictionary, get the listview, listen to the element index change event, and then update the _indexByKey dictionary

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

[Serializable]
public class SerializedDictionary<TK,TV> : IDictionary<TK,TV>,ISerializationCallbackReceiver
{
    [Serializable]
    private struct KeyValuePair
    {
        [SerializeField] private TK _key;
        [SerializeField] private TV _value;

        public KeyValuePair(TK key, TV value)
        {
            _key = key;
            _value = value;
        }
        
        public TK key{ get => _key; set => _key = value;}
        public TV value { get => _value; set => _value = value;}
        
    }


    [SerializeField] 
    private List<KeyValuePair> _pairs = new();

    
    private readonly Dictionary<TK, int> _indexByKey = new();
    private readonly Dictionary<TK, TV> _dictionary = new();

    [SerializeField, HideInInspector] private bool error;
    
    public SerializedDictionary(){}

    public SerializedDictionary(IDictionary<TK, TV> source)
    {
        foreach (var pair in source)
        {
            Add(pair.Key,pair.Value);
        }
    }
    

    public int Count => _dictionary.Count;
    public bool IsReadOnly => false;

    public ICollection<TK> Keys => _dictionary.Keys;
    public ICollection<TV> Values => _dictionary.Values;
    
    public TV this[TK key]
    {
        get => _dictionary[key];
        set
        {
            _dictionary[key] = value;
            if (_indexByKey.ContainsKey(key))
            {
                var index = _indexByKey[key];
                _pairs[index] = new KeyValuePair(key, value);
            }
            else
            {
                _pairs.Add(new KeyValuePair(key, value));
                _indexByKey.Add(key,_pairs.Count - 1);
            }
        }
    }
    public void Add(TK key, TV value)
    {
        _pairs.Add(new KeyValuePair(key,value));
        _dictionary.Add(key,value);
        _indexByKey.Add(key,_pairs.Count - 1);
    }

    public bool ContainsKey(TK key)
    {
        return _dictionary.ContainsKey(key);
    }

    public bool Remove(TK key)
    {
        if (_dictionary.Remove(key))
        {
            var index = _indexByKey[key];
            // var removed = _pairs[index];
            var last = _pairs[^1];
            var lastKey = last.key;
            var lastIndex = _pairs.Count - 1;
            
            if (_pairs.Count > 1)
            {
                _pairs[index] = last;
                // _pairs[lastIndex] = removed;
                // _indexByKey[key] = lastIndex;
                _indexByKey[lastKey] = index;
            }
            
            _pairs.RemoveAt(lastIndex);
            _indexByKey.Remove(key);
            return true;
        }

        return false;
    }
    
    
    public bool TryGetValue(TK key, out TV value)
    {
        return _dictionary.TryGetValue(key, out value);
    }
    
    public void Clear()
    {
        _pairs.Clear();
        _dictionary.Clear();
        _indexByKey.Clear();
    }

    public Dictionary<TK, TV> BuildNativeDictionary()
    {
        return new Dictionary<TK, TV>(_dictionary);
    }
    
    public void Add(KeyValuePair<TK, TV> pair)
    {
        Add(pair.Key,pair.Value);
    }
    
    public bool Contains(KeyValuePair<TK, TV> pair)
    {
        if (_dictionary.TryGetValue(pair.Key,out var value))
        {
            return EqualityComparer<TV>.Default.Equals(value, pair.Value);
        }

        return false;
    }

    public void CopyTo(KeyValuePair<TK, TV>[] array, int arrayIndex)
    {
        ICollection collection = _dictionary;
        collection.CopyTo(array,arrayIndex);
    }

    public bool Remove(KeyValuePair<TK, TV> pair)
    {
        if (_dictionary.TryGetValue(pair.Key,out var value))
        {
            var isEqual = EqualityComparer<TV>.Default.Equals(value, pair.Value);
            if (isEqual)
            {
                return Remove(pair.Key);
            }
        }

        return false;
    }

   

    public IEnumerator<KeyValuePair<TK, TV>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

   
    public static implicit operator Dictionary<TK, TV>(SerializedDictionary<TK, TV> serializedDictionary)
    {
        return serializedDictionary._dictionary;
    }

    public static implicit operator SerializedDictionary<TK, TV>(Dictionary<TK, TV> dictionary)
    {
        return new SerializedDictionary<TK, TV>(dictionary);
    }


    
    public void OnBeforeSerialize()
    {
      
    }

    public void OnAfterDeserialize()
    {
        
        _dictionary.Clear();
        _indexByKey.Clear();
        error = false;

        for (int i = 0; i < _pairs.Count; i++)
        {
            var key = _pairs[i].key;
            if (key != null && !ContainsKey(key))
            {
                _dictionary.Add(key,_pairs[i].value);
                _indexByKey.Add(key,i);
            }
            else
            {
                error = true;
            }
        }
    }
    
    
}

PropertyField binding is, for some reason, asynchronous. It’s an annoying choice and it makes it difficult to query specific visual elements.

Question is what do you want to do with the ListView specifically? If you want custom behaviour for it, you should instance a list view, configure, and bind it yourself.

You can see how Unity specifically binds a ListView here: UnityCsReference/Editor/Mono/UIElements/Controls/PropertyField.cs at master · Unity-Technologies/UnityCsReference · GitHub

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

[Serializable]
public class SerializedDictionary<TK,TV> : IDictionary<TK,TV>,ISerializationCallbackReceiver
{
    [Serializable]
    private struct KeyValuePair
    {
        [SerializeField] private TK _key;
        [SerializeField] private TV _value;

        public KeyValuePair(TK key, TV value)
        {
            _key = key;
            _value = value;
        }
        
        public TK key{ get => _key; set => _key = value;}
        public TV value { get => _value; set => _value = value;}
        
    }

    //由于字典不能序列化,所以要将字典的数据转化为列表。用键值对存储字典的数据
    // 列表包含键值对,同一个键的数据在列表的索引是不一样的。
    // 所以下面用一个字典来存储键对应的索引
    [SerializeField] 
    private List<KeyValuePair> _pairs = new();

    // 一个字典只能存在唯一键,这个键对应列表的索引
    private readonly Dictionary<TK, int> _indexByKey = new();
    private readonly Dictionary<TK, TV> _dictionary = new();

    [SerializeField, HideInInspector] private bool error;
    
    public SerializedDictionary(){}

    public SerializedDictionary(IDictionary<TK, TV> source)
    {
        foreach (var pair in source)
        {
            Add(pair.Key,pair.Value);
        }
    }
    

    public int Count => _dictionary.Count;
    public bool IsReadOnly => false;

    public ICollection<TK> Keys => _dictionary.Keys;
    public ICollection<TV> Values => _dictionary.Values;
    
    public TV this[TK key]
    {
        get => _dictionary[key];
        set
        {
            _dictionary[key] = value;
            if (_indexByKey.ContainsKey(key))
            {
                var index = _indexByKey[key];
                _pairs[index] = new KeyValuePair(key, value);
            }
            else
            {
                _pairs.Add(new KeyValuePair(key, value));
                _indexByKey.Add(key,_pairs.Count - 1);
            }
        }
    }
    public void Add(TK key, TV value)
    {
        _pairs.Add(new KeyValuePair(key,value));
        _dictionary.Add(key,value);
        _indexByKey.Add(key,_pairs.Count - 1);
    }

    public bool ContainsKey(TK key)
    {
        return _dictionary.ContainsKey(key);
    }

    public bool Remove(TK key)
    {
        if (_dictionary.Remove(key))
        {
            var index = _indexByKey[key];
            // var removed = _pairs[index];
            var last = _pairs[^1];
            var lastKey = last.key;
            var lastIndex = _pairs.Count - 1;
            
            if (_pairs.Count > 1)
            {
                _pairs[index] = last;
                // _pairs[lastIndex] = removed;
                // _indexByKey[key] = lastIndex;
                _indexByKey[lastKey] = index;
            }
            
            _pairs.RemoveAt(lastIndex);
            _indexByKey.Remove(key);
            return true;
        }

        return false;
    }
    
    
    public bool TryGetValue(TK key, out TV value)
    {
        return _dictionary.TryGetValue(key, out value);
    }
    
    public void Clear()
    {
        _pairs.Clear();
        _dictionary.Clear();
        _indexByKey.Clear();
    }

    public Dictionary<TK, TV> BuildNativeDictionary()
    {
        return new Dictionary<TK, TV>(_dictionary);
    }
    
    public void Add(KeyValuePair<TK, TV> pair)
    {
        Add(pair.Key,pair.Value);
    }
    
    public bool Contains(KeyValuePair<TK, TV> pair)
    {
        if (_dictionary.TryGetValue(pair.Key,out var value))
        {
            return EqualityComparer<TV>.Default.Equals(value, pair.Value);
        }

        return false;
    }

    public void CopyTo(KeyValuePair<TK, TV>[] array, int arrayIndex)
    {
        ICollection collection = _dictionary;
        collection.CopyTo(array,arrayIndex);
    }

    public bool Remove(KeyValuePair<TK, TV> pair)
    {
        if (_dictionary.TryGetValue(pair.Key,out var value))
        {
            var isEqual = EqualityComparer<TV>.Default.Equals(value, pair.Value);
            if (isEqual)
            {
                return Remove(pair.Key);
            }
        }

        return false;
    }

   

    public IEnumerator<KeyValuePair<TK, TV>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    //显示类型转化
    public static implicit operator Dictionary<TK, TV>(SerializedDictionary<TK, TV> serializedDictionary)
    {
        return serializedDictionary._dictionary;
    }

    public static implicit operator SerializedDictionary<TK, TV>(Dictionary<TK, TV> dictionary)
    {
        return new SerializedDictionary<TK, TV>(dictionary);
    }

    
    public void OnBeforeSerialize()
    {
       //已经通过_pairs填充了序列化数据了;
    }

    public void OnAfterDeserialize()
    {
        //通过_pair将数据填充到_dictionary,_indexByKey
        _dictionary.Clear();
        _indexByKey.Clear();
        error = false;

        for (int i = 0; i < _pairs.Count; i++)
        {
            var key = _pairs[i].key;
            if (key != null && !ContainsKey(key))
            {
                _dictionary.Add(key,_pairs[i].value);
                _indexByKey.Add(key,i);
            }
            else
            {
                error = true;
            }
        }
    }
    
    
}

I want to make a serialized dictionary, get the listview, listen to the element index change event, and then update the _indexByKey dictionary

Then like I said, you should be instancing and configuring the required visual elements yourself rather than using a PropertyField.