How to register System.Action as event callback

Assigning a method as a callback works directly:

7623823--948274--upload_2021-11-2_11-43-46.png

It appears registering an System.Action doesn’t work because we can’t implicitly convert System.Action to UIElements.Eventcallback

Is there is a solution to this? I feel like the old UI system had some sort of implicit conversion. I can create a new delegate of type and call the action but I think that’s wrapping a delegate in a delegate?

This is indeed how C# works in general, you can’t cast delegates from compatible types directly.

Your last solution of delegateCallback = new EventCallback<ChangeEvent<T>>(callback) is probably the easiest way to go. If you really need to avoid allocations at all costs, then you can always use the RegisterCallback<TEventType, TUserArgsType> method, where you can pass your Action<ChangeEvent> through the userArgs and avoid closing on it.

protected void RegisterChangeEventCallback<T>(VisualElement panel, string elementName, Action<ChangeEvent<T>> callback)
{
    var item = panel.Q(elementName);
    item.RegisterCallback<ChangeEvent<T>, Action<ChangeEvent<T>>>((e, a) => a(e), callback);
}

This will not allow you to as easily use UnregisterCallback later on, though, so you might want to reconsider, and your last solution was the easiest to read and most flexible in general.

If you really want to have some fun, the following (ugly) alternative would kind of work with UnregisterCallback too, as long as you don’t register multiple callbacks to the same type, in which case you would need more prewrapped helpers, and it starts to become quite messy.

private static class EventCallbackWrapper<TEvent>
{
    public static EventCallback<TEvent, Action<TEvent>> WrappedCallback = (e, a) => a(e);
}

protected void RegisterChangeEventCallback<T>(VisualElement panel, string elementName, Action<ChangeEvent<T>> callback)
{
    var item = panel.Q(elementName);
    item.RegisterCallback<ChangeEvent<T>, Action<ChangeEvent<T>>>(EventCallbackWrapper<ChangeEvent<T>>.WrappedCallback, callback);
}

protected void UnregisterChangeEventCallback<T>(VisualElement panel, string elementName)
{
    var item = panel.Q(elementName);
    item.UnregisterCallback<ChangeEvent<T>, Action<ChangeEvent<T>>>(EventCallbackWrapper<ChangeEvent<T>>.WrappedCallback);
}

Understood. Thank you and thanks for the alternatives, those were interesting to consider.