Beispiel #1
0
        private void RunElementTrackingTestRoutine(Action <
                                                       ObservableCollection <ObservableCollection <string> > /* data */,
                                                       TestScrollingSurface[] /* scrollers */,
                                                       ItemsRepeater /* rootRepeater */> testRoutine)
        {
            // Base setup for our element tracking tests.
            // We have 4 fake scrollers in series, initially in a non scrollable configuration.
            // Under them we have a group repeater tree (2 groups with 3 items each).
            // The group UI is a StackPanel with a TextBlock "header" and an inner ItemsRepeater.
            RunOnUIThread.Execute(() =>
            {
                int groupCount    = 2;
                int itemsPerGroup = 3;

                var data = new ObservableCollection <ObservableCollection <string> >(
                    Enumerable.Range(0, groupCount).Select(i => new ObservableCollection <string>(
                                                               Enumerable.Range(0, itemsPerGroup).Select(j => string.Format("Item #{0}.{1}", i, j)))));

                var itemElements = Enumerable.Range(0, groupCount).Select(i =>
                                                                          Enumerable.Range(0, itemsPerGroup).Select(j => new Border {
                    Tag = data[i][j], Width = 50, Height = 50, Background = new SolidColorBrush(Colors.Red)
                }).ToList()).ToArray();

                var headerElements = Enumerable.Range(0, groupCount).Select(i => new TextBlock {
                    Text = "Header #" + i
                }).ToList();
                var groupRepeaters = Enumerable.Range(0, groupCount).Select(i => new ItemsRepeater
                {
                    Tag          = "ItemsRepeater #" + i,
                    ItemsSource  = data[i],
                    ItemTemplate = MockElementFactory.CreateElementFactory(itemElements[i]),
                    Layout       = new TestGridLayout {
                        Orientation = Orientation.Horizontal, MinItemWidth = 50, MinItemHeight = 50, MinRowSpacing = 10, MinColumnSpacing = 10
                    }
                }).ToList();
                var groupElement = Enumerable.Range(0, groupCount).Select(i =>
                {
                    var panel = new StackPanel();
                    panel.Tag = "Group #" + i;
                    panel.Children.Add(headerElements[i]);
                    panel.Children.Add(groupRepeaters[i]);
                    return(panel);
                }).ToList();

                var rootRepeater = new ItemsRepeater
                {
                    Tag          = "Root ItemsRepeater",
                    ItemsSource  = data,
                    ItemTemplate = MockElementFactory.CreateElementFactory(groupElement),
                    Layout       = new TestStackLayout {
                        Orientation = Orientation.Vertical
                    }
                };

                var scrollers = new TestScrollingSurface[4];
                for (int i = 0; i < scrollers.Length; ++i)
                {
                    scrollers[i] = new TestScrollingSurface()
                    {
                        Tag     = "S" + i,
                        Content = i > 0 ? (UIElement)scrollers[i - 1] : rootRepeater
                    };
                }

                var resetScrollers = (Action)(() =>
                {
                    foreach (var scroller in scrollers)
                    {
                        scroller.IsHorizontallyScrollable = false;
                        scroller.IsVerticallyScrollable = false;
                        scroller.RegisterAnchorCandidateFunc = null;
                        scroller.UnregisterAnchorCandidateFunc = null;
                        scroller.GetRelativeViewportFunc = null;
                    }
                });

                var outerScroller    = scrollers.Last();
                outerScroller.Width  = 200.0;
                outerScroller.Height = 2000.0;

                Content = outerScroller;
                Content.UpdateLayout();

                testRoutine(data, scrollers, rootRepeater);
            });
        }
Beispiel #2
0
        // [TestMethod] Temporarily disabled for bug 18866003
        public void ValidateLoadUnload()
        {
            /*
             * if (!PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone2))
             * {
             *  Log.Warning("Skipping: Test has instability on rs1 and rs2. Tracked by bug 18919096");
             *  return;
             * }
             */

            // In this test, we will repeatedly put a repeater in and out
            // of the visual tree, under the same or a different parent.
            // And we will validate that the subscriptions and unsubscriptions to
            // the IRepeaterScrollingSurface events is done in sync.

            TestScrollingSurface scroller1       = null;
            TestScrollingSurface scroller2       = null;
            ItemsRepeater        repeater        = null;
            WeakReference        repeaterWeakRef = null;
            var renderingEvent = new ManualResetEvent(false);

            var unorderedLoadEvent = false;
            var loadCounter        = 0;
            var unloadCounter      = 0;

            int scroller1SubscriberCount = 0;
            int scroller2SubscriberCount = 0;

            RunOnUIThread.Execute(() =>
            {
                CompositionTarget.Rendering += (sender, args) =>
                {
                    renderingEvent.Set();
                };

                var host  = new Grid();
                scroller1 = new TestScrollingSurface()
                {
                    Tag = "Scroller 1"
                };
                scroller2 = new TestScrollingSurface()
                {
                    Tag = "Scroller 2"
                };
                repeater        = new ItemsRepeater();
                repeaterWeakRef = new WeakReference(repeater);

                repeater.Loaded += delegate
                {
                    Log.Comment("ItemsRepeater Loaded in " + ((FrameworkElement)repeater.Parent).Tag);
                    unorderedLoadEvent |= (++loadCounter > unloadCounter + 1);
                };
                repeater.Unloaded += delegate
                {
                    Log.Comment("ItemsRepeater Unloaded");
                    unorderedLoadEvent |= (++unloadCounter > loadCounter);
                };

                // Subscribers count should never go above 1 or under 0.
                var validateSubscriberCount = new Action(() =>
                {
                    Verify.IsLessThanOrEqual(scroller1SubscriberCount, 1);
                    Verify.IsGreaterThanOrEqual(scroller1SubscriberCount, 0);

                    Verify.IsLessThanOrEqual(scroller2SubscriberCount, 1);
                    Verify.IsGreaterThanOrEqual(scroller2SubscriberCount, 0);
                });

                scroller1.ConfigurationChangedAddFunc    = () => { ++scroller1SubscriberCount; validateSubscriberCount(); };
                scroller2.ConfigurationChangedAddFunc    = () => { ++scroller2SubscriberCount; validateSubscriberCount(); };
                scroller1.ConfigurationChangedRemoveFunc = () => { --scroller1SubscriberCount; validateSubscriberCount(); };
                scroller2.ConfigurationChangedRemoveFunc = () => { --scroller2SubscriberCount; validateSubscriberCount(); };

                scroller1.Content = repeater;
                host.Children.Add(scroller1);
                host.Children.Add(scroller2);

                Content = host;
            });

            IdleSynchronizer.Wait();
            Verify.IsTrue(renderingEvent.WaitOne(), "Waiting for rendering event");

            renderingEvent.Reset();
            Log.Comment("Putting repeater in and out of scroller 1 until we observe two out-of-sync loaded/unloaded events.");
            for (int i = 0; i < 2; ++i)
            {
                while (!unorderedLoadEvent)
                {
                    RunOnUIThread.Execute(() =>
                    {
                        // Validate subscription count for events + reset.
                        scroller1.Content = null;
                        scroller1.Content = repeater;
                    });
                    // For this issue to repro, we need to wait in such a way
                    // that we don't tick the UI thread. We can't use IdleSynchronizer here.
                    Task.Delay(16 * 3).Wait();
                }
                unorderedLoadEvent = false;
                Log.Comment("Detected an unordered load/unload event.");
            }

            IdleSynchronizer.Wait();
            Verify.IsTrue(renderingEvent.WaitOne(), "Waiting for rendering event");

            renderingEvent.Reset();
            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(1, scroller1SubscriberCount);
                Verify.AreEqual(0, scroller2SubscriberCount);

                Log.Comment("Moving repeater from scroller 1 to scroller 2.");
                scroller1.Content = null;
                scroller2.Content = repeater;
            });

            IdleSynchronizer.Wait();
            Verify.IsTrue(renderingEvent.WaitOne(), "Waiting for rendering event");

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(0, scroller1SubscriberCount);
                Verify.AreEqual(1, scroller2SubscriberCount);

                Log.Comment("Moving repeater out of scroller 2.");
                scroller2.Content = null;
                repeater          = null;
            });

            Log.Comment("Waiting for repeater to get GCed.");
            for (int i = 0; i < 5 && repeaterWeakRef.IsAlive; ++i)
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                IdleSynchronizer.Wait();
            }
            Verify.IsFalse(repeaterWeakRef.IsAlive);

            renderingEvent.Reset();
            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(0, scroller1SubscriberCount);
                Verify.AreEqual(0, scroller2SubscriberCount);

                Log.Comment("Scroller raise IRepeaterScrollSurface.PostArrange. Make sure no one is subscribing to it.");
                scroller1.InvalidateArrange();
                scroller2.InvalidateArrange();
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            Verify.IsTrue(renderingEvent.WaitOne(), "Waiting for rendering event");
        }