Search Unity

Question Event handlers on LocalizedStringEvent are lost when deactivating a game object

Discussion in 'Localization Tools' started by kork, Aug 28, 2020.

  1. kork

    kork

    Joined:
    Jul 14, 2009
    Posts:
    280
    In our UI I have some UI components that are conditionally showing and hiding. On of these is a label that shows a progress information:

    upload_2020-8-28_8-36-47.png

    This label needs to be dynamically updated at runtime to inject the current progress into it. The label is set up like this:

    upload_2020-8-28_8-38-32.png

    At runtime I update the format arguments like this:

    Code (CSharp):
    1.  
    2.      LocalizeStringEvent progress;
    3.  
    4. // ...
    5.      progress.StringReference.Arguments = new object[]
    6.                 {researchItem.spentHours, researchItem.descriptor.requiredHours};
    7.  
    8.       // force a refresh
    9.       progress.StringReference.RefreshString();
    10.  
    Now for reasons sometimes this label is not to be shown. To hide it, I simply deactivate the game object on which the label (and the
    LocalizeStringEvent
    ) resides. Now if I later activate it again, I get an exception when trying to refresh the string:

    Code (CSharp):
    1. Exception: RefreshString should be used with StringChanged however no change handler has been registered.
    2. UnityEngine.Localization.LocalizedString.RefreshString () (at Library/PackageCache/com.unity.localization@0.8.1-preview/Runtime/Localized Reference/LocalizedString.cs:130)
    So it would seem that deactivating the game object somehow removes the event from the
    LocalizedString
    instance that the
    LocalizedStringEvent 
    refers to. I dug a bit in the code and I think I have found the cause of this. In
    LocalizedStringEvent 
    there is code to clear the event handlers when the component is deactivated (starting around line 62):

    Code (CSharp):
    1.         /// <summary>
    2.         /// Stops listening for changes to <see cref="StringReference"/>.
    3.         /// </summary>
    4.         protected virtual void OnDisable() => ClearChangeHandler();
    I'm not exactly sure why it is there, but it breaks use cases where you need to dynamically show and hide UI elements or where you show and hide a complete dialog by disabling the root gameobject (which in turn disables all child game objects). A workaround would be to put the
    LocalizedStringEvent 
    on a separate game object that is not deactivated but that's rather messy. Am I using this the wrong way?
     
    Last edited: Aug 28, 2020
    hhoffren and drewjosh like this.
  2. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,281
    Hey,
    This looks like a bug.
    Could you please file a bug report so we can get it fixed :)
     
    drewjosh likes this.
  3. kork

    kork

    Joined:
    Jul 14, 2009
    Posts:
    280
    Yes I will do this. Should I use the editor's built-in bug reporting tool or do you have some other location for reporting bugs about the localization tools?
     
  4. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,281
    The normal bug reporter is fine. Thanks
     
  5. Cristyx

    Cristyx

    Joined:
    Feb 10, 2019
    Posts:
    2
    I am having exactly the same problem as Kork described. Hope you can fix this soon, I have no interest in developing a custom made localization system because of a bug when this complete solution already exists.

    Edit: In case this can help. This exception only occurs to me when I am developing on my slow laptop, not in the faster pc so I guess that the problem might be related to localization string load time being higher than gameobjects's deactivation time.
     
  6. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,281
    Hmm. this should have been fixed in 0.8.0, we changed the internal event. Could you file a bug report as I suspect this is a different issue?
     
  7. Cristyx

    Cristyx

    Joined:
    Feb 10, 2019
    Posts:
    2
    Nevermind. After reading your reply I did some debugging to be certain of what I said and found out that I was calling RefreshString() on an active component of a disabled gameobject. Solved it by checking gameobject' state before doing a refresh.

    Sorry and thank you, Karl.
     
    drewjosh and karl_jones like this.
  8. drewjosh

    drewjosh

    Joined:
    Sep 24, 2019
    Posts:
    30
    I've had the same problem and I was checking also if my Gameobject was active. For me the exception disappeared when I removed the OnEnable() function where I called RefreshString. Now I only call RefreshString() in the method where I update the argument for the smart string. Am I doing everything alright?

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Localization;
    3. using UnityEngine.Localization.Components;
    4.  
    5. public class Distance : MonoBehaviour
    6. {
    7.     public int distance;
    8.     public LocalizeStringEvent localizeString;
    9.  
    10.     public void SetDistance(int newDistance)
    11.     {
    12.         distance = newDistance;
    13.         localizeString.StringReference.RefreshString();
    14.     }
    15. }
     
  9. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    8,281
    Yes that's right. You only need to call it when something has changed after the string has been generated. We made some improvements in the next version to stop the errors calling Refresh.
    For now you should be able to check if the localized string componentis enabled and only call RefreshString when it is.
     
    drewjosh likes this.