Проблема с EditorGUI.EndChangeCheck, наблюдаемое поле еще не обновлено

Я пытаюсь расширить TextMeshProUI с помощью специальной реализации. Я расширил им редактор, чтобы можно было отслеживать некоторые изменения.

public class LocalizedTMP_UGUI : TextMeshProUGUI
{
    // Stripped code
    [SerializeField] private List<LocArgument> m_arguments;

    public void SetLocalizedText()
    {
        text = m_localizer.GetLocalization(m_localizationKey, m_arguments);
        ForceMeshUpdate();
    }
}
[Serializable]
public class LocArgument 
{
    public string name; 
    public string value;

    public LocArgument(string name, string value)
    {
        this.name = name;
        this.value = value;
    }
}

И что касается редакторской части:

[CustomEditor(typeof(LocalizedTMP_UGUI))]
[CanEditMultipleObjects]
public class LocalizedTMP_UGUI_Editor : TMP_EditorPanelUI, ITMPEditor
{
    private SerializedProperty m_arguments;
    private string [] m_languages; 
    private int m_languageIndex = 0;
    private ILocalization m_localizer;

    // removed OnEnable

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        int languageIndex = EditorGUILayout.Popup(m_languageIndex, m_languages);
        if (languageIndex != m_languageIndex) 
        {
            m_localizer.SetWithLocale(m_languages[languageIndex]);
            SetText();
            m_languageIndex = languageIndex; 
        }
        EditorGUI.BeginChangeCheck();
        EditorGUILayout.PropertyField(m_arguments);
        if (EditorGUI.EndChangeCheck())
        {
            SetText();
        }
        serializedObject.ApplyModifiedProperties();
        base.OnInspectorGUI();
    }

    public void SetText() 
    {
        LocalizedTMP_UGUI targetComp = (LocalizedTMP_UGUI)target;
        targetComp.SetLocalizedText();
        Repaint();
    }
}

Когда я переключаю настройку в EditorGUILayout.Popup, текст обновляется. Но если я изменю содержимое списка аргументов (поля значения), это не повлияет ни на отображаемый текст в сцене, ни на текстовое поле компонента. Хотя при взаимодействии с инспектором (например, сворачивании/развертывании списка) он обновляется и отображается правильно.

Я заметил, что при отладке метода SetLocalizedText текст назначается с задержкой в ​​одну букву. Итак, если я начну вводить «Привет», то при вводе H будет отображаться «», затем при следующем вводе e будет отображаться «H», затем «He» при вводе l и так далее. И хотя свойство text установлено, оно не обновит текстовое поле в инспекторе, пока не поработает с компонентом.

Вероятно, это связано с сочетанием прямого доступа с доступом к сериализованным объектам. SerializedObject — это снимок объекта с использованием отражения, установленный при вызове Update. Все, что вы меняете вручную (без использования методов сериализованного объекта) после вызова обновления, не находится в сериализованном объекте. Таким образом, установка текста непосредственно в цели не отражается на сериализованном объекте. Вы можете: изменить место вызова обновления, установить текст с помощью свойств сериализованного объекта или сделать все это путем назначения вручную.

hijinxbassist 24.04.2024 23:38

Спасибо за это, это направило меня в правильном направлении!

Everts 25.04.2024 08:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У меня было две проблемы: во-первых, судя по комментариям, я устанавливал текстовое поле, хотя оно должно быть сериализованным свойством.

private SerializedProperty m_text;

protected override void OnEnable()
{
    m_text = serializedObject.FindProperty("m_text");
}
public void SetText() 
{
    LocalizedTMP_UGUI targetComp = (LocalizedTMP_UGUI)target;
    m_text.stringValue = m_localizer.GetLocalization(targetComp.LocalizationKey, targetComp.Arguments.ToList());
    serializedObject.ApplyModifiedProperties();
}

Дополнительная проблема возникла в следующем случае: проверка возвращает true, но сериализованный объект все еще необходимо обновить.

if (EditorGUI.EndChangeCheck())
{
    serializedObject.ApplyModifiedProperties();
    SetText();
}

ApplyModifiedProperty обычно размещается в конце OnInspectorGUI, но в этом случае он необходим в проверке для обновления свойства перед его использованием.

когда вы изменяете target, вам нужно будет использовать либо EditorUtility.SetDirty , чтобы пометить этот ресурс как грязный, чтобы ваши изменения действительно были сохранены при нажатии ctrl + s ... или даже Undo.RecordObject , чтобы правильно поддержка отмены/повтора, а также, если это потенциально префаб, даже PrefabUtility.RecordPrefabInstancePropertyModifications

derHugo 25.04.2024 08:43

=> вы почти всегда предпочитаете использовать SerialzedProperty и SerializedObject вместо того, чтобы иметь дело с этими низкоуровневыми инструментами ;)

derHugo 25.04.2024 08:43

Другие вопросы по теме