Search Unity

Data Bind for Unity

Discussion in 'Works In Progress - Archive' started by coeing, Dec 1, 2014.

  1. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Update 10.02.2015:

    The first version of Data Bind for Unity is available in the Asset Store! Check it out now for a very low initial price and help me with your feedback to further develop it for your needs!

    Introduction:

    A clean separation between logic/data and visualization is a must-have, not only in software projects (http://en.wikipedia.org/wiki/Separation_of_presentation_and_content). This guarantees that the business logic of the application isn't dependent on the presentation, so the visualization can be easily adapted.

    One famous architecture, at least in the Microsoft universe, is the MVVM pattern (http://en.wikipedia.org/wiki/Model_View_ViewModel) which is highly utilized in Windows Presentation Foundation (WPF, http://en.wikipedia.org/wiki/Windows_Presentation_Foundation). I don't want to get too much into detail of this framework as it a fully developed business framework with a huge amount of complex stuff.

    The part we are interested in is the data binding between the view and the view model. The view model is an additional structure which sits between the view and the logic. It gets its data from the logic of the application and provides an interface for the view to use. Via data bindings the view can use the data provided by the view model to show it to the user.

    This is what we adapted with our plugin, so you'll have a common way how your UI is separated from you game logic to get many cool advantages:
    • Don't be afraid that UI changes break your game any more, the logic is completely separated
    • Exchange your UI system without touching any logic (e.g. from NGUI to Unity UI)
    • Easily extend the plugin to use it with a custom UI, world objects or custom input commands

    Example: Easy Health Bars

    Tired of remembering to update two variables (actor.Health = 20.0f, healthLabel.Text = „20“) if the health of your character changed, so the UI is updated correctly?

    No problem, Data Bind will take care of this from now on. You just update the data in your context and the UI will update magically!

    Okay, not really magically, but without any work on your side. In principal it works like this:
    • The data variables in your context are wrapped in a so called "Data property"
    • The bindings on UI side register for value changes on this properties
    • When your code sets a new value for your data, the property informs its listeners, so they can update the UI properly.
    More information

    Check out the official documentation with tutorials, examples, API and explanations. If any questions are left, just send me a message or post in this thread!

    ---------------------------------------------------------------------------------------------------------------------------

    Original Post:

    Hi there,

    We are using NData (http://forum.unity3d.com/threads/ndata-mvvm-framework-for-ngui.127918) for a long time now, but unfortunately there seems to be no further development. During the last projects we added many custom extensions to it, fixed some issues and changed some of the core classes a bit.

    So the idea came up to build a new data binding/MVVM asset from the ground up which can be used with both NGUI, uGUI and other UI frameworks. The core is practically done. But before we start to write a lot of documentation, tools and tutorials, I'd like to hear your opinion about it and if you have the need for such an asset. Or maybe you even know about an already existing asset that has everything a developer needs to do some nice data binding :)

    Here are the main features/advantages of the Data Bind asset we would build:
    • Data binding asset for Unity
    • More advanced and more general than NData
    • Separates your view from the logic of your game
    • Exchange your UI system without touching any logic
    • Switch between NGUI and Unity UI
    • Easily extendable for other UI systems (e.g. custom ones)
    So, what do you think? Really curious about your opinions!
     
    Last edited: Feb 10, 2015
  2. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Guess you guys need a little example to see what I am talking about :) I sat down and quickly implemented the most basic architecture to give you a little example.

    1. Setup the data context

    The first step to work with the data binding module would be to introduce a new context which holds the data that should be shown/manipulated in the view:

    Code (CSharp):
    1.  
    2. public class DataBindTestContext : Context
    3. {
    4.     #region Fields
    5.  
    6.     /// <summary>
    7.     ///   Data binding property, used to get informed when a data change happened.
    8.     /// </summary>
    9.     private readonly Property<string> textProperty = new Property<string>();
    10.  
    11.     #endregion
    12.  
    13.     #region Constructors and Destructors
    14.  
    15.     public DataBindTestContext()
    16.     {
    17.         this.Text = "Data Bind for Unity";
    18.     }
    19.  
    20.     #endregion
    21.  
    22.     #region Public Properties
    23.  
    24.     public string Text
    25.     {
    26.         get { return this.textProperty.Value; }
    27.         set { this.textProperty.Value = value; }
    28.     }
    29.  
    30.     #endregion
    31. }
    32.  
    As you can see there's nothing special about this class, just a storage, using the generic properties of the Data Bind module to capsule the data.

    In a real game the data would be filled from your logic system and updated when it changes there. For example in our own logic framework (http://www.slashgames.org/framework/) we use events to tell other systems when some important data changed.

    2. Setup your UI

    From now on you only work in your scene and can setup how the data your context provides is used. First we have to connect the data context to the UI via a UIContext:

    UIContext.png

    For fun I added a little popup which finds all context classes, so it the data context is instantiated when the UIContext awakes. You could also set the data context manually e.g. from another mono behaviour.

    3. Use your data

    This is all the setup work there is to do. We can now start and use the data properties that we defined in the context. Let's add a UI label and use the LabelBinding to bind the label text to the Text property from the data context:

    LabelBinding.png

    Two steps are necessary for this:
    - First we bind to the property "Text" of the data context with the "Data Binding String" script.
    - Second we add a "Label Binding" which connects the label which should visualize the data and the string data binding.

    This automatically updates the text of the label every time the data changes.

    ---------------------------------------------------------------------------------------------------------------------------------------------

    So, what do you think? If some people are interested in such a module I would love to spend some time to further develop it with more UI and data bindings :) I'm curious about your feedback!

    If you want to try out the example, just download the Unity package (NGUI required): DataBind.unitypackage
     

    Attached Files:

    ilya_ca and rakkarage like this.
  3. npruehs

    npruehs

    Joined:
    Jul 20, 2012
    Posts:
    67
    Love it. This approach has far more advantages than might occur at the first place.

    Being able to easily change your UI at any time without having to touch your UI logic essentially means: You can use a label to indicate your current hero health for prototyping, and replace it with a nice health bar later. Without touching any code.

    Moreover, you can write fancy binding code once and reuse throughout your game (and even future games). First thing that comes to my mind is showing a timer: You can bind the actual timer value to some float property (e.g. RemainingSeconds), and write a label binding that shows the timer in any format you wish (such as 1:27 or 1m 27s).
     
    theANMATOR2b and coeing like this.
  4. sonicviz

    sonicviz

    Joined:
    May 19, 2009
    Posts:
    1,051
    I haven't had a chance to look fully at your framework as I've been working through uFrame, Zenject, and MinIOC but I took a quick look at the example above and looks ok.

    I understand MVVM (extensive use of NDATA/NGUI) and have my head around IOC/DI but my gut feel is that most of the above solutions - while they are excellent in their own right - are a hammer where a scalpel is needed.

    Of course it depends on the app and business needs + tech strategy, but productivity is not just about making the thing so flexible and uncoupled you can't see the flows anymore.

    NDATA took me a little time to get my head around, but it's lightweight compared to these.

    A simple data binding combined with messaging/events (Advanced C# Messenger++ or new Unity events) might be simpler and more modular than some of the more heavyweight solutions mentioned above.
    I'll keep playing with them some more but I really want something lighter.

    It's not that complex to decouple things if you have a binding framework to take care of the front end dependencies and used messaging/events to keep the rest flexible. Sure, it's not AS flexible as IOC/DI but from what I see you lose even more readability which is also key, especially when picking a project back up after some time.

    The biggest issue I see is creating the bindings for custom controls such as customs listview, scroll list or listbox.

    Alternatively, how about a publish/subscribe approach instead of data binding?
     
    Last edited: Dec 5, 2014
    coeing likes this.
  5. sonicviz

    sonicviz

    Joined:
    May 19, 2009
    Posts:
    1,051
  6. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Hi @sonicviz,

    We are using the publish/subscribe pattern pretty much for the event manager in our Slash framework. This allows a very clean and strict separation between the different systems inside the logic and it separates the systems from the data contexts.

    Between the data contexts and the UI there are just two ways of communication possible:

    1. The UI gets informed if a data value changed if it bound itself to the property.
    2. The data context provides methods which can be called by the UI when a user command occured (e.g. a button was clicked which should fire the weapon => OnFireWeapon). Very often the context does nothing else than queue the correct event, which is handled by the logic.

    About the complexity: I'm completely with you. I checked some of the frameworks you mentioned and in my opinion it's really a bit too much to deal with dependency injection. On the other side, once one understands the basic architecture it might not be that complex anymore. But I haven't found a use case where I desperately need DI, so I stay away from it right now ;)
     
    sonicviz likes this.
  7. sonicviz

    sonicviz

    Joined:
    May 19, 2009
    Posts:
    1,051
    Nice. I'll take a closer look at it.

    In my experience (ie: I've played a lot of *accidental jazz* in my time) simple is better on all fronts.

    The irony of using a complex system to promote productivity when a simple one will do is not lost on me!
    (much as I love patterns, but I've grown out of my pattern mania now and just want a clean simple flexible framework)
     
  8. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    A framework should always be as simple as possible in my opinion. As a developer I can only use the full potential of a framework if I fully understood how it works. So the simpler the better :)

    Furthermore I don't like frameworks which take over all parts of your project. I even restrict Unity to only work on the visualization of our games and work with pure C# in the logic. So I strive for modular plugins which have a clearly defined workspace.
     
  9. sonicviz

    sonicviz

    Joined:
    May 19, 2009
    Posts:
    1,051
    coeing likes this.
  10. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    683
  11. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
  12. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Hi @rakkarage,

    Yes, we stumbled upon this framework already, but it bundles too much functionality in one asset in my opinion. Eventually worth a look how they implemented their data binding. Do you know if it is delivered with sources or just the binaries?`

    Cheers
    Christian
     
  13. sonicviz

    sonicviz

    Joined:
    May 19, 2009
    Posts:
    1,051
    I don't think you need too many to start, maybe just:
    • uGUI
    • uGUI extended to the Material Framework (see prev link)
    • NGUI

    ?
     
  14. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Yes, those would be the basic ones, I guess. I could provide a little documentation how to support further UI frameworks, so it could be used for own frameworks as well.
     
  15. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
  16. Galahad

    Galahad

    Joined:
    Feb 13, 2012
    Posts:
    72
    Good evening coeing.

    I need to add a Setter and configure it by code without using inspector at all. How can I do that?
     
  17. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Hi @Galahad,

    Should be no problem. You can set the Data field of the Setter completely via code. E.g. to link the setter to data from a context, just set the Type to DataBindingType.Context and the Path to the path to the data in the context.

    If you tell me which specific setter you have to add, I can give you a small code snippet. But maybe my description already helps :)
     
  18. Galahad

    Galahad

    Joined:
    Feb 13, 2012
    Posts:
    72
    Thank you for the prompt reply, here te code I'm using:


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using Slash.Unity.DataBind.UI.Unity.Setters;
    4. using Slash.Unity.DataBind.Core.Presentation;
    5. using UnityEngine.UI;
    6.  
    7. public class ToggleExample : MonoBehaviour
    8. {
    9.     public ToggleIsOnSetter setter;
    10.     // Use this for initialization
    11.     void Start ()
    12.     {
    13.         setter.Data.Type = DataBindingType.Context;
    14.         setter.Data.Path = "Bool";
    15.         setter.enabled = true;
    16.     }
    17.              
    18. }
    The ToggleIsOnSetter on scene has it 'Path' set to 'CUSTOM' and the 'Custom Path' is empty.

    The following error issues:

    InvalidCastException: Value is not a convertible object: ToggleStateContext to System.Boolean
    System.Convert.ToType (System.Object value, System.Type conversionType, IFormatProvider provider, Boolean try_target_to_type) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Convert.cs:2941)
    System.Convert.ChangeType (System.Object value, System.Type conversionType) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Convert.cs:2490)
    Slash.Unity.DataBind.Core.Presentation.DataBinding.GetValue[Boolean] () (at Assets/Slash.Unity.DataBind/Scripts/Core/Presentation/DataBinding.cs:131)
    Slash.Unity.DataBind.Foundation.Setters.SingleSetter`1[System.Boolean].OnObjectValueChanged (System.Object newValue) (at Assets/Slash.Unity.DataBind/Scripts/Foundation/Setters/SingleSetter.cs:90)
    Slash.Unity.DataBind.Foundation.Setters.ComponentSingleSetter`2[UnityEngine.UI.Toggle,System.Boolean].OnObjectValueChanged (System.Object newValue) (at Assets/Slash.Unity.DataBind/Scripts/Foundation/Setters/ComponentSingleSetter.cs:46)
    Slash.Unity.DataBind.Foundation.Setters.SingleSetter.OnEnable () (at Assets/Slash.Unity.DataBind/Scripts/Foundation/Setters/SingleSetter.cs:65)
    UnityEngine.Behaviour:set_enabled(Boolean)
    ToggleExample:Start() (at Assets/Slash.Unity.DataBind/Examples/ToogleBool/ToggleExample.cs:15)

    Regards =]
     
  19. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Hi @Galahad,

    Just tried your example, thanks a lot for providing it!

    It looks like the DataBinding is initialized too early for your adjustments to have an effect. The SingleSetter base class initializes its binding in Awake already. This happens before you do your adjustments in the Start method of the ToggleExample script.

    What you can do (and what I might change after some testing in the asset) is to do the initialization of the binding in the Start method, so it is only done when the script is enabled.

    Just copy the Awake method of the SingleSetter class (Foundation/Setters/SingleSetter.cs, line 36), rename it to Start() and remove the AddBinding call from the Awake method. This worked for me. It shouldn't create any bigger problems, but if you get one let me know!

    Cheers
    Christian
     
  20. Galahad

    Galahad

    Joined:
    Feb 13, 2012
    Posts:
    72
    It worked wonders!

    I congratulate you for this great product.

    Many thanks
    Thiago
     
  21. Galahad

    Galahad

    Joined:
    Feb 13, 2012
    Posts:
    72
    I would like a two-way binding were the Toggle Button get the default state from the Context after being instantiated and then proceed to update the property whenever it's own state change(user click on it). On other hand it can't stop receiving external changes to the given property. I attached a Setter and a Getter to the Toggle and used the following code:

    Code (CSharp):
    1. using UnityEngine;
    2. using Slash.Unity.DataBind.Core.Presentation;
    3. using Slash.Unity.DataBind.UI.Unity.Setters;
    4. using Slash.Unity.DataBind.UI.Unity.Getters;
    5. using System.Collections;
    6.  
    7. public class ToggleExample : MonoBehaviour
    8. {
    9.     public ContextHolder holder;
    10.     public ToggleIsOnSetter setter;
    11.     public ToggleIsOnGetter getter;
    12.     // Use this for initialization
    13.     IEnumerator Start ()
    14.     {
    15.         setter.Data.Path = "PlayState";
    16.         getter.Path = "PlayState";
    17.         setter.enabled = true;
    18.         yield return new WaitForEndOfFrame();
    19.         getter.enabled = true;
    20.     }
    21.  
    22.     void Update()
    23.     {
    24.         Debug.Log(((ToggleStateContext)holder.Context).PlayState);
    25.         if (Input.GetKeyDown(KeyCode.E))
    26.         {
    27.             ((ToggleStateContext)holder.Context).PlayState = !((ToggleStateContext)holder.Context).PlayState;
    28.         }
    29.     }
    30.                
    31. }
    I'm using the correct approach in this setting?
     
  22. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,644
    I was looking for something similar, I have just a question: shouldn't the databinding happen between the view and the model in such a way that if I change a member of the model from the viewmodel the view will update automatically?
     
  23. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Hi @sebas77,

    You can use e.g. a TextGetter on a UI Text to change the data context property if the text in the UI Text changes. Is it something like that what you mean?

    In Data Bind the Property and Collection members of the Context classes handle the data changes. They monitor their data value and send out an event if the value changed. So if you change a data property in the context which is used in the view, the view will update automatically. And if you registered for the ValueChanged event on your logic side you can adjust your model whenever the data value changed.

    Let me know if my explanations helped :) Maybe check the examples in the package (if you already bought it) and the official release thread as well: http://forum.unity3d.com/threads/released-data-bind-for-unity.298471/

    Cheers
    Christian
     
  24. Galahad

    Galahad

    Joined:
    Feb 13, 2012
    Posts:
    72
    Good evening,

    I'm using a Collection. The items of this collection have various properties, and among them a Boolean one.
    I wanted to track the collection for any changes on the boolean state on ANY of these items.

    It is possible to achieve?

    Regards
    Thiago
     
  25. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Good morning Thiago!

    This is something which is not possible in a general way right now, but also something I thought about a few times the last weeks. What you can do is to have an additional boolean data property, register yourself for the CollectionChanged event of your collection plus the ValueChanged event of each item in the collection and update the boolean data property in the event callback.

    I hope to find the time in the next months to write something more generic for this case (or computed data values in general).

    Cheers
    Christian
     
  26. Galahad

    Galahad

    Joined:
    Feb 13, 2012
    Posts:
    72
    Thank you for you prompt response.
    Since it's a Dynamic Collection I'll try to register all collections items boolean changed event to the same callback and try to sort they by their index on the list.

    Regards
    Thiago
     
  27. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    You're welcome :) If you have a working example I really like to check it out, maybe it helps me to figure out a generic way for the asset.
     
  28. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Hi there,

    I am evaluating this asset and have read over all your documentation but the included example usage is I think too simple for me to fully grasp how this asset works.

    In your example you bind only a single piece of data. Would it be possible to do an example binding at least 3 or 4 pieces of data of different types/different UI controls?

    The reason I ask is because after reading your documentation and example I am left with the impression that using DataBind is very unwieldy and requires a custom class be written for every piece of data, and complex components setup and connected for every piece of data.

    That is the impression I am left with after reading, but that can't possibly be true. On the other hand I'm not willing to buy it first just to find out if that is true or not :) Thus the request of expanding the example.

    Thanks!
     
  29. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    271
    Hey @jwvanderbeck!
    I posted my reply in the official, not-work-in-progress thread: https://forum.unity3d.com/threads/released-data-bind-for-unity.298471/page-3#post-3115239 :)
     
  30. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825