變更事件(Change events)

當一個Element的值改變時,就會發送一個Change Event,例如使用者切換了(toggles)一個核取方塊(Checkbox),Change Event是一個帶有類型的事件(Typed Event),它含有這個Element先前的值和新值。由於Change Event是在新的值被賦值後才觸發,因此你無法透過取消Change Event的方式去來避免值的改變。

Event 描述 Trickles down Bubbles up Cancellable
ChangeEvent 當一個Element的值改變時,就會發送一個Change Event

專屬於Change Event的屬性

  • previousValue: 存放該Element先前的值 The previous value of the target control.
  • newValue: 存放該Element該要改變的新值

Change Event是一個通知事件(notification event)讓你可以在visual element的值改變時做出反應,例如:當使用者按下音樂核取方塊(Checkbox)那麼遊戲的音樂就應該都被關閉。

Change Event應用到所有有實作INotifyValueChanged<T>的controls其中<T>就是ChangeEvent,此外這個也被在內部使用,透過Data binding的方式來更新實體物件的屬性

避免觸發Change Event

如果你是透過程式碼更改control的值而觸發control的Change Event,你可以透過呼叫INotifyValueChange<T>中的SetValueWithoutNotify來更改control的值,並避免觸發Change Event

註冊Change Event
  1. 呼叫在Visual Element上的RegisterCallback<>()

    • 如果你想要在一個Element中監聽它的子Elements中是否有發生改變的話,可以使用
      1
      2
      3
      4
      5
      6
      7
      8
      // 使用RegisterCallback註冊callback
      rootVisualElement.RegisterCallback<ChangeEvent<bool>>(OnBoolChangedEvent);

      // callback方法,它會監聽bool值是否發生改變
      private void OnBoolChangedEvent(ChangeEvent<bool> evt)
      {
      // Handling code
      }
  2. 呼叫有實作INotifyValueChange的Visual Element上的RegisterValueChangedCallback()

    • 使用RegisterValueChangedCallback會比較方便因為它已經內建(build-in)好要傳值得類型
    • 取消註冊可以使用UnregisterValueChangedCallback
      1
      2
      3
      4
      5
      6
      var newToggle = new Toggle("Test Toggle");
      newToggle.RegisterValueChangedCallback(OnTestToggleChanged);
      private void OnTestToggleChanged(ChangeEvent<bool> evt)
      {
      // Handling code
      }
例子一:註冊兩個ChangeEvent,一個在toggle element上使用RegisterValueChangedCallback,另外一個在root element使用RegisterCallback

以下例子為示範如何使用ChangeEvent

  1. 在Assets > Scripts > Editor 下建立一個 C# Script ChangeEventTestWindow.cs
  2. 將以下程式碼複製到剛剛建立的C# Script中
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.UIElements;

    public class ChangeEventTestWindow : EditorWindow
    {
    private Toggle m_MyToggle;

    // 這個Attributes會在 Windows -> UI Tollkit 下加入一個 Change Event Test Window
    [MenuItem("Window/UI Toolkit/Change Event Test Window")]
    public static void ShowExample()
    {
    ChangeEventTestWindow wnd = GetWindow<ChangeEventTestWindow>();
    wnd.titleContent = new GUIContent("Change Event Test Window");
    }

    public void CreateGUI()
    {
    // 建立一個 toggle control
    m_MyToggle = new Toggle("Test Toggle") { name = "My Toggle" };
    rootVisualElement.Add(m_MyToggle);

    // 使用RegisterValueChangedCallback為這個 toggle control註冊OnTestToggleChanged
    m_MyToggle.RegisterValueChangedCallback(OnTestToggleChanged);

    // 使用RegisterCallback在root element註冊OnBoolChangedEvent,它必須要指定泛型
    rootVisualElement.RegisterCallback<ChangeEvent<bool>>(OnBoolChangedEvent);
    }

    private void OnBoolChangedEvent(ChangeEvent<bool> evt)
    {
    Debug.Log($"Toggle changed. Old value: {evt.previousValue}, new value: {evt.newValue}");
    }

    private void OnTestToggleChanged(ChangeEvent<bool> evt)
    {
    Debug.Log($"A bool value changed. Old value: {evt.previousValue}, new value: {evt.newValue}");
    }
    }
  3. 在Unity編輯器中找到 Window > UI Toolkit > Change Events Test Window
  4. 觀看結果
例子二:使用程式碼觸發事件的話,可以透過element上的SetValueWithoutNotify避免觸發Change Event
  • 將以下程式碼覆蓋到ChangeEventTestWindow.cs Script中
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.UIElements;

    public class ChangeEventTestWindow : EditorWindow
    {
    private Toggle m_MyToggle;

    [MenuItem("Window/UI Toolkit/Change Event Test Window")]
    public static void ShowExample()
    {
    GetWindow<ChangeEventTestWindow>().titleContent = new GUIContent("Change Event Test Window");
    }

    public void CreateGUI()
    {
    // 建立一個toggle並為其註冊callback
    m_MyToggle = new Toggle("Test Toggle") { name = "My Toggle" };
    m_MyToggle.RegisterValueChangedCallback((evt) => { Debug.Log("Change Event received"); });
    rootVisualElement.Add(m_MyToggle);

    // 建立一個button來更改toggle的值
    Button button01 = new Button() { text = "Toggle" };
    button01.clicked += () =>
    {
    // 這個會觸發Change Event
    m_MyToggle.value = !m_MyToggle.value;
    };
    rootVisualElement.Add(button01);

    // 建立另外一個button,但是使用SetValueWithoutNotify更改toggle的值,
    Button button02 = new Button() { text = "Toggle without notification" };
    button02.clicked += () =>
    {
    // 使用SetValueWithoutNotify()不會觸發Change Event
    m_MyToggle.SetValueWithoutNotify(!m_MyToggle.value);
    };
    rootVisualElement.Add(button02);
    }
    }
  • 觀看結果

Reference: https://docs.unity3d.com/Manual/UIE-Change-Events.html

評論