К содержимому

UI Toolkit без ручных биндингов

Unity UI Toolkit мощный, но обычные экраны всё равно означают boilerplate: деревья UXML, C#-поиски Q<>, manual bindings и кучу колбэков в духе MVVM. Поисковые запросы выглядят как unity uitoolkit binding boilerplate, unity ui toolkit mvvm, uitoolkit data binding — а не «Vue-подобный фреймворк».

SUS отвечает на эту боль: один файл .sharq, реактивные Prop / Computed / Watch, без ручных биндингов для того же UI.

Without manual bindings

Бок о бок

Один и тот же счётчик: label + button. Сначала — обычный UI Toolkit (UXML + C# с ручной проводкой data binding). Затем — тот же экран как .sharq SFC.

Обычный UI Toolkit — UXML + C#

xml
<!-- Counter.uxml -->
<ui:UXML xmlns:ui="UnityEngine.UIElements">
  <ui:VisualElement class="counter">
    <ui:Label name="value-label" text="0" class="counter__value" />
    <ui:Button name="inc-button" text="+1" />
  </ui:VisualElement>
</ui:UXML>
csharp
// CounterView.cs — manual bindings / MVVM-ish glue
using UnityEngine;
using UnityEngine.UIElements;

public class CounterView : MonoBehaviour
{
    [SerializeField] UIDocument document;

    Label _valueLabel;
    Button _incButton;
    int _count;

    void OnEnable()
    {
        var root = document.rootVisualElement;
        _valueLabel = root.Q<Label>("value-label");
        _incButton = root.Q<Button>("inc-button");

        // Manual subscription — easy to forget on disable / rebuild
        _incButton.clicked += OnInc;
        Refresh();
    }

    void OnDisable()
    {
        if (_incButton != null)
            _incButton.clicked -= OnInc;
    }

    void OnInc()
    {
        _count++;
        Refresh(); // hand-pushed data binding
    }

    void Refresh()
    {
        if (_valueLabel != null)
            _valueLabel.text = _count.ToString();
    }
}

SUS — .sharq (без ручных биндингов)

xml
<!-- Counter.sharq -->
<template>
  <ui:VisualElement $MainElement class="counter">
    <ui:Label :text="Count" class="counter__value" />
    <ui:Button text="+1" @click="OnInc" />
  </ui:VisualElement>
</template>

<script>
public Prop<int> Count = new(0);
private void OnInc() => Count.Value++;
</script>

<style>
.counter { flex-direction: row; align-items: center; }
.counter__value { font-size: 24px; margin-right: 12px; }
</style>

Меняете Count.Value — label обновляется. Без Q<>, без clicked +=, без Refresh() для data binding этого экрана.

Что перестаёте писать

Боль (поисковые термины)Обычный UI ToolkitС SUS
boilerplateUXML + MonoBehaviour + lookup + subscribeОдин .sharq
manual bindingsQ<> + callbacks + text = …:text / @click на Prop
MVVM / view-models на каждый экранЧасто рукамиРеактивные источники в компоненте
data binding glueПересобирается на каждое полеВстроенные Prop / Computed / Watch

Компиляция в Editor превращает .sharq в обычный [UxmlElement] partial class + USS — UI Builder и отладчик по-прежнему видят нормальный C#.

Дальше