變更事件(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
呼叫在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
}
- 如果你想要在一個Element中監聽它的子Elements中是否有發生改變的話,可以使用
呼叫有實作
INotifyValueChange
的Visual Element上的RegisterValueChangedCallback()
- 使用RegisterValueChangedCallback會比較方便因為它已經內建(build-in)好要傳值得類型
- 取消註冊可以使用
UnregisterValueChangedCallback
1
2
3
4
5
6var newToggle = new Toggle("Test Toggle");
newToggle.RegisterValueChangedCallback(OnTestToggleChanged);
private void OnTestToggleChanged(ChangeEvent<bool> evt)
{
// Handling code
}
例子一:註冊兩個ChangeEvent
,一個在toggle element上使用RegisterValueChangedCallback
,另外一個在root element使用RegisterCallback
以下例子為示範如何使用ChangeEvent
- 在Assets > Scripts > Editor 下建立一個 C# Script
ChangeEventTestWindow.cs
- 將以下程式碼複製到剛剛建立的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
39using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public class ChangeEventTestWindow : EditorWindow
{
private Toggle m_MyToggle;
// 這個Attributes會在 Windows -> UI Tollkit 下加入一個 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}");
}
} - 在Unity編輯器中找到 Window > UI Toolkit > Change Events Test Window
- 觀看結果
例子二:使用程式碼觸發事件的話,可以透過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
40using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public class ChangeEventTestWindow : EditorWindow
{
private Toggle m_MyToggle;
[ ]
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