Search Unity

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

Discussion in 'UIElements' started by unity_IpxdANggCs1roQ, Aug 13, 2019.

  1. unity_IpxdANggCs1roQ

    unity_IpxdANggCs1roQ

    Joined:
    Feb 19, 2018
    Posts:
    25
    Last edited: Sep 9, 2019
  2. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    114
    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. unity_IpxdANggCs1roQ

    unity_IpxdANggCs1roQ

    Joined:
    Feb 19, 2018
    Posts:
    25
    Thanks for your reply.

    Something was wrong with my code, but now MarkDirtyRepaint works well for my situation.
    Thx!
     
    Last edited: Aug 16, 2019
  4. Dunskat

    Dunskat

    Joined:
    Oct 17, 2017
    Posts:
    8
    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.
     
  5. unity_IpxdANggCs1roQ

    unity_IpxdANggCs1roQ

    Joined:
    Feb 19, 2018
    Posts:
    25
    Following simple code works well and it clears all children of the rootVisualElement immediately;
    Code (CSharp):
    1. rootVisualElement.Query<Button>("my-button-id").ForEach(button =>
    2.     {
    3.       button.clickable.clicked += () =>
    4.       {
    5.        rootVisualElement.Clear();
    6.       };
    7.     });
    As far as I know, you don't need to write addtional code to force refresh UI Elements in this case. Is there a possibility that some other part of your code is wrong?
     
  6. Dunskat

    Dunskat

    Joined:
    Oct 17, 2017
    Posts:
    8
    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.
     
  7. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    421
    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.
     
    Dunskat likes this.