Hello everyone. Could someone help me because I’m not sure how to implement listening for value changes in ListView items? My need is to create a custom ListView item that includes an enum field. Each value of the enum field corresponds to a specific template to be displayed, and if the enum field value is changed, the template displayed on the item should also change.
I suspect that the problem is caused by the ListView’s recycling feature and that I don’t know where I should unregister the listeners. This is causing confusion in the ListView (for example, the add and remove buttons stop working and throw Null Pointer Exceptions).
Here’s an example code. Also note that in the final version, the enumfield will include a binding path, and the selection of the enum will be written to a serialized property. I mention this in case it has any significance (e.g., from a binding perspective).
Thank you in advance for your help.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class CustomListViewItem : VisualElement
{
public enum Template
{
Template1,
Template2
}
public VisualTreeAsset template1 { get; set; }
public VisualTreeAsset template2 { get; set; }
private VisualElement templateContainer = null;
private VisualElement currentTemplate = null;
[UnityEngine.Scripting.Preserve]
public new class UxmlFactory : UxmlFactory<CustomListViewItem, UxmlTraits> { }
public new class UxmlTraits : VisualElement.UxmlTraits
{
UxmlAssetAttributeDescription<VisualTreeAsset> m_Template1 =
new UxmlAssetAttributeDescription<VisualTreeAsset> { name = "template-1" };
UxmlAssetAttributeDescription<VisualTreeAsset> m_Template2 =
new UxmlAssetAttributeDescription<VisualTreeAsset> { name = "template-2" };
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
var ate = ve as CustomListViewItem;
ate.template1 = m_Template1.GetValueFromBag(bag, cc);
ate.template2 = m_Template2.GetValueFromBag(bag, cc);
ate.Initialize();
}
}
public CustomListViewItem()
{
}
void Initialize()
{
var enumField = new EnumField(Template.Template1);
EventCallback<ChangeEvent<Enum>> valueChangedCallback = (evt) =>
{
Template template = (Template)Enum.ToObject(typeof(Template), evt.newValue);
this.UpdateContentTemplate(template);
};
enumField.RegisterValueChangedCallback(valueChangedCallback);
this.Add(enumField);
this.templateContainer = new VisualElement();
this.Add(this.templateContainer);
}
void UpdateContentTemplate(Template template)
{
if(this.currentTemplate != null)
{
this.templateContainer.Remove(this.currentTemplate);
this.currentTemplate = null;
}
if(template == Template.Template1)
{
this.currentTemplate = this.template1.CloneTree();
}else if(template == Template.Template2)
{
this.currentTemplate = this.template2.CloneTree();
}
if(this.currentTemplate != null)
{
this.templateContainer.Add(this.currentTemplate);
}
}
}