Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

(Solved)How to force update visual element on the "current frame" ?

Discussion in 'UI Toolkit' started by unity_IpxdANggCs1roQ, Aug 13, 2019.

  1. unity_IpxdANggCs1roQ

    unity_IpxdANggCs1roQ

    Joined:
    Feb 19, 2018
    Posts:
    44
    MarkDirtyRepaint() toggles flag so it causes update on the next frame.

    But I want to force update my visual element on the current frame.

    Any solutions?
    thank you.
     
    Last edited: Mar 1, 2021
  2. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    771
    Hello,

    This is not really possible with the way the system is designed. Can you tell us a bit on what are you trying to accomplish? Maybe there is a different approach.
     
  3. Dunskat

    Dunskat

    Joined:
    Oct 17, 2017
    Posts:
    11
    Hey, I'd like to revive this if someone is checking it -
    My situation is:
    rootVisualElement.Clear();
    rootVisualElement.Add(new SpecificInheritedFromVisualElements());
    rootVisualElement.Query<SpecificInheritedFromVisualElements>().ForEach((element) =>
    {
    Do something - specifically related to the element size and position in window in this case.
    }

    What the result is it still finds all the old elements that were supposedly cleared, and doesn't find the new one that was created. More than this, on position for those cleared elements it returns NaN (which makes sense)
    Is there a way to:
    1. Force wait for next frame without creating co-routines (because doing so will force me to change my entire script to accommodate for frame waits. especially given that editor coroutines are still experimental)
    2. Force refresh of all the visual elements under a specific window so I can get the right info.
     
  4. Dunskat

    Dunskat

    Joined:
    Oct 17, 2017
    Posts:
    11
    My problem wasn't to force refresh, it was to force refresh immediate, which is not possible.
    If anyone else stumbles upon this problem, my solution was using OnEditorUpdate event just while I needed to wait. That way there's no Update loop when I don't need it, and I can flag when I need the event to happen.
    Technically I don't even need the flag, because this event will only happen when I need it to.

    Code (CSharp):
    1. private void DoSomething()
    2.         {
    3.             DoModificationsToVisualElements();
    4.  
    5.             EditorApplication.update += OnEditorUpdate;
    6.         }
    7.  
    8.         private void OnEditorUpdate()
    9.         {
    10.                 if (scrollFramesCounter < 1)
    11.                 {
    12.                     scrollFramesCounter += 1;
    13.                    
    14.                 }
    15.                 else
    16.                 {
    17.                     DelayedProcessThatRequiresPostRefresh();
    18.                     EditorApplication.update -= OnEditorUpdate;
    19.                     scrollFramesCounter = 0;
    20.                 }
    21.         }
    My tests show that a single editor update frame was enough for the VisualElement layout to not return NaN on position.
     
  5. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    Two more options to have something execute after the UI has had a chance to update:
    1. using delayCall:
    Code (CSharp):
    1. EditorApplication.delayCall += () =>
    2. {
    3.     // some work
    4. };
    2. using UIElements scheduler:
    Code (CSharp):
    1. myElement.scheduler.Execute(() => { // some work });
    Both of these options will only execute once, on a future frame (but not too many frames in the future) so you don't have to worry about disabling repeat executions.
     
    SparkesRS, orenwang, SudoCat and 13 others like this.
  6. Nexer8

    Nexer8

    Joined:
    Dec 10, 2017
    Posts:
    271
    Can we be sure that the layout of the element has been calculated when using the scheduler? In my case it seems to only work sometimes. Most of the time I get NaN values. And if not, then what is the point of using VisualElement.schedule.Execute? Does it have some other use case?
     
  7. marcospgp

    marcospgp

    Joined:
    Jun 11, 2018
    Posts:
    194
    Is this why when I create a
    new PropertyField(mySerializedProperty)
    it appears to be empty? What's the reason behind its child elements not being created in the constructor?

    Update:

    I can confirm that these do work! I don't feel great about using an obscure-ish fix though :D
     
    Last edited: Jan 18, 2022
    Midiphony-panda likes this.
  8. Edvard-D

    Edvard-D

    Joined:
    Jun 14, 2012
    Posts:
    125
    For anyone coming across this in the future, the options uDamian provided do not guarantee that the styles have been resolved before it's executed if you change an element's class. I needed to call ExecuteLater, and a value of 10 was sufficient in my case.

    Code (CSharp):
    1. myElement.schedule.Execute(() => {  /*some work*/ }).ExecuteLater(10);
     
    Baldrekr, florianBrn and Lance-Grooms like this.
  9. TwoBitMachines

    TwoBitMachines

    Joined:
    Oct 5, 2016
    Posts:
    43
    For future readers, I was having this issue as well, PropertyField will not appear if you add it after the visual tree was already created.

    So instead of doing this:

    PropertyField property = new PropertyField(SerializedProperty);



    Do this:

    PropertyField property = new PropertyField();
    property.BindProperty(SerializedProperty);