[Unity6] How do I bind a callback to a Button in UIToolKit?

I am verifying MVVM for runtime in Unity6 while reading the official documentation.

For example, I know that I can write the following when binding to Label.text.


var label = element.Q<Label>("SampleLabel");
label.SetBinding(
    new BindingId(nameof(Label.text)),
    new DataBinding()
    {
        dataSource = viewModel,
        dataSourcePath = PropertyPath.FromName(nameof(ViewModel.Label)),
        dataSourceType = typeof(string),
        bindingMode = BindingMode.ToTarget,
        updateTrigger = BindingUpdateTrigger.OnSourceChanged,
    }
);

However, since Button.clickable does not have a [CreateProperty] attribute, it does not appear to be possible to do the binding with this technique.

In writing data binding in code like this, how should I set up the binding for Button.clickable?

I understand that callbacks can be added by writing “Button clicked += ()=>{}”, but I would prefer to have function name based binding like Xamarin or WPF.

(This is because it allows us to clearly separate the design of the UI from the coding of the logic. Of course, we know that we need to prepare libraries for connections like ReactiveProperty).

I would be happy to write the following…
(or if we could bind the methods directly)

View


var button = element.Q<Button>("SampleButton");
button.SetBinding(
    new BindingId(nameof(Button.clickable)),
    new DataBinding()
    {
        dataSource = viewModel,
        dataSourcePath = PropertyPath.FromName(nameof(ViewModel.OnClick)),
        dataSourceType = typeof(Clickable),
        bindingMode = BindingMode.ToTarget,
        updateTrigger = BindingUpdateTrigger.OnSourceChanged,
    }
);

ViewModel

public class ViewModel
{
    private Clickable _onClick;
    [CreateProperty]
    public Clickable OnClick
    {
        get
        {
            return _onClick;
        }
    }
    public ViewModel()
    {
        _onClick = new Clickable(OnClickCallback)
    }
    private void OnClickCallback()
    {
        UnityEngine.Debug.Log("Click!");
    }
}

Does anyone have any methods or ideas for this?

2 Likes

After seeing this post, I have tried to solve the same problem in different ways, but the attempts are not successful.

I don’t know how to bind Action/Command execution in a dynamic scenario without automatic binding. Registering Clickable from user’s point of view seems not that necessary task.

Callbacks and handlers, for any kind of VisualElement use EventBase<T> children. I don’t think you can directly pass a callable struct to an action. But you can use the ClickEvent callback:

var myButton = myView.Q<Button>("MyButton");
myButton.RegisterCallback<ClickEvent>(OnButtonClicked);

See the documentation for more : Unity - Manual: Click events

There is an example of a way to solve this issue by using UxmlObjects here. It does require some code to get things setup but once ready you can then use UXML to configure various behaviours such as button clicks. See the ButtonBehaviour example in the linked page.

1 Like

Thanks everyone.
Finally, I decided to stop with the method name-based binding and write a program that adds the method to the target VisualElement’s Manipulator.

ForExample:

View
This view internally looks for a button with elementName and adds a manipulator to it.

private readonly CallbackableElement<Button> _buttonElement = CallbackableElement.Create<Button>(
    elementName,
    callback: OnClick
);

I’m interested in your usecase, could you elaborate a bit more what you did ? I do agree that the current way of registering callbacks to buttons is broken. Thanks !