MrHayato
Topic Author
Posts: 36
Joined: 19 Sep 2014, 21:29

[Unity] Loaded event issues

09 Jul 2015, 20:35

Hi,

I've been pulling my hair out trying to get this to work, but I can't seem to...

The idea:
- A scrollviewer contains a stackpanel
- The stackpanel contains a bunch of items in it.
- I want to know where each item is, relative to the scrollviewer.
- A control contains buttons, with one button per item in the scrollviewer.
- Clicking the buttons will scroll the scrollviewer to the position of the item

So I created an attached property to be attached to any scrollviewer (including a custom one we've built)

I've created a gist with all the attempts I've tried to get this working: https://gist.github.com/MrHayato/64402a3d1ca1139fcd6e

The attached property can be seen in this gist as TrackerA and looks pretty straightforward. However, the debug line only writes out (0,0) as the position for each of the children (even though they're all visible, no bindings).

I then added child.UpdateLayout() to each of the children, thinking perhaps it needs to be measured and arranged. You can see this at TrackerB.cs (line 29). This was a little better, as I was getting non-zero values. However, it seems the event fires twice, and then throws an exception:
Exception: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: System.ApplicationException: Element is already loaded
  at Noesis.UIElement.UpdateLayout () [0x00015] in D:\Dev\iQmetrix\XQ.Shelf\Un
Noesis.Error.Check () (at Assets/Plugins/NoesisGUI/Scripts/Core/NoesisError.cs:21)
Noesis.UIRenderer.Noesis_UpdateRenderer (Int32 rendererId, Double timeInSeconds) (at Assets/Plugins/NoesisGUI/Scripts/Core/NoesisUIRendererImports.cs:145)
Noesis.UIRenderer.Update (Double timeInSeconds, AntialiasingMode aaMode, TessellationMode tessMode, TessellationQuality tessQuality, RendererFlags flags, Boolean enableMouse, Boolean enableTouch, Boolean enablePostProcess, Boolean flipVertically) (at Assets/Plugins/NoesisGUI/Scripts/Core/NoesisUIRenderer.cs:129)
NoesisGUIPanel.LateUpdate () (at Assets/Plugins/NoesisGUI/Scripts/NoesisGUIPanel.cs:203)
So maybe loaded is getting fired too often? Not sure why, since it should only fire once. So, I'll make sure it is only fired once (TrackerC line 15). However, we are back to the first result, where everything reports 0,0.

What gives? Why is Loaded firing more than once if I call UpdateLayout on its children? And why aren't the correct sizes being reported back without it? I thought the loaded event would fire after it's loaded.
 
User avatar
sfernandez
Site Admin
Posts: 1912
Joined: 22 Dec 2011, 19:20

Re: [Unity] Loaded event issues

09 Jul 2015, 21:46

Hi,

The problem is in our side, because Loaded event is raised when element is added to the UI tree, and not after first layout is done as it occurs in WPF. We have a ticket open to fix this: https://trello.com/c/Plh08ybM

Right now, the best approach (to behave similar to WPF) is to hook to the SizeChanged event and check when was the first time the event was fired. In your code will look like this:
    public class NavigationTracker : DependencyObject
    {
        private static readonly IDictionary<NavigationAnchor, NavigationPoints> _navigationLookup =
            new Dictionary<NavigationAnchor, NavigationPoints>();
 
        private static void OnNavigationViewChanged(DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var scrollViewer = dependencyObject as ScrollViewer;
 
            if (scrollViewer == null)
            {
                throw new Exception("NavigationTracker can only be applied on ScrollViewers.");
            }
 
            //Only initialize once..
            var initialized = false;
            scrollViewer.SizeChanged += (sender, args) =>
            {
                if (!initialized)
                {
                    Initialize(scrollViewer);
                    initialized = true;
                }
            };
        }
 
        private static void Initialize(ScrollViewer scrollViewer)
        {
            var panel = scrollViewer.Content as Panel;
 
            if (panel == null)
            {
                throw new Exception("Can only track panels in the scrollviewer");
            }
 
            foreach (var child in panel.Children.Cast<FrameworkElement>())
            {
                var matrix = child.TransformToAncestor(scrollViewer);
                var position = new Point(matrix[3].X, matrix[3].Y);
                Debug.Log(position);
            }
        }
 
        // NOTE: Value type needs to match DependencyProperty type!!! (it was string in your code)
        public static void SetNavigationView(UIElement element, NavigationView value)
        {
            element.SetValue(NavigationViewProperty, value);
        }
 
        public static NavigationView GetNavigationView(UIElement element)
        {
            return (NavigationView)element.GetValue(NavigationViewProperty);
        }
 
        public static DependencyProperty NavigationViewProperty =
            DependencyProperty.RegisterAttached("NavigationView", typeof (NavigationView), typeof (NavigationTracker), new PropertyMetadata(null, OnNavigationViewChanged));
    }
The Loaded event shouldn't be fired twice, even if you call UpdateLayout(). This seems like a bug, I'll take note.
 
MrHayato
Topic Author
Posts: 36
Joined: 19 Sep 2014, 21:29

Re: [Unity] Loaded event issues

09 Jul 2015, 22:00

Perfect. This did the trick.

Do you know what the ETA on the Loaded fix would be? I have a feeling we'll encounter this more times later.

Thanks again!
 
User avatar
sfernandez
Site Admin
Posts: 1912
Joined: 22 Dec 2011, 19:20

Re: [Unity] Loaded event issues

10 Jul 2015, 10:53

We want to use the work on this ticket to implement the Initialized event too, and get rid of the OnPostInit() function that deviates from WPF API. As this can break customer code we planned to include it in 1.3 release.

We will study the possibility to modify the Loaded event only so it can be included in an upcoming release of 1.2 version.
 
User avatar
sfernandez
Site Admin
Posts: 1912
Joined: 22 Dec 2011, 19:20

Re: [Unity] Loaded event issues

17 Jul 2015, 13:39

We finally decided to fix the behavior of Loaded event (now will be fired after element gets ready for render) for the next 1.2.4 release. We also included the missing FrameworkElement.Initialized event.
 
User avatar
jsantos
Site Admin
Posts: 2904
Joined: 20 Jan 2012, 17:18
Contact:

Re: [Unity] Loaded event issues

11 Aug 2015, 20:09

Fixed in v1.2.4

Who is online

Users browsing this forum: Bing [Bot] and 1 guest