Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

[RELEASED] Data Bind for Unity

Discussion in 'Assets and Asset Store' started by coeing, Feb 16, 2015.

  1. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Good job, @Jochanan, I just wanted to reply, but you already found a very clean way :)

    My (quick) solution would have been to add a reference to the Command script to the script that checks the key press and call the InvokeCommand() method there. But your solution is much more reusable *thumbsup*
     
  2. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    The new version 1.13 of Data Bind was just submitted and is now in review :)

    If there are any issues you are still missing, there is a public issue tracker where everybody can add their wishes, bug reports, ideas, feedback,...:

    https://bitbucket.org/coeing/data-bind/issues

    The main additions:
    - First version of filters/aggregators for data collections (let me know what you think about it!)
    - Several scripts to use with TextMesh Pro
    - Several new scripts (providers, syncrhonizers, setters)
    - More intelligent inspector for data binding fields (type checks to only be able to assign correct behaviour)
    - Fix for wrong initialization of Data Binding when assigning value to context from script right after setting the context

    Here is the full changelog:
    * Show foldout for member value which is of an unknown type (Otherwise there is no name of the member in the inspector and its children are rendered immediately)

    * Update value of CollectionAnyFilter when an item was added/removed

    * Add currency string formatter to create a formatted currency amount from a number and a culture name

    * Inform about value change of TextureAspectRatioProvider when texture changed

    * Add InputFieldTextSynchronizer and SliderValueSynchronizer to component menu

    * Call LateUpdate of data context node connector of ComponentSingleGetter, ContextDataUpdater, UnityEventTrigger and ComponentDataSynchronizer

    * Draw foldout for custom types in data contexts + Show foldout for member value which is of an unknown type (Otherwise there is no name of the member in the inspector and its children are rendered immediately)

    * Add synchronizer, observer and setter for TextMeshPro input field

    * Add CollectionAggregation with sum functions for collections

    * Register initial items in CollectionObserver.Init

    * Issue #72 Add a GameObjectActiveSwitch which activates one game object when a boolean provider is true, otherwise activates a second game object and vice versa

    * Issue #69 Check values of constant objects each update when in editor, so the user can play around with the value in the inspector

    * Issue #68 Move NGUI examples to Addons/NGUI folder and include atlas for examples

    * Handle replacing an item in a collection by ItemsSetter and clear collection in ItemsSetter when it gets disabled (Otherwise items are created even if items setter is disabled)

    * Add AspectRatioFitterAspectRatioSetter, RawImageTextureSetter and TextureAspectRatioProvider

    * Updating Count of collection only after saving event handler of Item event (ItemAdded, ItemRemoved,...) (Otherwise the updating of the Count property may cause a listener to register for the item events an thus will be informed about the item event although the initial collection already contained it)

    * Only show selection popup for provider when more than one component will work

    * Issue #17 Use type hint for GameObjectSingleSetter and only show game object component selection if type hint not available (otherwise the reference is already of the right type)

    * Issue #17 Add data type hint which is used to only allow references that match the required type

    * Issue #70 Call Enable method of DataBindingOperator in OnEnable, even if Start() method wasn't called yet. The Start() method may only be called one frame later if the game object was created in the Start method of another game object (e.g. the GameObjectItemsSetter)

    * Call ValueChanged event once for a ConstantObjectProvider, otherwise not all listeners may be updated correctly

    * Call initial ValueChanged event of DataContextNodeConnector in LateUpdate of the holding mono behaviour (yield return new WaitForEndOfFrame and yield return null will both wait until the next frame, not only until the end of the current frame. This causes a 1 frame delay between the context setting and the value updates)

    * Update ActiveSetter example to test delayed ValueChanged event in DataContextNodeConnector

    * Allow observing read-only properties as their value may change internally

    * Cancel initial value change callback if a value change occurs in the mean time

    * Clear context of DataContextMediator before it is removed, so the context is correctly unregistered

    * Add providers for the (vertical) normalized position of a scroll rect

    * Make DataBinding implement IDataProvider

    * Add ItemReplaced event to data collection

    * Add converter from Vector2 to Vector3

    * Add provider for RectTransform width

    * StrangeIoC - Overwrite bubbleToContext, so it is possible to have the ContextView on the same game object than the view itself (This is useful when views are stored in separate scenes to be isolated)

    * Add CollectionAnyFilter

    * Add script to use collection changes as Unity events

    * Listen to ItemInserted of observed collection in CollectionObserver

    * Implement IDataProvider<T> for Property<T> and make class non-sealed

    * Return items with concrete type when iterating over Collection<T> instead of returning object type

    * Add setter for the alpha value of a CanvasGroup

    * Add converters for values -> color and base color + alpha -> color

    * Add index to insert item game objects at in GameObjectItemsSetter

    The new version will be available in a few days in the Unity Asset Store:

    https://www.assetstore.unity3d.com/#!/content/28301
     
  3. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Unity was pretty quick with the review this time, so version 1.13 is already available in the asset store! :)

    https://www.assetstore.unity3d.com/#!/content/28301

    In case you are thinking about a purchase: Right now there is a 20% discount for Unity Plus and Pro members!

    Have a nice weekend!
     
  4. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    hi @coeing,
    i have been waiting for the newest version to go live, because i have found a bug in the previous versions and i wanted to be sure, whether it persists or not.
    Problem is, that OnValueChange listeners are not unregistered almost never, even thought they should have been in case of gameobject is disabled for example. This is causing issues in our project (like change handler is called twenty times instead of once). May i ask you to check it out? I have already reported the issue to your bitbucket with a slightly modified Property.cs file
     
  5. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @Jochanan
    Great, thanks a lot for the detailed report. I will have a look at it immediately.
     
  6. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    Hi @coeing,
    i have yet another issue. I have this kind of layout in my custom switch (true/false)
    Výstřižek.PNG
    Code is pretty standard
    Code (CSharp):
    1. public class SwitchIsOnProvider : ComponentDataProvider<Switch, bool>
    2. {
    3.     /// <inheritdoc />
    4.     protected override void AddListener(Switch target)
    5.     {
    6.         target.onValueChanged.AddListener(this.OnToggleValueChanged);
    7.     }
    8.  
    9.     /// <inheritdoc />
    10.     protected override bool GetValue(Switch target)
    11.     {
    12.         return target.isOn;
    13.     }
    14.  
    15.     /// <inheritdoc />
    16.     protected override void RemoveListener(Switch target)
    17.     {
    18.         target.onValueChanged.RemoveListener(this.OnToggleValueChanged);
    19.     }
    20.  
    21.     private void OnToggleValueChanged(bool newValue)
    22.     {
    23.         this.OnTargetValueChanged();
    24.     }
    25. }
    Code (CSharp):
    1. public class SwitchIsOnSetter : ComponentSingleSetter<Switch, bool>
    2. {
    3.     /// <inheritdoc />
    4.     protected override void UpdateTargetValue(Switch target, bool value)
    5.     {
    6.         target.isOn = value;
    7.     }
    8. }
    In the previous version we used (1.0.9 if i remember it correctly), on context settings @ component enabling, the triggers were in this order
    1) SwitchIsOnSetter
    2) SwitchIsOnProvider
    3) ContextDataUpdater

    in the current version 1.0.13 with patch, triggers are in this order
    1) SwitchIsOnProvider
    2) ContextDataUpdater
    3) SwitchIsOnSetter

    which completely invalidates a content of context and sets up default values, that are set in the Switch gameobject.
    How can i change that?
     
  7. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @Jochanan,

    Thanks again for the report. I will try to reproduce it today with the standard ToggleIsOnSetter/Provider.

    Short question: Where do you set the context to the context holder exactly (Start, Awake, OnEnable,...)?

    In the meantime you can try to derive from the new Synchronizer script to check if it works with that one. It is exactly made for that use case (having a two way binding). Hopefully the initialization order there is as you would expect it.
     
  8. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    Hi @coeing,
    it is a little bit complicated because we are using custom holder. The context is set BEFORE the gameobject with the holder is enabled basically.

    I try to derive from ComponentDataSynchronizer class and let you know.
    That class was not there a few versions ago :)
     
  9. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Yes, it is new since 1.11.

    I created an issue in the bug tracker and was already able to reproduce and fix it: https://bitbucket.org/coeing/data-bind/issues/77/contextdataupdater-overwrites-value-in
     
  10. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    Both approaches have been working for me. Thanks
     
  11. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Glad to hear and sorry for the inconveniences :)
     
  12. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    Hello again @coeing,
    there might be another potetial issue.

    I have found out, that value property on CollectionWhereBehaviour is accessed before both Collection and ComparisonValue are set.
    This leads, that NULL is returned as a value.
    Is it possible to do some tweeks to change this behaviour?

    Null value has different meaning in my use case. It changes a texture for a brief moment to default one (when null) to set the right one after only a few miliseconds, which looks not as nice as i wold like to have.

    I tried to change the order of AddBinding inside Init function, but it cased, that the second DataBinding were set to null when value vas accessed for the first time.
    thanks!
     
  13. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    Real issue is, that i use combination of
    CollectionRangeLookup and GameObjectItemsSetter.

    GameObjectItemsSetter has a provider CollectionRangeLookup which takes forst X from Collection.

    Code (CSharp):
    1. public class GameObjectItemsSetter : ItemsSetter
    2. {
    3. protected override void ClearItems()
    4. protected override void CreateItem(object itemContext, int itemIndex)
    5. }
    Problem is, that every time something change in the Collection, the CollectionRangeLookup creates a new Collection. New collection triggers ClearItems on CollectionRageLookup() and then multiple CreateItem calls
    within them the created gameobjects are instantiated and reset for a brief moment.
    That looks really bad.

    Is there something you/i can do?
    I am using CollectionRangeLookup, because i want to have first X items of collection instantiated using GameObjectItemsSetter and others are handled differently
     
  14. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Thanks for reporting and having a deeper look into that issue.

    It's probably necessary to make the CollectionRangeLookup a bit more sophisticated, so it just adjusts the resulting collection (or leaves it untouched if nothing would change) instead of creating a new one every time. If I remember correctly I created the CollectionRangeLookup for a quite simple use case in a project where the current behaviour was good enough.

    Could you create an issue in the issue tracker? Than I will see if I can have a look into it within the next days.
     
    Jochanan likes this.
  15. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    Hi,
    I was wondering why you are calling binding updates in LateUpdate() in DataBindingOperator.cs?
    Is this absolutely necessary to check every frame?

    Also why did you implement properties like private and public modifiers instead of just public readonly? This would reduce the amount of code and increase readability a lot.

    Thanks
     
  16. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @mmvlad ,

    Thanks for your questions and feedback.

    About the LateUpdate: This had to be added because of an initialization issue. The order of the Unity callbacks (Awake, Start, OnEnable) is kind of random with different game objects and mono behaviours. That's why the final setting of the initial value is done in the first LateUpdate after the activation of a binding. That way it's guaranteed that all bindings fetched their correct initial value.
    There might be room for some optimization though, because it's really only necessary for the initialization. So collecting all initialization actions and calling them only once in the next LateUpdate (e.g. of an InitializationManager) might get rid of the LateUpdate methods of the DataBindingOperators. In my projects I didn't see a big performance hit though, did you?

    About your second question: I'm not sure if I understand what part you mean, could you give an example?

    Cheers
    Christian
     
  17. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    @coeing I mean is is possible to use code like below?
    public readonly Property<bool> IsSomethingDoneProperty = new Property<bool>();

    I'd prefer to use ".Value" manually instead of adding properties that do that for each property.
     
  18. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    I see, thanks for the example. The reason behind the properties is to hide that a property has a data property as a backing field from the world outside the context class.
    You might use the data property directly, the ValueChanged event will still be triggered. I never tested it this way, so there might be some places on the presentation side that depend on the public property with the data property as a backing field. In the inspector you might have to enter the context path manually (in your case: IsSomethingDone).

    If you find something that doesn't work with this setup, feel free to add a bug to the issue tracker and I hope to find the time to have a look at it: https://bitbucket.org/coeing/data-bind/issues
     
  19. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    @coeing awesome, I will try, thanks for the quick response.
     
  20. plamenmarinov

    plamenmarinov

    Joined:
    Jun 13, 2018
    Posts:
    2
    Hi @coeing,
    i am trying to use Data Bind on a TextMeshPro object so i used the setter from the addon. The context link and data binding is working great. I can see proper values are passed to the setter. gameobject.png
    Then on target.SetText(...) comes the threading exception and the setter sets the text in the Unity editor window but rendered text is the old one.
    setterscript.png

    I also tried to create my own setter for the normal TextMesh object using my setter but ended with same and ended with same result. These kind of problems don't happen on UI text objects but i believe they are passed in different thread than the main.
    Any help will be appreciated.
    Plamen.
     
  21. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @plamenmarinov

    Thanks for posting the issue into the forum, this may help other devs in the future when they have a similar issue :)

    It would be interesting to know where you are setting the text in the context that is displayed by the TextMeshPro element. This code probably runs in a different thread than the Unity main thread, e.g. because it's a web socket or other network connection.

    In a recent project we solved the threading issue by having a message queue being filled by the web socket and this message queue was used by a Coroutine in the Unity main thread to handle the incoming messages. You will have to lock the queue to avoid that both threads access the message queue at the same time, but other than that it's easy to setup.
     
  22. plamenmarinov

    plamenmarinov

    Joined:
    Jun 13, 2018
    Posts:
    2
    Hi @coeing,
    You are right i set the value from network communication function running on the background thread. Thanks for the direction.
     
  23. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    @coeing I've been using your framework for a few weeks now and its awesome. Exactly what I was looking for. Though the single issue I have now is LateUpdate I wrote before.
    I have a pretty small scene and every frame I get 500+ calls to lateUpdate as I am using 100+ elems in scroll list with few bindings each.
    I would really appreciate it if you make a small fix to reduce the amount of LateUpdate calls.
     
  24. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @mmvlad,

    Sorry about the late answer, Unity didn't inform me (again) about a new post in this thread :/

    I will see what I can do about it. Right now I try to publish the next version, so it won't get into that. But I'll give it a high prio for the next one and added an issue for it to the issue tracker: https://bitbucket.org/coeing/data-bind/issues/79/only-call-lateupdate-when-its-necessary
     
  25. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    The new version 1.14 of Data Bind was submitted a few days ago and is already live!

    If there are any issues you are still missing, there is a public issue tracker where everybody can add their wishes, bug reports, ideas, feedback,...:

    https://bitbucket.org/coeing/data-bind/issues

    The main additions:
    - Tackled some older issues from the issue tracker
    - Added a GroupActiveSetter (base class) and a EnumGroupActiveSetter to activate/deactivate a group of game objects
    - Add example for collection aggregations (Aggregations)

    Here is the full changelog:
    * Convert special characters in format string of StringFormatter to allow line breaks

    * Exclude JetBrains, System and Newtonsoft namespaces for context types

    * Issue #40 Add a GroupActiveSetter (base class) and a EnumGroupActiveSetter to activate/deactivate a group of game objects

    * Issue #71 Add possibility to add data type hint to provider and use it to filter components when dragging game object on to data binding provider

    * Issue #27 Add overload for AddBinding to DataBindingOperator to register a callback when the data binding value changed

    * Issue #75 Adjust build scripts, so addon packages are still build correctly

    * Issue #75 Move addons into separate folder

    * Issue #74 Add setting to make data property backing fields case insensitive

    * Issue #78 Don't create new collection in CollectionRangeLookup and time the data collection changes, but do incremental changes instead

    * Delay setting of context value in ContextDataUpdater to end of frame if node connector is not initialized yet (i.e. no context set and/or init action not executed)

    * Cleanup ContextDataUpdaterTest

    * Make LateUpdate method of DataBindingOperator public to execute it from unit tests

    * Clean up obsolete game objects in Synchronizers and TwoWayBindingExample

    * Add example for collection aggregations

    * Use CollectionAggregation base class to implement the Any filter

    * Issue #76 Remove event handler from underlying data provider and INotifyPropertyChanged parent when last event handler was removed from INodeValueObserver

    The new version is available in the Unity Asset Store:

    https://www.assetstore.unity3d.com/#!/content/28301
     
  26. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
  27. nicloay

    nicloay

    Joined:
    Jul 11, 2012
    Posts:
    475
    It looks like LateUpdate is an issue for me.
    I have a collection and GameObjectItemsSetter which instantieate gameobject with internal contextHolder.
    The problem is that
    Frame1
    - Read collection instantiate object instances (with default values in text fields, images, etc)
    Frame2
    - TextSetters, ImageSetters change value to actual value from contexts

    I just updated the DataBind from 1.0.12 to 1.14 and got this wired behaviour. (in 1.0.12 everything was working good).


    upd1: Yes. I'm right. To reproduce the bug at prefab Slash.Unity.DataBind/Examples/Collection/Item Unity at the text component set the value "xxxxx" as on screenshot below
    upload_2018-8-7_21-11-5.png
    Then on scene CollectionExampleUnity Click "Pause" and "Play" so your scene start and pause immediate at the first frame will show "xxxxx"
    upload_2018-8-7_21-12-5.png
    and next frame will update values
     
    Last edited: Aug 7, 2018
    coeing likes this.
  28. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hey @nicloay,

    Thanks for the detailed report. I had a look and could reproduce the issue (created an official issue to the tracker: https://bitbucket.org/coeing/data-bind/issues/81/items-of-a-gameobjectitemssetter-are).

    A previous issue (https://bitbucket.org/coeing/data-bind/issues/79/only-call-lateupdate-when-its-necessary) requires me to refactor the initialization logic anyway, so I will take your issue into account.

    It will definitively go into version 1.15, I just have to find some time to think about new logic there and make sure that it doesn't break other things when I change it.

    Cheers
    Christian
     
  29. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hey @nicloay,

    Good news: I already found the time to refactor it :) It would be nice to have someone test it, so I can be sure that it didn't break anything. If you send me a mail (christian.oeing@slashgames.org) I could send you a Unity package with the changes.

    Cheers
    Christian
     
  30. nicloay

    nicloay

    Joined:
    Jul 11, 2012
    Posts:
    475
    Thanks @coeing for quick response.

    I sent you email and can test changes on my project tomorrow.

    Thanks.
    //Nikolay.
     
  31. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    Hi @coeing
    was wondering if there are some tutorial/sample on how to bind to collection elements?
    How can I bind to Nth value of collection and set its value?

    Thank you
     
  32. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    Hi @coeing,
    I was looking for SelectableInteractibleGetter, but i have not found one. I was trying to make one myself, but i have not been successfull - i have not found any function to add as listener.
    Do you have any idea, whether this is possible?
    Cheers,
     
  33. sameer-mirza

    sameer-mirza

    Joined:
    Nov 14, 2011
    Posts:
    36
    Hi,

    I'm trying to bind an InputField with a Slider in such a way that they are both hooked to a float value. Things generally work with InputFieldValueSynchronizer and SliderValueSynchronizer. However, I'd like the input from the InputField to be validated based on the Min/Max of the Slider. How can I achieve this without having to use specific references to the controls?

    Best,
    Sameer.
     
  34. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @mmvlad,
    Sorry for the late response, I just got informed yesterday about new posts in this thread :/

    You can bind to a specific index of a collection by using the path:
    Code (CSharp):
    1. Collection.N
    So if you want to bind to the third item of your collection "MyItems":
    Code (CSharp):
    1. MyItems.3
    I will add a usage to the Collection example for the next version.
     
  35. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @Jochanan,
    Sorry also to you for the late response.

    I added an issue (https://bitbucket.org/coeing/data-bind/issues/84/add-a-selectableinteractiblegetter-or) and hope to find some time soon to check it out and give you an answer.

    UPDATE:

    Already got to it. The interactable flag of a Unity.UI.Selectable has no event when it changes (because it can't be changed by the user in the UI). Therefore it is not possible to have a similar provider like for Toggle.isOn.

    Attached you can find the new SelectableInteractableProvider which gives you the value of the flag, but which doesn't fire a value changed event when the flag is changed via code.

    To get that behaviour you would need to use the ComponentPullDataProvider which checks if the value changed each frame. But be warned, it's not very performant to do this. If you have to, check out the TransformLocalPositionProvider. I would name the provider SelectableInteractablePullProvider.

    I don't know where you change the interactable flag in your application. If it is via the SelectableInteractableSetter I would use the same data source where you plan to use the SelectableInteractableProvider.
     
    Last edited: Sep 20, 2018
  36. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi Sameer,

    Thanks for the example you send me, this helped me understand what you try to achieve.

    Your use case is more an issue about input field validation than it has to do with data binding. Here are the first things you can do:

    Set the Content Type of the InputField to Decimal Number:
    This makes sure the user can only input numbers and the decimal point, no characters

    Clamp the input field value before writing it into the data context:
    You could write a new Formatter (e.g. ClampNumberFormatter) which takes 3 data bindings: an input value, a min and a max value. The output value is the input value when it is between min and max, min if smaller than min and max if greater than max.
    Now you can't use the InputFieldTextSynchronizer anymore because it directly syncs the input field text with the data context value. Instead use this chain to get the input field text to the data context value:
    - InputFieldTextProvider -> ClampNumberFormatter -> DataContextUpdater
    And add a script to update the input field text from the data context value:
    - InputFieldTextSetter

    Hope those ideas help you to achieve what you plan :)
     
    sameer-mirza likes this.
  37. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    I would actually would like to "Press a button" on "Enter". I did that using "KeyPressedEvent"
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;
    3.  
    4. public class KeyPressedEvent : MonoBehaviour {
    5.  
    6.     public KeyCode KeyCodeValue;
    7.  
    8.     /// <summary>
    9.     ///   Called when notification faded out.
    10.     /// </summary>
    11.     [Tooltip("Called when key with KeyCodeValue was pressed")]
    12.     public UnityEvent KeyPressed;
    13.  
    14.     public void OnKeyPressed()
    15.     {
    16.         this.KeyPressed.Invoke();
    17.     }
    18.  
    19.     private void Update()
    20.     {
    21.         bool keyPressed = Input.GetKeyDown(this.KeyCodeValue);
    22.         if (keyPressed)
    23.         {
    24.             OnKeyPressed();
    25.         }
    26.     }
    27. }
    28.  
    But i need to invoke that command ONLY if the button is interactible (clickeable)
     
  38. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi @Jochanan
    It sounds to me that you should make the game object the KeyPressedEvent is on also inactive when the button becomes non-interactable. This way the key pressed event is only handled while the button is interactable.
     
  39. Jochanan

    Jochanan

    Joined:
    Nov 9, 2016
    Posts:
    85
    That was my plan. I am using such "layout" quite often :)
     
  40. sameer-mirza

    sameer-mirza

    Joined:
    Nov 14, 2011
    Posts:
    36
    Hi again!

    I have a Slider with a synchronizer on it. Now I want to execute a method when the data gets updated. If I set up a command (or call the method directly in the OnValueChanged Unity event for the slider) I get an outdated value by a frame (The method gets called before the synchronizer it seems). Is there a way of triggering a callback when the value gets updated instead of hooking it up with the Unity OnValueChanged event?
     
  41. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi Sameer,

    Yes, you should register to the value change of the data context property if you use that value. Where do you use that value? In you logic or in a mono behaviour? If you use it in a mono behaviour you can make it a DataBindingOperator and add a DataBinding to it. This data binding connects to the value in the data context and you can register for its ValueChanged event.

    If you need it in your logic you can add an event to your data context (e.g. SliderValueChanged). In the constructor of your data context you can register for the ValueChanged event of your data property backing field (e.g. sliderValueProperty) and invoke the event of your data context (e.g. SliderValueChanged).

    Code (CSharp):
    1.     private readonly Property<float> sizeProperty = new Property<float>();
    2.  
    3.     public float Size
    4.     {
    5.         get { return sizeProperty.Value; }
    6.         set { sizeProperty.Value = value; }
    7.     }
    8.  
    9.     public SliderInputFieldContext()
    10.     {
    11.         sizeProperty.ValueChanged += OnSizeChanged;
    12.     }
    13.  
    14.     public event Action<float> SizeChanged;
    15.  
    16.     private void OnSizeChanged()
    17.     {
    18.         var handler = SizeChanged;
    19.         if (handler != null) handler(Size);
    20.     }
    21.  
    Hope those explanations help :)
     
    Last edited: Oct 4, 2018
    sameer-mirza likes this.
  42. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    @coeing Thanks!
    One more question - how would you suggest handling UI animations with MVVM?
    e.g. sequences, one window should first close after that new opens etc.
     
  43. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    This is a thing I also had in some projects. In general I have one data context per window/dialog/button. Those UI elements have an animator which handles the closed/opening/opened/closing states. The data context has a data property IsVisible or IsOpen (sometimes you need both, when IsVisible really hides the UI element completely).

    Now when the data property changes, it sets a boolean parameter in the animator (via AnimatorBooleanSetter). This boolean parameter is responsible for doing the state transitions.

    Now about several windows: The short and dirty way would be to delay setting the data property of a window by X seconds. This should work if you have only a few windows and there is always one visible.

    The clean way would be a window manager which triggers the opening of a window and stores which window is open. If there is another window open when one should open, it triggers the closing and waits for it to be closed (either a fixed time or when the window data context reports that it was closed).

    The window data context can report that it was closed by an animation trigger which then invokes a method on a custom script that then invokes the event on the data context. Those are some indirections, but only the animation itself knows when it is finished. You just have to make sure that the animation always fires the event, otherwise the window manager might wait forever (a timeout in the window manager might be a good idea as a fallback).

    There are probably more ways of doing this, but this is the way I would go :)
     
  44. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    @coeing thanks for the quick response

    there is only one reliable way to be sure animation event is fired - ditch Unity animator in favor of DoTween or similar :)
     
  45. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    True! In that case you can call the Closed event in the data context directly from your DOTween script :)
     
  46. sameer-mirza

    sameer-mirza

    Joined:
    Nov 14, 2011
    Posts:
    36
    Thanks for this! I have another question for you :)

    Problem: We have a system where we have some functions run when certain data values are updated. This also includes a heavy funciton at the end if the value is updated via UI. The values are in a layer system so changing layer contexts also triggers these functions. We want the UI to get updated when changing contexts but don't necessarily want to trigger the expensive function each time a layer context is switched.

    Is there a way to make the "OnValueChanged" handlers for the UI controls NOT be triggered when switching contexts?

    I hope I make sense with my question.

    Cheers,
    Sameer.
     
  47. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Hi Sameer,

    What exactly do you mean with "layer system"? There is not really a way to avoid the event triggering when the value changes. I would try to add this logic at another place. For example you could set a flag "SkipValueCalculation" before setting the context and clear the flag after you set it. But without knowing the structure of your logic it's hard to decide what's the best way to do it.
     
    sameer-mirza likes this.
  48. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    Hi @coeing ,
    in my previous project in Unity 2017 everything was working fine, but in my new project in Unity 2018.2.12.f1 in ContextDataUpdater when I select Reference it shows No Type and I am unable to link an object.
    Also in 2017 I am using 1.0.13 and in 2018 1.14. I checked the source code for drawers and it differs so I assume this is a reason. But can't be sure, didn't have time to investigate deeply.

     
  49. coeing

    coeing

    Joined:
    Mar 17, 2011
    Posts:
    236
    Thanks a lot for the report. I will have a look at it and provide a fix if necessary. I planned to release version 1.15 soon, so the fix will make it into that version :)
     
  50. mmvlad

    mmvlad

    Joined:
    Dec 31, 2014
    Posts:
    89
    @coeing thanks. Will 1.15 also contain fix for empty fixedUpdates?
     
unityunity