Change the Value of a Toggle without triggering OnValueChanged?

Can You change the value of a toggle without having it call it’s OnValueChanged functions?

When the user presses the toggle i need some code to happen but sometimes i need to change the Active state of the toggle in code without triggering it’s OnValueChanged. Is there a way to “silently” switch the state of a toggle?

3 Likes

currently no there is not although internally we do have support for not sending it. i’ll see if someone has a reason not to expose this.

2 Likes

It would be super helpful, I’m converting some of our old UI to the new system and I noticed that we would have some potential infinite loops if we used the OnValueChanged for a lot of things.

6 Likes

So it seems like its not something we’ll add for V1 right now. I’m sure there should be some way to avoid the infinite loop.

Its pretty problematic whenever you are using one of the new UI elements to represent another piece of data that can change from something that isn’t direct user input.

For example if I have int X and I make a slider so the user can change the value of int x. I would make the slider’s OnValueChanged change the value of X. Then if for some reason the value X changes because of some other code I have to update the value of the slider so it accurately reflects the new value of X. Setting the value of the slider in code to the new value of X would trigger the sliders OnValueChanged which would set the value of X again.

If your OnValueChanged is doing more than just setting the value of something it can get pretty annoying.

3 Likes

For toggles you can use OnClick event of EventTrigger component instead of OnValueChanged. It solved loop problem in my case.

6 Likes

Same problem here. I need to update a slider’s value based on a movie’s playback position. I would prefer not getting an OnValueChanged event when I change the slider’s value through code. Only when the user changes it by dragging the thumb, should the event be fired.

2 Likes

Same. i have a slider onValueChange that changes when i change the value from code

i would like and expect onValueChange to happen only when the user changes the value not when i do in code

as a workaround i have to wrap all my value access with an ignore bool flag and check that in the scroll change handler

1 Like

Another workaround that I just implemented is to instead of modifying the value that the slider represents, actually manipulate the slider instead. For instance, lets say you want a slider to represent music volume. But other things manipulate the volume as well (e.g. PlayerPrefs). Have them all go through the slider to change the volume, nothing changes the volume directly. The ONLY thing that accesses the volume is the slider, period. So it would go like this:

PlayerPrefs → Slider → Volume
Human → Slider → Volume

instead of:

PlayerPrefs → Volume
Human → Slider → Volume

This basically means you cannot do a Model View Controller architecture using the new UI system without adding quite ugly code (I am currently writing said ugly code). If you cannot change a control’s state without triggering the entire UI logic, then the authoritative state is stored inside the UI control (so, the View), and not inside the Model.

I have player option data which is loaded from PlayerPrefs, and I need to set the player option UI to reflect that data. There is no way around this, and every game with any kind of options must surely do this, and run into this exact same problem.

When I set the UI control’s state, that forcibly triggers the same logic as if the player had clicked on it. Which in my case means that initializing the player option UI does the same thing as if the player clicks every single control, which is problematic in my case.

I now have to implement “React to this button except when this flag says we’re initializing the UI” logic. The solution by Daniel above could work too, but it has its own drawbacks.

grumble

12 Likes

Same problem. I want to have ignoreEvents variable in every UI element for example

2 Likes

I have a similar problem with the new UI. Working on an RTS-like game and want UI toggles to represent the states of units when they get selected. I wondered if there was a decent way to (re)set UI elements without triggering any functions.

The thing that baffles me is if you look at the source for Toggle, in the (private) Set function that takes an argument dictating whether or not to send the callback, it does an early out if the value didn’t change. So I’m not sure why this infinite loop problem occurs in the first place.

Edit: Whoops, never mind. I see why that wouldn’t solve the problem.

In this case, I don’t use the OnValueChanged methods.
Instead, I implement the interface IPointerClickHandler in the class and then I use the method:
public void OnPointerClick(PointerEventData data)
This method is called only when the user clicks on the toggle and not when the value is changed by code.

4 Likes

This would be super helpful.

I hope this gets addressed soon.

Please add this, as it is very needed.

I added a ticket, so if you need this, please vote: http://feedback.unity3d.com/suggestions/expose-unityengine-dot-ui-dot-toggle-dot-set-bool-value-bool-sendcallback

1 Like
using UnityEngine;
using UnityEngine.UI;
using System.Reflection;

public static class UISetExtensions
{
    static MethodInfo toggleSetMethod;

    static UISetExtensions()
    {
        MethodInfo[] methods = typeof(Toggle).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);
        for (var i = 0; i < methods.Length; i++)
        {
            if (methods[i].Name == "Set" && methods[i].GetParameters().Length == 2)
            {
                toggleSetMethod = methods[i];
                break;
            }
        }
    }
    public static void Set(this Toggle instance, bool value, bool sendCallback)
    {
        toggleSetMethod.Invoke(instance, new object[] {value, sendCallback});
    }
}

:):slight_smile:

7 Likes

I’m not sure if this should count as reflection abuse or pure elegance, but either way I love it! Thanks for sharing! =)

1 Like

Think of it as a temporary hack until unity introduces a proper solution.