Search Unity

Showcase UI Toolkit MVVM Data Binding with full Localization support

Discussion in 'UI Toolkit' started by bustedbunny2, Feb 8, 2023.

  1. bustedbunny2

    bustedbunny2

    Joined:
    Oct 27, 2021
    Posts:
    25
    While being very happy with UI Toolkit, I was also constantly disappointed with lack of support for features that are required already.
    And even though it is known that UITK runtime data binding and localization support are in works, I couldn't wait to start using UITK in my projects. That's why I decided to develop data binding myself.

    Considering UITK is using very similar to XAML - UXML and CSS - USS, it is also very convenient to use the best patterns used in GUI development. As of now UITK fully supports Model-View-Presentation pattern, which is ok to work with, but involves a lot of code-from-behind which makes development of UI more complex than required. So I decided to go with Model-View-ViewModel pattern, which involves View->ViewModel data binding and separates View development from code bringing number of advantages:
    1. It is possible to fully refactor View without ever touching code and vice versa - fully refactor code without breaking View.
    2. UI designers don't need to know how to program in order work.
    3. Total amount of code is significantly reduced.
    In order to achieve this I decided to use CommunityToolkit.Mvvm package, which is endorsed by Microsoft and brings a lot of improvements to workflow:
    1. Code generation of boilerplate
    2. Very performant messaging system
    So what has already been achieved? As of now package already supports these features:
    1. TextElement's text binding.
      You can bind text to a property using string.Format style.
    2. Localization binding with support of variables, nested variables and nested LocalizedStrings and all sorts of smart-string features.
      Altogether this makes UI development with Localization very simple, involving very little code-from-behind.
    3. INotifyValueChanged<T> binding.
      This is the kind of 2 way binding that allows for a wide variety of applications. For example: reading user input.
    4. IRelayCommand binding.
      This provides a way to call methods with clicks. You can even pass certain data along in parameter giving you an opportunity to reuse code for different UI elements.
    5. Reflection binding.
      This kind of binding allows you bind literally any property of VisualElement to code. For example: binding of style.fontSize or style.backgroundImage.
    6. Burst support.
      And if you are using DOTS you can use unmanaged Messenger wrapper to send any kind of data from bursted code to your UI, making game-UI integration very straight-forward.
    And many other features are in works.

    All kinds of bindings use delegates and avoid boxing as much as possible. This is achieved using pre-compiled generics allowing you to provide support for any custom type for binding.
    This is also 100% IL2CPP and WebGL compatible.

    Requirements:
    • UniTask. It is used widely to provide spike less Localization's string generation.
    • Net Standard 2.1
    • Unity 2022.2. While all previous version are also partially supported (as long as they support NS 2.1 and UniTask), 2022.2 is the first version that also supports Roslyn 4.0.1 API which gives an opportunity to use all power of CommunityToolkit.Mvvm source generators.

    Package contains a sample featuring most mentioned features and detailed readme with tutorial on almost every feature in a package.
    Package is licensed under MIT license.

    https://github.com/bustedbunny/com.bustedbunny.mvvmtoolkit

    Reminder: this is WIP and until first stable release many breaking changes might be pushed without a warning.
     
    Last edited: Feb 8, 2023
  2. ErnestSurys

    ErnestSurys

    Joined:
    Jan 18, 2018
    Posts:
    94
    Some feedback from my quick look at the project
    - The `com.unity.collections` dependency is missing from the package manifest. The package does not compile without it
    - You can add a link to the UniTask repo in README.md
    - Paths to samples are not included in the package manifest. No way to import them from the Pacman window
    - Samples are broken as the Sample scene has missing references
     
  3. bustedbunny2

    bustedbunny2

    Joined:
    Oct 27, 2021
    Posts:
    25
    Thanks, that was indeed an overlook from my end. Sample and package dependencies should be fixed now.
     
  4. StarredSwan

    StarredSwan

    Joined:
    Apr 1, 2019
    Posts:
    1
    Thanks! Seems to be working out of the box now. Some feedback based on the getting started guide:

    - Some steps are missing screenshots or require additional knowledge on how to perform certain steps (localization for instance)
    - In the SampleScene overview (4th image) there is a UIDocument GameObject that came out of nowhere.
    - The OpenTestViewMessage class should be created before it is consumed in SampleUIInitializer (or it should be noted that it gives an error, since it does not exist yet). In a later stage, you add the await root.Initialize and messenger.Send again. Maybe the first sceenshot of the SampleUIInitializer is wrong and needs to have those lines removed?

    - For the binding tutorial, maybe start with the simplest example, i.e. just have a counter update in a label? Starting with the localization based bindings threw me off at first, thinking I needed that just to get a simple binding working.

    Overall it is a very nice package that makes UI work almost as easy as just using MVVM with C#! Great job!
     
  5. bustedbunny2

    bustedbunny2

    Joined:
    Oct 27, 2021
    Posts:
    25
    UIRoot of package does not render UI by itself. You need to provide UIDocument to it. You can do so either manually via property, or assign it to serialized field, which will automatically assign it to property.

    Messages classes can be created at any point. They are simply a signature and sometimes data container used to identify receivers and process sent data.
    I personally reuse them via static fields to avoid creation of garbage.

    Localization bindings are slightly easier, that's why I started with them.

    Overall I should update readme a lot, since it's pretty outdated atm. Sample is up-to-date though.

    But rn I work on further integration of messenger into Unity (aka NativeMessenger) and potentially I'll replace Microsoft's StrongReferenceMessenger. SO it might be not soon.

    If you have questions you can ping me in Unity discord btw. Nickname is @Issue
    I hang a lot in DOTS/UI-Toolkit channels.
     
    PrimalCoder likes this.