public void ValidateOneScrollerScenario()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("Skipping since version is less than RS5 and effective viewport feature is not available below RS5");
                return;
            }

            var      realizationRects         = new List <Rect>();
            Scroller scroller                 = null;
            var      viewChangeCompletedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var repeater = new ItemsRepeater()
                {
                    Layout = GetMonitoringLayout(new Size(500, 600), realizationRects),
                    HorizontalCacheLength = 0.0,
                    VerticalCacheLength   = 0.0
                };

                scroller = new Scroller
                {
                    Child  = repeater,
                    Width  = 200,
                    Height = 300
                };

                Content = scroller;
                Content.UpdateLayout();

                Verify.AreEqual(2, realizationRects.Count);
                Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]);
                Verify.AreEqual(new Rect(0, 0, 200, 300), realizationRects[1]);
                realizationRects.Clear();

                scroller.ViewChangeCompleted += (Scroller sender, ScrollerViewChangeCompletedEventArgs args) =>
                {
                    viewChangeCompletedEvent.Set();
                };
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                scroller.ChangeOffsets(new ScrollerChangeOffsetsOptions(0.0, 100.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints));
            });
            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(0, 100, 200, 300), realizationRects.Last());
                realizationRects.Clear();

                viewChangeCompletedEvent.Reset();
                scroller.ChangeZoomFactor(new ScrollerChangeZoomFactorOptions(2.0f, ScrollerViewKind.Absolute, Vector2.Zero, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints));
            });
            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(
                    new Rect(0, 100, 100, 150),
                    realizationRects.Last());
                realizationRects.Clear();
            });
        }
        private void CanAddAndRemoveSnapPointsFromAScroller(ScrollSnapPointsAlignment alignment)
        {
            Scroller                scroller   = null;
            ScrollSnapPoint         snapPoint2 = null;
            RepeatedScrollSnapPoint snapPoint3 = null;
            RepeatedScrollSnapPoint snapPoint4 = null;

            RunOnUIThread.Execute(() =>
            {
                scroller = new Scroller();
                ScrollSnapPoint snapPoint1 = new ScrollSnapPoint(snapPointValue: 10, alignment: alignment);
                snapPoint2 = new ScrollSnapPoint(snapPointValue: 10, alignment: alignment);
                snapPoint3 = new RepeatedScrollSnapPoint(offset:  10, interval: 10, start:  10, end: 100, alignment: alignment);
                snapPoint4 = new RepeatedScrollSnapPoint(offset: 100, interval: 10, start: 100, end: 200, alignment: alignment);
                ZoomSnapPoint snapPoint5 = new ZoomSnapPoint(snapPointValue: 10);
                scroller.HorizontalSnapPoints.Add(snapPoint1);
                scroller.VerticalSnapPoints.Add(snapPoint1);
                scroller.ZoomSnapPoints.Add(snapPoint5);
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual <int>(1, scroller.HorizontalSnapPoints.Count);
                Verify.AreEqual <int>(1, scroller.VerticalSnapPoints.Count);
                Verify.AreEqual <int>(1, scroller.ZoomSnapPoints.Count);
                scroller.HorizontalSnapPoints.Add(snapPoint2);
                scroller.HorizontalSnapPoints.Add(snapPoint3);
                scroller.HorizontalSnapPoints.Add(snapPoint4);
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual <int>(4, scroller.HorizontalSnapPoints.Count);
                scroller.HorizontalSnapPoints.Remove(snapPoint2);
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual <int>(3, scroller.HorizontalSnapPoints.Count);
                scroller.HorizontalSnapPoints.Remove(snapPoint2);
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual <int>(3, scroller.HorizontalSnapPoints.Count);
                scroller.HorizontalSnapPoints.Clear();
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual <int>(0, scroller.HorizontalSnapPoints.Count);
                Verify.AreEqual <int>(1, scroller.VerticalSnapPoints.Count);
                Verify.AreEqual <int>(1, scroller.ZoomSnapPoints.Count);
            });
        }
        public void VerifyDefaultsAndBasicSetting()
        {
            NavigationView navView        = null;
            Rectangle      footer         = null;
            TextBlock      header         = null;
            Setter         styleSetter    = null;
            Style          hamburgerStyle = null;

            RunOnUIThread.Execute(() =>
            {
                footer        = new Rectangle();
                footer.Height = 40;

                header      = new TextBlock();
                header.Text = "Header";

                styleSetter          = new Setter();
                styleSetter.Property = FrameworkElement.MinHeightProperty;
                styleSetter.Value    = "80";
                hamburgerStyle       = new Style();

                navView = new NavigationView();

                // Verify Defaults
                Verify.IsTrue(navView.IsPaneOpen);
                Verify.AreEqual(641, navView.CompactModeThresholdWidth);
                Verify.AreEqual(1008, navView.ExpandedModeThresholdWidth);
                Verify.IsNull(navView.PaneFooter);
                Verify.IsNull(navView.Header);
                Verify.IsTrue(navView.IsSettingsVisible);
                Verify.IsTrue(navView.IsPaneToggleButtonVisible);
                Verify.IsTrue(navView.IsTitleBarAutoPaddingEnabled);
                Verify.IsTrue(navView.AlwaysShowHeader);
                Verify.AreEqual(48, navView.CompactPaneLength);
                Verify.AreEqual(320, navView.OpenPaneLength);
                Verify.IsNull(navView.PaneToggleButtonStyle);
                Verify.AreEqual(0, navView.MenuItems.Count);
                Verify.AreEqual(NavigationViewDisplayMode.Minimal, navView.DisplayMode);
                Verify.AreEqual("", navView.PaneTitle);
                Verify.IsFalse(navView.IsBackEnabled);
                Verify.AreEqual(NavigationViewBackButtonVisible.Auto, navView.IsBackButtonVisible);

                // Verify basic setters
                navView.IsPaneOpen = true;
                navView.CompactModeThresholdWidth  = 500;
                navView.ExpandedModeThresholdWidth = 1000;
                navView.PaneFooter                   = footer;
                navView.Header                       = header;
                navView.IsSettingsVisible            = false;
                navView.IsPaneToggleButtonVisible    = false;
                navView.IsTitleBarAutoPaddingEnabled = false;
                navView.AlwaysShowHeader             = false;
                navView.CompactPaneLength            = 40;
                navView.OpenPaneLength               = 300;
                navView.PaneToggleButtonStyle        = hamburgerStyle;
                navView.PaneTitle                    = "ChangedTitle";
                navView.IsBackEnabled                = true;
                navView.IsBackButtonVisible          = NavigationViewBackButtonVisible.Visible;
                // TODO(test adding a MenuItem programmatically)
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.IsTrue(navView.IsPaneOpen);
                Verify.AreEqual(500, navView.CompactModeThresholdWidth);
                Verify.AreEqual(1000, navView.ExpandedModeThresholdWidth);
                Verify.AreEqual(footer, navView.PaneFooter);
                Verify.AreEqual(header, navView.Header);
                Verify.IsFalse(navView.IsSettingsVisible);
                Verify.IsFalse(navView.IsPaneToggleButtonVisible);
                Verify.IsFalse(navView.IsTitleBarAutoPaddingEnabled);
                Verify.IsFalse(navView.AlwaysShowHeader);
                Verify.AreEqual(40, navView.CompactPaneLength);
                Verify.AreEqual(300, navView.OpenPaneLength);
                Verify.AreEqual(hamburgerStyle, navView.PaneToggleButtonStyle);
                Verify.AreEqual("ChangedTitle", navView.PaneTitle);
                Verify.IsTrue(navView.IsBackEnabled);
                Verify.AreEqual(NavigationViewBackButtonVisible.Visible, navView.IsBackButtonVisible);

                // Verify nullable values
                navView.PaneFooter            = null;
                navView.Header                = null;
                navView.PaneToggleButtonStyle = null;
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.IsNull(navView.PaneFooter);
                Verify.IsNull(navView.Header);
                Verify.IsNull(navView.PaneToggleButtonStyle);
            });
        }
        public void CanGrowCacheBufferWithScrollViewer()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5");
                return;
            }

            ScrollViewer  scroller = null;
            ItemsRepeater repeater = null;
            var           measureRealizationRects = new List <Rect>();
            var           arrangeRealizationRects = new List <Rect>();
            var           fullCacheEvent          = new ManualResetEvent(initialState: false);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Preparing the visual tree...");

                scroller = new ScrollViewer
                {
                    Width  = 400,
                    Height = 400
                };

                var layout = new MockVirtualizingLayout
                {
                    MeasureLayoutFunc = (availableSize, context) =>
                    {
                        var ctx = (VirtualizingLayoutContext)context;
                        Log.Comment("MeasureLayout - Rect:" + ctx.RealizationRect);
                        if (measureRealizationRects.Count == 0 || measureRealizationRects.Last() != ctx.RealizationRect)
                        {
                            measureRealizationRects.Add(ctx.RealizationRect);
                        }

                        return(new Size(1000, 2000));
                    },

                    ArrangeLayoutFunc = (finalSize, context) =>
                    {
                        var ctx = (VirtualizingLayoutContext)context;
                        Log.Comment("ArrangeLayout - Rect:" + ctx.RealizationRect);
                        if (arrangeRealizationRects.Count == 0 || arrangeRealizationRects.Last() != ctx.RealizationRect)
                        {
                            arrangeRealizationRects.Add(ctx.RealizationRect);
                        }

                        if (ctx.RealizationRect.Height == scroller.Height * (repeater.VerticalCacheLength + 1))
                        {
                            fullCacheEvent.Set();
                        }

                        return(finalSize);
                    }
                };

                repeater = new ItemsRepeater()
                {
                    Layout = layout
                };

                scroller.Content = repeater;
                Content          = scroller;
            });

            if (!fullCacheEvent.WaitOne(DefaultWaitTimeInMS))
            {
                Verify.Fail("Cache full size never reached.");
            }
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                var cacheLength = repeater.VerticalCacheLength;
                var expectedRealizationWindow = new Rect(
                    -cacheLength / 2 * scroller.Width,
                    -cacheLength / 2 * scroller.Height,
                    (1 + cacheLength) * scroller.Width,
                    (1 + cacheLength) * scroller.Height);

                Log.Comment("Validate that the realization window reached full size.");
                Verify.AreEqual(expectedRealizationWindow, measureRealizationRects.Last());
                Verify.AreEqual(expectedRealizationWindow, arrangeRealizationRects.Last());

                Log.Comment("Validate that the realization window grew by 40 pixels each time during the process.");
                for (int i = 2; i < measureRealizationRects.Count; ++i)
                {
                    Verify.AreEqual(-40, measureRealizationRects[i].X - measureRealizationRects[i - 1].X);
                    Verify.AreEqual(-40, measureRealizationRects[i].Y - measureRealizationRects[i - 1].Y);
                    Verify.AreEqual(80, measureRealizationRects[i].Width - measureRealizationRects[i - 1].Width);
                    Verify.AreEqual(80, measureRealizationRects[i].Height - measureRealizationRects[i - 1].Height);

                    Verify.AreEqual(-40, arrangeRealizationRects[i].X - arrangeRealizationRects[i - 1].X);
                    Verify.AreEqual(-40, arrangeRealizationRects[i].Y - arrangeRealizationRects[i - 1].Y);
                    Verify.AreEqual(80, arrangeRealizationRects[i].Width - arrangeRealizationRects[i - 1].Width);
                    Verify.AreEqual(80, arrangeRealizationRects[i].Height - arrangeRealizationRects[i - 1].Height);
                }
            });
        }
        public void ValidateBasicScrollViewerScenario()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5");
                return;
            }

            var              realizationRects         = new List <Rect>();
            var              viewChangeCompletedEvent = new AutoResetEvent(false);
            ScrollViewer     scrollViewer             = null;
            ManualResetEvent viewChanged    = new ManualResetEvent(false);
            ManualResetEvent layoutMeasured = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var repeater = new ItemsRepeater()
                {
                    Layout = GetMonitoringLayout(new Size(500, 600), realizationRects, layoutMeasured),
                    HorizontalCacheLength = 0.0,
                    VerticalCacheLength   = 0.0
                };

                scrollViewer = new ScrollViewer {
                    Content = repeater,
                    Width   = 200,
                    Height  = 300,
                    HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden,
                    VerticalScrollBarVisibility   = ScrollBarVisibility.Hidden,
                };

                scrollViewer.ViewChanged += (sender, args) =>
                {
                    if (!args.IsIntermediate)
                    {
                        Log.Comment("ViewChanged " + scrollViewer.HorizontalOffset + ":" + scrollViewer.VerticalOffset);
                        viewChanged.Set();
                    }
                };

                Content = scrollViewer;
            });

            Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout");

            RunOnUIThread.Execute(() =>
            {
                // First layout pass will invalidate measure during the first arrange
                // so that we can get a viewport during the second measure/arrange pass.
                Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]);
                Verify.AreEqual(new Rect(0, 0, 200, 300), realizationRects[1]);
                realizationRects.Clear();

                viewChanged.Reset();
                layoutMeasured.Reset();
                scrollViewer.ChangeView(null, 100.0, 1.0f, disableAnimation: true);
            });

            IdleSynchronizer.Wait();
            Verify.IsTrue(viewChanged.WaitOne(), "Did not receive view changed event");
            Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout");
            viewChanged.Reset();
            layoutMeasured.Reset();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(0, 100, 200, 300), realizationRects.Last());
                realizationRects.Clear();
                viewChangeCompletedEvent.Reset();

                // Max viewport offset is (300, 400). Horizontal viewport offset
                // is expected to get coerced from 400 to 300.
                scrollViewer.ChangeView(400, 100.0, 1.0f, disableAnimation: true);
            });

            IdleSynchronizer.Wait();
            Verify.IsTrue(viewChanged.WaitOne(), "Did not receive view changed event");
            Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout");
            viewChanged.Reset();
            layoutMeasured.Reset();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(300, 100, 200, 300), realizationRects.Last());
                realizationRects.Clear();
                viewChangeCompletedEvent.Reset();

                scrollViewer.ChangeView(null, null, 2.0f, disableAnimation: true);
            });

            IdleSynchronizer.Wait();
            Verify.IsTrue(viewChanged.WaitOne(), "Did not receive view changed event");
            Verify.IsTrue(layoutMeasured.WaitOne(), "Did not receive measure on layout");
            viewChanged.Reset();
            layoutMeasured.Reset();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(150, 50, 100, 150), realizationRects.Last());
                realizationRects.Clear();
            });
        }
Пример #6
0
        public void VerifyCorrectionsInNonScrollableDirection()
        {
            ItemsRepeater           rootRepeater = null;
            ScrollViewer            scrollViewer = null;
            ItemsRepeaterScrollHost scrollhost   = null;
            ManualResetEvent        viewChanged  = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                scrollhost = (ItemsRepeaterScrollHost)XamlReader.Load(
                    @"<controls:ItemsRepeaterScrollHost Width='400' Height='600'
                     xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                     xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                     xmlns:controls='using:Microsoft.UI.Xaml.Controls'>
                    <ScrollViewer Width='400' Height='400' x:Name='scrollviewer'>
                        <controls:ItemsRepeater x:Name='repeater'>
                            <DataTemplate>
                                <StackPanel>
                                    <controls:ItemsRepeater ItemsSource='{Binding}'>
                                        <controls:ItemsRepeater.Layout>
                                            <controls:StackLayout Orientation='Horizontal' />
                                        </controls:ItemsRepeater.Layout>
                                    </controls:ItemsRepeater>
                                </StackPanel>
                            </DataTemplate>
                        </controls:ItemsRepeater>
                    </ScrollViewer>
                </controls:ItemsRepeaterScrollHost>");

                rootRepeater              = (ItemsRepeater)scrollhost.FindName("repeater");
                scrollViewer              = (ScrollViewer)scrollhost.FindName("scrollviewer");
                scrollViewer.ViewChanged += (sender, args) =>
                {
                    if (!args.IsIntermediate)
                    {
                        viewChanged.Set();
                    }
                };

                List <List <int> > items = new List <List <int> >();
                for (int i = 0; i < 100; i++)
                {
                    items.Add(Enumerable.Range(0, 4).ToList());
                }
                rootRepeater.ItemsSource = items;
                Content = scrollhost;
            });

            // scroll down several times and validate no crash
            for (int i = 1; i < 5; i++)
            {
                IdleSynchronizer.Wait();
                RunOnUIThread.Execute(() =>
                {
                    scrollViewer.ChangeView(null, i * 200, null);
                });

                Verify.IsTrue(viewChanged.WaitOne(DefaultWaitTimeInMS));
                viewChanged.Reset();
            }
        }
        public void ValidateOneScrollViewerScenario()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5");
                return;
            }

            var          realizationRects         = new List <Rect>();
            ScrollViewer scrollViewer             = null;
            var          viewChangeCompletedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var repeater = new ItemsRepeater()
                {
                    Layout = GetMonitoringLayout(new Size(500, 600), realizationRects),
                    HorizontalCacheLength = 0.0,
                    VerticalCacheLength   = 0.0
                };

                scrollViewer = new ScrollViewer
                {
                    Content = repeater,
                    Width   = 200,
                    Height  = 300
                };

                Content = scrollViewer;
                Content.UpdateLayout();

                Verify.AreEqual(2, realizationRects.Count);
                Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]);
                Verify.AreEqual(new Rect(0, 0, 200, 300), realizationRects[1]);
                realizationRects.Clear();

                scrollViewer.ViewChanged += (Object sender, ScrollViewerViewChangedEventArgs args) =>
                {
                    if (!args.IsIntermediate)
                    {
                        viewChangeCompletedEvent.Set();
                    }
                };
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                scrollViewer.ChangeView(0.0, 100.0, null, true);
            });
            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(0, 100, 200, 300), realizationRects.Last());
                realizationRects.Clear();

                viewChangeCompletedEvent.Reset();
                scrollViewer.ChangeView(null, null, 2.0f, true);
            });
            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(
                    new Rect(0, 50, 100, 150),
                    realizationRects.Last());
                realizationRects.Clear();
            });
        }
        private void AnchoringWithOffsetCoercion(bool reduceAnchorOffset)
        {
            using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper(
                       enableAnchorNotifications: true,
                       enableInteractionSourcesNotifications: true,
                       enableExpressionAnimationStatusNotifications: false))
            {
                Scroller       scroller                     = null;
                Border         anchorElement                = null;
                AutoResetEvent scrollerLoadedEvent          = new AutoResetEvent(false);
                AutoResetEvent scrollerViewChangedEvent     = new AutoResetEvent(false);
                AutoResetEvent scrollerAnchorRequestedEvent = new AutoResetEvent(false);

                // This test validates that the Scroller accounts for maximum vertical offset (based on viewport and content extent)
                // when calculating the vertical offset shift for anchoring. The vertical offset cannot exceed content extent - viewport.

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("Visual tree setup");
                    anchorElement = new Border
                    {
                        Width             = 100,
                        Height            = 100,
                        Background        = new SolidColorBrush(Colors.Red),
                        Margin            = new Thickness(0, 600, 0, 0),
                        VerticalAlignment = VerticalAlignment.Top
                    };

                    Grid grid = new Grid();
                    grid.Children.Add(anchorElement);
                    grid.Width      = 200;
                    grid.Height     = 1000;
                    grid.Background = new SolidColorBrush(Colors.Gray);

                    scroller = new Scroller
                    {
                        Content = grid,
                        Width   = 200,
                        Height  = 200
                    };

                    scroller.Loaded += (object sender, RoutedEventArgs e) =>
                    {
                        Log.Comment("Scroller.Loaded event handler");
                        scrollerLoadedEvent.Set();
                    };

                    scroller.ViewChanged += delegate(Scroller sender, object args)
                    {
                        Log.Comment("ViewChanged - HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}",
                                    sender.HorizontalOffset, sender.VerticalOffset, sender.ZoomFactor);
                        if ((reduceAnchorOffset && sender.VerticalOffset == 400) ||
                            (!reduceAnchorOffset && sender.VerticalOffset == 500))
                        {
                            scrollerViewChangedEvent.Set();
                        }
                    };

                    scroller.AnchorRequested += delegate(Scroller sender, ScrollerAnchorRequestedEventArgs args)
                    {
                        Log.Comment("Scroller.AnchorRequested event handler. Forcing the red Border to be the Scroller anchor.");
                        args.AnchorElement = anchorElement;
                        scrollerAnchorRequestedEvent.Set();
                    };

                    Log.Comment("Setting window content");
                    MUXControlsTestApp.App.TestContentRoot = scroller;
                });

                WaitForEvent("Waiting for Scroller.Loaded event", scrollerLoadedEvent);
                IdleSynchronizer.Wait();

                ScrollTo(scroller, 0.0, 600.0, AnimationMode.Disabled, SnapPointsMode.Ignore);

                RunOnUIThread.Execute(() =>
                {
                    Verify.AreEqual(600, scroller.VerticalOffset);

                    Log.Comment("Scroller.Content height is reduced by 300px. Scroller.VerticalOffset is expected to be reduced by 100px (600 -> 500).");
                    (scroller.Content as Grid).Height = 700;
                    if (reduceAnchorOffset)
                    {
                        Log.Comment("Tracked element is shifted up by 200px within the Scroller.Content (600 -> 400). Anchoring is expected to reduce the VerticalOffset by half of that (500 -> 400).");
                        anchorElement.Margin = new Thickness(0, 400, 0, 0);
                    }
                    scrollerViewChangedEvent.Reset();
                });

                WaitForEvent("Waiting for Scroller.ViewChanged event", scrollerViewChangedEvent);
                WaitForEvent("Waiting for Scroller.AnchorRequested event", scrollerAnchorRequestedEvent);
                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    Verify.AreEqual(reduceAnchorOffset ? 400 : 500, scroller.VerticalOffset);
                });
            }
        }
        // [TestMethod] Issue 1018
        public void CanReuseElementsDuringUniqueIdReset()
        {
            var data = new WinRTCollection(Enumerable.Range(0, 2).Select(i => string.Format("Item #{0}", i)));
            List <UIElement>   mapping        = null;
            ItemsRepeater      repeater       = null;
            MockElementFactory elementFactory = null;
            ContentControl     focusedElement = null;

            RunOnUIThread.Execute(() =>
            {
                mapping = new List <UIElement> {
                    new ContentControl(), new ContentControl()
                };
                repeater = CreateRepeater(
                    MockItemsSource.CreateDataSource(data, supportsUniqueIds: true),
                    MockElementFactory.CreateElementFactory(mapping));
                elementFactory = (MockElementFactory)repeater.ItemTemplate;

                Content = repeater;
                repeater.UpdateLayout();

                focusedElement = (ContentControl)repeater.TryGetElement(1);
                focusedElement.Focus(FocusState.Keyboard);
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                elementFactory.ValidateGetElementCalls(
                    new MockElementFactory.GetElementCallInfo(0, repeater),
                    new MockElementFactory.GetElementCallInfo(1, repeater));
                elementFactory.ValidateRecycleElementCalls();

                data.ResetWith(new[] { data[0], "New item" });

                Verify.AreEqual(0, repeater.GetElementIndex(mapping[0]));
                Verify.AreEqual(1, repeater.GetElementIndex(mapping[1]));
                Verify.IsNull(repeater.TryGetElement(0));
                Verify.IsNull(repeater.TryGetElement(1));

                elementFactory.ValidateGetElementCalls(/* GetElement should not be called */);
                elementFactory.ValidateRecycleElementCalls(/* RecycleElement should not be called */);

                mapping[1] = new ContentControl(); // For "New Item"

                repeater.UpdateLayout();

                Verify.AreEqual(0, repeater.GetElementIndex(mapping[0]));
                Verify.AreEqual(1, repeater.GetElementIndex(mapping[1]));
                Verify.AreEqual(mapping[0], repeater.TryGetElement(0));
                Verify.AreEqual(mapping[1], repeater.TryGetElement(1));

                elementFactory.ValidateGetElementCalls(
                    new MockElementFactory.GetElementCallInfo(1, repeater));
                elementFactory.ValidateRecycleElementCalls(
                    new MockElementFactory.RecycleElementCallInfo(focusedElement, repeater));

                // If the focused element survived the reset, we will keep focus on it. If not, we
                // try to find one based on the index. In this case, the focused element (index 1)
                // got recycled, and we still have index 1 after the stable reset, so the new index 1
                // will get focused. Note that recycling the elements to view generator in the case of
                // stable reset happens during the arrange, so by that time we will have pulled elements
                // from the stable reset pool and maybe created some new elements as well.
                int index = repeater.GetElementIndex(focusedElement);
                Log.Comment("focused index " + index);
                Verify.AreEqual(mapping[1], FocusManager.GetFocusedElement());
            });
        }
        private void AnchoringAtAlmostFarEdge(Orientation orientation)
        {
            using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper(
                       enableAnchorNotifications: true,
                       enableInteractionSourcesNotifications: true,
                       enableExpressionAnimationStatusNotifications: false))
            {
                Scroller       scroller            = null;
                AutoResetEvent scrollerLoadedEvent = new AutoResetEvent(false);

                RunOnUIThread.Execute(() =>
                {
                    scroller = new Scroller();

                    SetupDefaultAnchoringUI(orientation, scroller, scrollerLoadedEvent);
                });

                WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent);

                ZoomTo(scroller, 2.0f, 0.0f, 0.0f, AnimationMode.Disabled, SnapPointsMode.Ignore);

                double horizontalOffset = 0.0;
                double verticalOffset   = 0.0;

                RunOnUIThread.Execute(() =>
                {
                    if (orientation == Orientation.Vertical)
                    {
                        verticalOffset = scroller.ExtentHeight * 2.0 - scroller.Height - 1.0;
                        scroller.VerticalAnchorRatio = 1.0;
                    }
                    else
                    {
                        horizontalOffset = scroller.ExtentWidth * 2.0 - scroller.Width - 1.0;
                        scroller.HorizontalAnchorRatio = 1.0;
                    }
                });

                ScrollTo(scroller, horizontalOffset, verticalOffset, AnimationMode.Disabled, SnapPointsMode.Ignore, false /*hookViewChanged*/);

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("Inserting child at far edge");
                    InsertStackPanelChild((scroller.Content as Border).Child as StackPanel, 1 /*operationCount*/, c_defaultAnchoringUIStackPanelChildrenCount /*newIndex*/, 1 /*newCount*/);
                });

                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("No Scroller offset change expected");
                    if (orientation == Orientation.Vertical)
                    {
                        Verify.AreEqual(scroller.VerticalOffset, verticalOffset);
                    }
                    else
                    {
                        Verify.AreEqual(scroller.HorizontalOffset, horizontalOffset);
                    }
                });
            }
        }
        private void AnchoringElementWithResizedViewport(Orientation orientation, double viewportSizeChange)
        {
            using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper(
                       enableAnchorNotifications: true,
                       enableInteractionSourcesNotifications: true,
                       enableExpressionAnimationStatusNotifications: false))
            {
                Scroller       scroller                 = null;
                AutoResetEvent scrollerLoadedEvent      = new AutoResetEvent(false);
                AutoResetEvent scrollerViewChangedEvent = new AutoResetEvent(false);

                RunOnUIThread.Execute(() =>
                {
                    scroller = new Scroller();

                    SetupDefaultAnchoringUI(orientation, scroller, scrollerLoadedEvent);
                });

                WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent);

                ZoomTo(scroller, 2.0f, 0.0f, 0.0f, AnimationMode.Disabled, SnapPointsMode.Ignore);

                double horizontalOffset = 0.0;
                double verticalOffset   = 0.0;

                RunOnUIThread.Execute(() =>
                {
                    if (orientation == Orientation.Vertical)
                    {
                        verticalOffset = (scroller.ExtentHeight * 2.0 - scroller.Height) / 2.0;
                        scroller.VerticalAnchorRatio = 0.5;
                    }
                    else
                    {
                        horizontalOffset = (scroller.ExtentWidth * 2.0 - scroller.Width) / 2.0;
                        scroller.HorizontalAnchorRatio = 0.5;
                    }
                });

                ScrollTo(scroller, horizontalOffset, verticalOffset, AnimationMode.Disabled, SnapPointsMode.Ignore, false /*hookViewChanged*/);

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("Scroller view prior to viewport size change: HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}",
                                scroller.HorizontalOffset, scroller.VerticalOffset, scroller.ZoomFactor);

                    scroller.ViewChanged += delegate(Scroller sender, object args)
                    {
                        Log.Comment("ViewChanged - HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}",
                                    sender.HorizontalOffset, sender.VerticalOffset, sender.ZoomFactor);
                        scrollerViewChangedEvent.Set();
                    };

                    if (orientation == Orientation.Vertical)
                    {
                        Log.Comment("Changing viewport height");
                        scroller.Height += viewportSizeChange;
                    }
                    else
                    {
                        Log.Comment("Changing viewport width");
                        scroller.Width += viewportSizeChange;
                    }
                });

                WaitForEvent("Waiting for Scroller.ViewChanged event", scrollerViewChangedEvent);
                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("Scroller view after viewport size change: HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}",
                                scroller.HorizontalOffset, scroller.VerticalOffset, scroller.ZoomFactor);
                    Log.Comment("Expecting offset change equal to half the viewport size change");
                    if (orientation == Orientation.Vertical)
                    {
                        Verify.AreEqual(scroller.VerticalOffset, verticalOffset - viewportSizeChange / 2.0);
                    }
                    else
                    {
                        Verify.AreEqual(scroller.HorizontalOffset, horizontalOffset - viewportSizeChange / 2.0);
                    }
                });
            }
        }
        private void AnchoringAtFarEdgeWhileDecreasingViewport(Orientation orientation)
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                Log.Comment("Skipping test on RS1 where InteractionTracker's AdjustPositionXIfGreaterThanThreshold/AdjustPositionYIfGreaterThanThreshold are ineffective in this scenario.");
                return;
            }

            using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper(
                       enableAnchorNotifications: true,
                       enableInteractionSourcesNotifications: true,
                       enableExpressionAnimationStatusNotifications: false))
            {
                Scroller       scroller                 = null;
                AutoResetEvent scrollerLoadedEvent      = new AutoResetEvent(false);
                AutoResetEvent scrollerViewChangedEvent = new AutoResetEvent(false);

                RunOnUIThread.Execute(() =>
                {
                    scroller = new Scroller();

                    SetupDefaultAnchoringUI(orientation, scroller, scrollerLoadedEvent);
                });

                WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent);

                ZoomTo(scroller, 2.0f, 0.0f, 0.0f, AnimationMode.Disabled, SnapPointsMode.Ignore);

                double horizontalOffset = 0.0;
                double verticalOffset   = 0.0;

                RunOnUIThread.Execute(() =>
                {
                    if (orientation == Orientation.Vertical)
                    {
                        verticalOffset = scroller.ExtentHeight * 2.0 - scroller.Height;
                        scroller.VerticalAnchorRatio = 1.0;
                    }
                    else
                    {
                        horizontalOffset = scroller.ExtentWidth * 2.0 - scroller.Width;
                        scroller.HorizontalAnchorRatio = 1.0;
                    }
                });

                ScrollTo(scroller, horizontalOffset, verticalOffset, AnimationMode.Disabled, SnapPointsMode.Ignore, false /*hookViewChanged*/);

                RunOnUIThread.Execute(() =>
                {
                    scroller.ViewChanged += delegate(Scroller sender, object args)
                    {
                        Log.Comment("ViewChanged - HorizontalOffset={0}, VerticalOffset={1}, ZoomFactor={2}",
                                    sender.HorizontalOffset, sender.VerticalOffset, sender.ZoomFactor);
                        scrollerViewChangedEvent.Set();
                    };

                    if (orientation == Orientation.Vertical)
                    {
                        Log.Comment("Decreasing viewport height");
                        scroller.Height -= 100;
                    }
                    else
                    {
                        Log.Comment("Decreasing viewport width");
                        scroller.Width -= 100;
                    }
                });

                WaitForEvent("Waiting for Scroller.ViewChanged event", scrollerViewChangedEvent);
                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    if (orientation == Orientation.Vertical)
                    {
                        verticalOffset = scroller.ExtentHeight * 2.0 - scroller.Height;
                    }
                    else
                    {
                        horizontalOffset = scroller.ExtentWidth * 2.0 - scroller.Width;
                    }

                    Log.Comment("Scroller offset change expected");
                    Verify.AreEqual(scroller.HorizontalOffset, horizontalOffset);
                    Verify.AreEqual(scroller.VerticalOffset, verticalOffset);
                });
            }
        }
Пример #13
0
        public void TransitionFallbackLogic()
        {
            AnimatedIcon animatedIcon       = null;
            var          layoutUpdatedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                animatedIcon        = new AnimatedIcon();
                animatedIcon.Source = new MockIRichAnimatedIconSource();

                Content = animatedIcon;
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                animatedIcon.LayoutUpdated += AnimatedIcon_LayoutUpdated;
                AnimatedIcon.SetState(animatedIcon, "a");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "b");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual("aTob_Start", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                Verify.AreEqual("aTob_End", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));

                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "c");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual("bToc_Start", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                // bToc_End is undefined in MockIRichAnimatedIconSource
                Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));

                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "d");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                // cTod_Start is undefined in MockIRichAnimatedIconSource
                Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                Verify.AreEqual("cTod_End", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));

                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "e");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                // dToe_Start and dToe_End are undefined in MockIRichAnimatedIconSource, the first backup is dToe
                Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                Verify.AreEqual("dToe", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));

                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "f");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                // eTof_Start, eTof_End, and eTof are undefined in MockIRichAnimatedIconSource, the second backup is f
                Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                Verify.AreEqual("f", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));

                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "b");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                // fTob_Start, fTob_End, fTob and b are all undefined in MockIRichAnimatedIconSource, the third backup is any
                // marker which ends with the string "Tob_End"
                Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                Verify.AreEqual("aTob_End", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));

                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "0.12345");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                // bTo0.12345_Start, bTo0.12345_End, bTo0.12345, and 0.12345  are all undefined in MockIRichAnimatedIconSource, and
                // there are no markers which end with the string "To0.12345_End" so finally we attempt to interpret the state as
                // a float to get the position to animate to.
                Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                Verify.AreEqual("0.12345", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));

                layoutUpdatedEvent.Reset();
                AnimatedIcon.SetState(animatedIcon, "Failure");
                Content.UpdateLayout();
            });

            IdleSynchronizer.Wait();
            layoutUpdatedEvent.WaitOne();

            RunOnUIThread.Execute(() =>
            {
                // 0.12345ToFailure_Start, 0.12345ToFailure_End, 0.12345ToFailure, and Failure are all undefined in MockIRichAnimatedIconSource, and
                // there are no markers which end with the string "ToFailure_End" and Failure is not a float, so we have failed to find a marker.
                Verify.AreEqual("", AnimatedIconTestHooks.GetLastAnimationSegmentStart(animatedIcon));
                Verify.AreEqual("0.0", AnimatedIconTestHooks.GetLastAnimationSegmentEnd(animatedIcon));
            });

            void AnimatedIcon_LayoutUpdated(object sender, object e)
            {
                layoutUpdatedEvent.Set();
            }
        }
        public void ChangeOffsetsWhileScrollControllersAreAttached()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                Log.Comment("Skipping failing test on RS1.");
                return;
            }

            Scroller  scroller = null;
            Rectangle rectangleScrollerContent = null;
            CompositionScrollController horizontalScrollController = null;
            CompositionScrollController verticalScrollController   = null;
            AutoResetEvent loadedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                rectangleScrollerContent = new Rectangle();
                scroller = new Scroller();
                horizontalScrollController = new CompositionScrollController();
                verticalScrollController   = new CompositionScrollController();

                horizontalScrollController.Orientation = Orientation.Horizontal;

                horizontalScrollController.LogMessage += (CompositionScrollController sender, string args) =>
                {
                    Log.Comment(args);
                };

                verticalScrollController.LogMessage += (CompositionScrollController sender, string args) =>
                {
                    Log.Comment(args);
                };

                scroller.HorizontalScrollController = horizontalScrollController;
                scroller.VerticalScrollController   = verticalScrollController;

                SetupUIWithScrollControllers(
                    scroller,
                    rectangleScrollerContent,
                    horizontalScrollController,
                    verticalScrollController,
                    loadedEvent);
            });

            WaitForEvent("Waiting for Loaded event", loadedEvent);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("HorizontalScrollController size={0}, {1}", horizontalScrollController.ActualWidth, horizontalScrollController.ActualHeight);
                Log.Comment("VerticalScrollController size={0}, {1}", verticalScrollController.ActualWidth, verticalScrollController.ActualHeight);
            });

            IdleSynchronizer.Wait();

            Log.Comment("Jump to offsets");
            ScrollTo(
                scroller,
                (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 2.0,
                (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 2.0,
                AnimationMode.Disabled,
                SnapPointsMode.Ignore,
                true /*hookViewChanged*/,
                (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 2.0,
                (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 2.0);

            Log.Comment("Animate to offsets");
            ScrollTo(
                scroller,
                (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 4.0,
                (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 4.0,
                AnimationMode.Enabled,
                SnapPointsMode.Ignore,
                false /*hookViewChanged*/,
                (c_defaultUIScrollerContentWidth - c_defaultUIScrollerWidth) / 4.0,
                (c_defaultUIScrollerContentHeight - c_defaultUIScrollerHeight) / 4.0);

            Log.Comment("Jump to zoomFactor 2.0");
            ZoomTo(
                scroller,
                2.0f,
                0.0f,
                0.0f,
                AnimationMode.Disabled,
                SnapPointsMode.Ignore,
                false /*hookViewChanged*/);

            Log.Comment("Animate to zoomFactor 1.5");
            ZoomTo(
                scroller,
                1.5f,
                0.0f,
                0.0f,
                AnimationMode.Enabled,
                SnapPointsMode.Ignore,
                false /*hookViewChanged*/);
        }
Пример #15
0
        public void VerifyFocusedItemIsRecycledOnCollectionReset()
        {
            List <Layout> layouts = new List <Layout>();

            RunOnUIThread.Execute(() =>
            {
                layouts.Add(new MyCustomNonVirtualizingStackLayout());
                layouts.Add(new StackLayout());
            });

            foreach (var layout in layouts)
            {
                List <string> items = new List <string> {
                    "item0", "item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9"
                };
                const int     targetIndex = 4;
                string        targetItem  = items[targetIndex];
                ItemsRepeater repeater    = null;

                RunOnUIThread.Execute(() =>
                {
                    repeater = new ItemsRepeater()
                    {
                        ItemsSource  = items,
                        ItemTemplate = CreateDataTemplateWithContent(@"<Button Content='{Binding}'/>"),
                        Layout       = layout
                    };
                    Content = repeater;
                });

                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("Setting Focus on item " + targetIndex);
                    Button toFocus = (Button)repeater.TryGetElement(targetIndex);
                    Verify.AreEqual(targetItem, toFocus.Content as string);
                    toFocus.Focus(FocusState.Keyboard);
                });

                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("Removing focused element from collection");
                    items.Remove(targetItem);

                    Log.Comment("Reset the collection with an empty list");
                    repeater.ItemsSource = new List <string>();
                });

                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    Log.Comment("Verify new elements");
                    for (int i = 0; i < items.Count; i++)
                    {
                        Button currentButton = (Button)repeater.TryGetElement(i);
                        Verify.IsNull(currentButton);
                    }
                });
            }
        }
        public void ValidateElementClearingOrderFromFlowLayout()
        {
            ItemsSourceView dataSource = null;

            RunOnUIThread.Execute(() => dataSource = new ItemsSourceView(Enumerable.Range(0, 15).ToList()));
            ScrollViewer scrollViewer     = null;
            var          repeater         = SetupRepeater(dataSource, null /*layout*/, out scrollViewer);
            List <int>   clearedIndices   = new List <int>();
            var          viewChangedEvent = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                scrollViewer.ViewChanged += (sender, args) =>
                {
                    if (!args.IsIntermediate)
                    {
                        viewChangedEvent.Set();
                    }
                };

                repeater.Layout           = new StackLayout();
                repeater.ElementPrepared += (sender, args) =>
                {
                    ((FrameworkElement)args.Element).Height = 20;
                };
                repeater.UpdateLayout();

                repeater.ElementClearing += (sender, args) =>
                {
                    int index = repeater.GetElementIndex(args.Element);
                    Log.Comment("Clearing.." + index);
                    clearedIndices.Add(index);
                };

                scrollViewer.ChangeView(null, 100.0, null, disableAnimation: true);
            });

            Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTime), "Waiting for ViewChanged.");
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                // Validate order is 0, 1, 2, 3
                for (int i = 0; i < 4; i++)
                {
                    Verify.AreEqual(i, clearedIndices[i]);
                }

                clearedIndices.Clear();
                viewChangedEvent.Reset();
                scrollViewer.ChangeView(null, 0.0, null, disableAnimation: true);
            });

            Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTime), "Waiting for ViewChanged.");
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                // Validate order is backwards 14, 13, 12, 11
                for (int i = 0; i < 4; i++)
                {
                    Verify.AreEqual(14 - i, clearedIndices[i]);
                }
            });
        }
Пример #17
0
        private void NestedRepeaterWithDataTemplateScenario(bool disableAnimation)
        {
            if (!disableAnimation && PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("This test is showing consistent issues with not scrolling enough on RS5 and 19H1 when animations are enabled, tracked by microsoft-ui-xaml#779");
                return;
            }

            // Example of how to include debug tracing in an ApiTests.ItemsRepeater test's output.
            // using (PrivateLoggingHelper privateLoggingHelper = new PrivateLoggingHelper("Repeater"))
            // {
            ItemsRepeater    rootRepeater = null;
            ScrollViewer     scrollViewer = null;
            ManualResetEvent viewChanged  = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var anchorProvider = (ItemsRepeaterScrollHost)XamlReader.Load(
                    @"<controls:ItemsRepeaterScrollHost Width='400' Height='600'
                        xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                        xmlns:controls='using:Microsoft.UI.Xaml.Controls'>
                    <controls:ItemsRepeaterScrollHost.Resources>
                        <DataTemplate x:Key='ItemTemplate' >
                            <TextBlock Text='{Binding}' />
                        </DataTemplate>
                        <DataTemplate x:Key='GroupTemplate'>
                            <StackPanel>
                                <TextBlock Text='{Binding}' />
                                <controls:ItemsRepeater ItemTemplate='{StaticResource ItemTemplate}' ItemsSource='{Binding}' VerticalCacheLength='0'/>
                            </StackPanel>
                        </DataTemplate>
                    </controls:ItemsRepeaterScrollHost.Resources>
                    <ScrollViewer x:Name='scrollviewer'>
                        <controls:ItemsRepeater x:Name='rootRepeater' ItemTemplate='{StaticResource GroupTemplate}' VerticalCacheLength='0' />
                    </ScrollViewer>
                </controls:ItemsRepeaterScrollHost>");

                rootRepeater              = (ItemsRepeater)anchorProvider.FindName("rootRepeater");
                rootRepeater.SizeChanged += (sender, args) =>
                {
                    Log.Comment($"SizeChanged: Size=({rootRepeater.ActualWidth} x {rootRepeater.ActualHeight})");
                };

                scrollViewer = (ScrollViewer)anchorProvider.FindName("scrollviewer");
                scrollViewer.ViewChanging += (sender, args) =>
                {
                    Log.Comment($"ViewChanging: Next VerticalOffset={args.NextView.VerticalOffset}, Final VerticalOffset={args.FinalView.VerticalOffset}");
                };
                scrollViewer.ViewChanged += (sender, args) =>
                {
                    Log.Comment($"ViewChanged: VerticalOffset={scrollViewer.VerticalOffset}, IsIntermediate={args.IsIntermediate}");

                    if (!args.IsIntermediate)
                    {
                        viewChanged.Set();
                    }
                };

                var itemsSource = new ObservableCollection <ObservableCollection <int> >();
                for (int i = 0; i < 100; i++)
                {
                    itemsSource.Add(new ObservableCollection <int>(Enumerable.Range(0, 5)));
                }
                ;

                rootRepeater.ItemsSource = itemsSource;
                Content = anchorProvider;
            });

            // scroll down several times to cause recycling of elements
            for (int i = 1; i < 10; i++)
            {
                IdleSynchronizer.Wait();
                RunOnUIThread.Execute(() =>
                {
                    Log.Comment($"Size=({rootRepeater.ActualWidth} x {rootRepeater.ActualHeight})");
                    Log.Comment($"ChangeView(VerticalOffset={i * 200})");
                    scrollViewer.ChangeView(null, i * 200, null, disableAnimation);
                });

                Log.Comment("Waiting for view change completion...");
                Verify.IsTrue(viewChanged.WaitOne(DefaultWaitTimeInMS));
                viewChanged.Reset();
                Log.Comment("View change completed");

                RunOnUIThread.Execute(() =>
                {
                    Verify.AreEqual(i * 200, scrollViewer.VerticalOffset);
                });
            }
            // }
        }
        // [TestMethod] Issue #1018
        public void CanPinFocusedElements()
        {
            // Setup a grouped repeater scenario with two groups each containing two items.
            var data = new ObservableCollection <ObservableCollection <string> >(Enumerable
                                                                                 .Range(0, 2)
                                                                                 .Select(i => new ObservableCollection <string>(Enumerable
                                                                                                                                .Range(0, 2)
                                                                                                                                .Select(j => string.Format("Item #{0}.{1}", i, j)))));

            List <ContentControl>[] itemElements   = null;
            ItemsRepeater[]         innerRepeaters = null;
            List <StackPanel>       groupElements  = null;
            ItemsRepeater           rootRepeater   = null;
            var gotFocus = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                itemElements = new[] {
                    Enumerable.Range(0, 2).Select(i => new ContentControl()).ToList(),
                    Enumerable.Range(0, 2).Select(i => new ContentControl()).ToList()
                };

                itemElements[0][0].GotFocus += delegate { gotFocus.Set(); };

                innerRepeaters = Enumerable.Range(0, 2).Select(i => CreateRepeater(
                                                                   MockItemsSource.CreateDataSource(data[i], supportsUniqueIds: false),
                                                                   MockElementFactory.CreateElementFactory(itemElements[i]))).ToArray();

                groupElements = Enumerable.Range(0, 2).Select(i =>
                {
                    var panel = new StackPanel();
                    panel.Children.Add(new ContentControl());
                    panel.Children.Add(innerRepeaters[i]);
                    return(panel);
                }).ToList();

                rootRepeater = CreateRepeater(
                    MockItemsSource.CreateDataSource(data, supportsUniqueIds: false),
                    MockElementFactory.CreateElementFactory(groupElements));
                Content = rootRepeater;
                rootRepeater.UpdateLayout();

                itemElements[0][0].Focus(FocusState.Keyboard);
            });

            Verify.IsTrue(gotFocus.WaitOne(DefaultWaitTimeInMS), "Waiting for focus event on the first element of the first group.");
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Recycle focused element 0.0 and validate it's still realized because it is pinned.");
                {
                    var ctx = (VirtualizingLayoutContext)innerRepeaters[0].Tag;
                    ctx.RecycleElement(itemElements[0][0]);
                    Verify.AreEqual(0, innerRepeaters[0].GetElementIndex(itemElements[0][0]));
                }

                Log.Comment("Recycle element 0.1 and validate it's no longer realized because it is not pinned.");
                {
                    var ctx = (VirtualizingLayoutContext)innerRepeaters[0].Tag;
                    ctx.RecycleElement(itemElements[0][1]);
                    Verify.AreEqual(-1, innerRepeaters[0].GetElementIndex(itemElements[0][1]));
                }

                Log.Comment("Recycle group 0 and validate it's still realized because one of its items is pinned.");
                {
                    var ctx = (VirtualizingLayoutContext)rootRepeater.Tag;
                    ctx.RecycleElement(groupElements[0]);
                    Verify.AreEqual(0, rootRepeater.GetElementIndex(groupElements[0]));
                }

                itemElements[1][1].GotFocus += delegate { gotFocus.Set(); };
                itemElements[1][1].Focus(FocusState.Keyboard);
            });

            Verify.IsTrue(gotFocus.WaitOne(DefaultWaitTimeInMS), "Waiting for focus event on the second element of the second group.");
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Log.Comment(@"Move focus to item 1.1 and validate item 0.0 and group 0 are recycled because 
                 the only thing keeping them around is the fact that item 0.0 was focus pinned");
                {
                    ((VirtualizingLayoutContext)rootRepeater.Tag).RecycleElement(groupElements[0]);
                    ((VirtualizingLayoutContext)innerRepeaters[0].Tag).RecycleElement(itemElements[0][0]);

                    Verify.AreEqual(-1, rootRepeater.GetElementIndex(groupElements[0]));
                    Verify.AreEqual(-1, innerRepeaters[0].GetElementIndex(itemElements[0][0]));
                    Verify.AreEqual(1, innerRepeaters[0].GetElementIndex(itemElements[1][1]));
                }

                Log.Comment(@"Delete item 1.1 from the data. This will force the element to get recycled even if it's pinned.");
                {
                    data[1].RemoveAt(1);
                    rootRepeater.UpdateLayout();

                    Verify.AreEqual(-1, innerRepeaters[1].GetElementIndex(itemElements[1][1]));
                }
            });
        }
Пример #19
0
        public void VerifyStoreScenarioCache()
        {
            ItemsRepeater rootRepeater = null;

            RunOnUIThread.Execute(() =>
            {
                var scrollhost = (ItemsRepeaterScrollHost)XamlReader.Load(
                    @" <controls:ItemsRepeaterScrollHost Width='400' Height='200'
                        xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                        xmlns:controls='using:Microsoft.UI.Xaml.Controls'>
                        <controls:ItemsRepeaterScrollHost.Resources>
                            <DataTemplate x:Key='ItemTemplate' >
                                <TextBlock Text='{Binding}' Height='100' Width='100'/>
                            </DataTemplate>
                            <DataTemplate x:Key='GroupTemplate'>
                                <StackPanel>
                                    <TextBlock Text='{Binding}' />
                                    <controls:ItemsRepeaterScrollHost>
                                        <ScrollViewer HorizontalScrollMode='Enabled' VerticalScrollMode='Disabled' HorizontalScrollBarVisibility='Auto' VerticalScrollBarVisibility='Hidden'>
                                            <controls:ItemsRepeater ItemTemplate='{StaticResource ItemTemplate}' ItemsSource='{Binding}'>
                                                <controls:ItemsRepeater.Layout>
                                                    <controls:StackLayout Orientation='Horizontal' />
                                                </controls:ItemsRepeater.Layout>
                                            </controls:ItemsRepeater>
                                        </ScrollViewer>
                                    </controls:ItemsRepeaterScrollHost>
                                </StackPanel>
                            </DataTemplate>
                        </controls:ItemsRepeaterScrollHost.Resources>
                        <ScrollViewer x:Name='scrollviewer'>
                            <controls:ItemsRepeater x:Name='rootRepeater' ItemTemplate='{StaticResource GroupTemplate}'/>
                        </ScrollViewer>
                    </controls:ItemsRepeaterScrollHost>");

                rootRepeater = (ItemsRepeater)scrollhost.FindName("rootRepeater");

                List <List <int> > items = new List <List <int> >();
                for (int i = 0; i < 100; i++)
                {
                    items.Add(Enumerable.Range(0, 4).ToList());
                }
                rootRepeater.ItemsSource = items;
                Content = scrollhost;
            });

            IdleSynchronizer.Wait();

            // Verify that first items outside the visible range but in the realized range
            // for the inner of the nested repeaters are realized.
            RunOnUIThread.Execute(() =>
            {
                // Group2 will be outside the visible range but within the realized range.
                var group2 = rootRepeater.TryGetElement(2) as StackPanel;
                Verify.IsNotNull(group2);

                var group2Repeater = ((ItemsRepeaterScrollHost)group2.Children[1]).ScrollViewer.Content as ItemsRepeater;
                Verify.IsNotNull(group2Repeater);

                Verify.IsNotNull(group2Repeater.TryGetElement(0));
            });
        }
        public void VerifyOverrides()
        {
            #if !BUILD_LEAN_MUX_FOR_THE_STORE_APP
            RatingControl ratingControl = null;
            PersonPicture personPicture = null;
            #endif
            Slider slider = null;
            Grid   root   = null;

            RunOnUIThread.Execute(() =>
            {
                var appResources = Application.Current.Resources;
                // 1) Override WinUI defined brush in App.Resources.
                appResources["RatingControlCaptionForeground"] = new SolidColorBrush(Colors.Orange);

                // 2) Override system brush used by WinUI ThemeResource.

                ((ResourceDictionary)appResources.ThemeDictionaries["Light"])["SystemAltHighColor"]   = Colors.Green;
                ((ResourceDictionary)appResources.ThemeDictionaries["Default"])["SystemAltHighColor"] = Colors.Green;
                ((ResourceDictionary)appResources.ThemeDictionaries["HighContrast"])["SystemColorButtonTextColor"] = Colors.Green;

                // 3) Override brush name used by a system control
                appResources["SliderTrackValueFill"] = new SolidColorBrush(Colors.Purple);

                root = new Grid
                {
                    Background = new SolidColorBrush(Colors.AntiqueWhite),
                };

                StackPanel panel = new StackPanel {
                    Orientation = Orientation.Vertical
                };
                panel.Children.Add(slider = new Slider());

                #if !BUILD_LEAN_MUX_FOR_THE_STORE_APP
                panel.Children.Add(ratingControl = new RatingControl()
                {
                    Value = 2
                });
                panel.Children.Add(personPicture = new PersonPicture());
                #endif

                root.Children.Add(panel);
                // Add an element over top to prevent stray mouse input from interfering.
                root.Children.Add(new Button
                {
                    Background          = new SolidColorBrush(Color.FromArgb(30, 0, 255, 0)),
                    HorizontalAlignment = HorizontalAlignment.Stretch,
                    VerticalAlignment   = VerticalAlignment.Stretch
                });

                MUXControlsTestApp.App.TestContentRoot = root;
            });
            IdleSynchronizer.TryWait();

            //System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(20)).Wait();

            RunOnUIThread.Execute(() =>
            {
                #if !BUILD_LEAN_MUX_FOR_THE_STORE_APP
                // 1) Verify that overriding WinUI defined brushes in App.Resources works.
                Verify.AreEqual(Colors.Orange, ((SolidColorBrush)ratingControl.Foreground).Color,
                                "Verify RatingControlCaptionForeground override in Application.Resources gets picked up by WinUI control");

                // 2) Verify that overriding a system color used by a WinUI control works.
                Verify.AreEqual(Colors.Green, ((SolidColorBrush)personPicture.Foreground).Color,
                                "Verify PersonPictureForegroundThemeBrush (which uses SystemAltHighColor) overridden in Application.Resources gets picked up by WinUI control");
                #endif

                // 3) Verify that overriding a system brush used by a system control works.
                if (PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone1))
                {
                    // Below code is comment because of bug 19180323 and we expect the code to be enabled again after test case is moved to nuget testapp

                    //Verify.AreEqual(Colors.Purple, ((SolidColorBrush)slider.Foreground).Color,
                    //    "Verify Slider (which uses SliderTrackValueFill as its .Foreground) overridden in Application.Resources gets picked up by Slider control");
                }
                else
                {
                    // Before RS1, we used to reference system brushes directly.
                }

                Log.Comment("Setting Window.Current.Content = null");
                MUXControlsTestApp.App.TestContentRoot = null;
            });
            IdleSynchronizer.TryWait();
        }
        public void ValidateTwoScrollViewerScenario()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5");
                return;
            }

            var          realizationRects   = new List <Rect>();
            ScrollViewer horizontalScroller = null;
            ScrollViewer verticalScroller   = null;
            var          horizontalViewChangeCompletedEvent = new AutoResetEvent(false);
            var          verticalViewChangeCompletedEvent   = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var repeater = new ItemsRepeater()
                {
                    Layout = GetMonitoringLayout(new Size(500, 500), realizationRects),
                    HorizontalCacheLength = 0.0,
                    VerticalCacheLength   = 0.0
                };

                horizontalScroller = new ScrollViewer
                {
                    Content = repeater,
                    HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
                    VerticalScrollBarVisibility   = ScrollBarVisibility.Disabled,
                    HorizontalScrollMode          = ScrollMode.Enabled,
                    VerticalScrollMode            = ScrollMode.Disabled
                };

                verticalScroller = new ScrollViewer
                {
                    Content = horizontalScroller,
                    Width   = 200,
                    Height  = 200
                };

                Content = verticalScroller;
                Content.UpdateLayout();

                Verify.AreEqual(2, realizationRects.Count);
                Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]);
                Verify.AreEqual(new Rect(0, 0, 200, 200), realizationRects[1]);
                realizationRects.Clear();

                horizontalScroller.ViewChanged += (Object sender, ScrollViewerViewChangedEventArgs args) =>
                {
                    if (!args.IsIntermediate)
                    {
                        horizontalViewChangeCompletedEvent.Set();
                    }
                };

                verticalScroller.ViewChanged += (Object sender, ScrollViewerViewChangedEventArgs args) =>
                {
                    if (!args.IsIntermediate)
                    {
                        verticalViewChangeCompletedEvent.Set();
                    }
                };
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                verticalScroller.ChangeView(0.0, 100.0, null, true);
            });
            Verify.IsTrue(verticalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(0, 100, 200, 200), realizationRects.Last());
                realizationRects.Clear();

                // Max viewport offset is (300, 300). Horizontal viewport offset
                // is expected to get coerced from 400 to 300.
                horizontalScroller.ChangeView(400.0, 100.0, null, true);
            });
            Verify.IsTrue(horizontalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(300, 100, 200, 200), realizationRects.Last());
                realizationRects.Clear();
            });
        }
Пример #22
0
        public void CanReplaceSingleItem()
        {
            CustomItemsSource dataSource = null;

            RunOnUIThread.Execute(() => dataSource = new CustomItemsSource(Enumerable.Range(0, 10).ToList()));
            ScrollViewer  scrollViewer     = null;
            ItemsRepeater repeater         = null;
            var           viewChangedEvent = new ManualResetEvent(false);
            int           elementsCleared  = 0;
            int           elementsPrepared = 0;

            RunOnUIThread.Execute(() =>
            {
                repeater = SetupRepeater(dataSource, ref scrollViewer);
                scrollViewer.ScrollChanged += (sender, args) =>
                {
                    if (args.HorizontalChange != 0 || args.VerticalChange != 0)
                    {
                        viewChangedEvent.Set();
                    }
                };

                repeater.ElementPrepared += (sender, args) => { elementsPrepared++; };
                repeater.ElementClearing += (sender, args) => { elementsCleared++; };

                scrollViewer.ChangeView(null, 200, null, true);
            });

            Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTime), "Waiting for ViewChanged.");
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                var realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(4, realized);

                Log.Comment("Replace before realized range.");
                dataSource.Replace(index: 0, oldCount: 1, newCount: 1, reset: false);
                repeater.UpdateLayout();

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(4, realized);

                Log.Comment("Replace in realized range.");
                elementsPrepared = 0;
                elementsCleared  = 0;
                dataSource.Replace(index: 2, oldCount: 1, newCount: 1, reset: false);
                repeater.UpdateLayout();
                Verify.AreEqual(1, elementsPrepared);
                Verify.AreEqual(1, elementsCleared);

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(4, realized);

                Log.Comment("Replace after realized range");
                dataSource.Replace(index: 8, oldCount: 1, newCount: 1, reset: false);
                repeater.UpdateLayout();

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(4, realized);
            });
        }
        public void CanBringIntoViewElements()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("Skipping since version is less than RS5 and effective viewport is not available below RS5");
                return;
            }

            if (!PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone3))
            {
                Log.Warning("Skipping CanBringIntoViewElements because UIElement.BringIntoViewRequested was added in RS4.");
                return;
            }

            ScrollViewer  scroller        = null;
            ItemsRepeater repeater        = null;
            var           rootLoadedEvent = new AutoResetEvent(initialState: false);
            var           effectiveViewChangeCompletedEvent = new AutoResetEvent(initialState: false);
            var           viewChangeCompletedEvent          = new AutoResetEvent(initialState: false);

            var viewChangedOffsets = new List <double>();

            RunOnUIThread.Execute(() =>
            {
                var lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam laoreet erat vel massa rutrum, eget mollis massa vulputate. Vivamus semper augue leo, eget faucibus nulla mattis nec. Donec scelerisque lacus at dui ultricies, eget auctor ipsum placerat. Integer aliquet libero sed nisi eleifend, nec rutrum arcu lacinia. Sed a sem et ante gravida congue sit amet ut augue. Donec quis pellentesque urna, non finibus metus. Proin sed ornare tellus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam laoreet erat vel massa rutrum, eget mollis massa vulputate. Vivamus semper augue leo, eget faucibus nulla mattis nec. Donec scelerisque lacus at dui ultricies, eget auctor ipsum placerat. Integer aliquet libero sed nisi eleifend, nec rutrum arcu lacinia. Sed a sem et ante gravida congue sit amet ut augue. Donec quis pellentesque urna, non finibus metus. Proin sed ornare tellus.";
                var root  = (Grid)XamlReader.Load(TestUtilities.ProcessTestXamlForRepo(
                                                      @"<Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' xmlns:controls='using:Microsoft.UI.Xaml.Controls'> 
                         <Grid.Resources>
                           <controls:StackLayout x:Name='VerticalStackLayout' />
                           <controls:RecyclingElementFactory x:Key='ElementFactory'>
                             <controls:RecyclingElementFactory.RecyclePool>
                               <controls:RecyclePool />
                             </controls:RecyclingElementFactory.RecyclePool>
                             <DataTemplate x:Key='ItemTemplate'>
                               <Border Background='LightGray' Margin ='5'>
                                 <TextBlock Text='{Binding}' TextWrapping='WrapWholeWords' />
                               </Border>
                             </DataTemplate>
                           </controls:RecyclingElementFactory>
                         </Grid.Resources>
                         <ScrollViewer x:Name='Scroller' Width='400' Height='600' Background='Gray'>
                           <controls:ItemsRepeater
                             x:Name='ItemsRepeater'
                             ItemTemplate='{StaticResource ElementFactory}'
                             Layout='{StaticResource VerticalStackLayout}'
                             HorizontalCacheLength='0'
                             VerticalCacheLength='0' />
                         </ScrollViewer>
                       </Grid>"));

                var elementFactory = (RecyclingElementFactory)root.Resources["ElementFactory"];
                scroller           = (ScrollViewer)root.FindName("Scroller");
                repeater           = (ItemsRepeater)root.FindName("ItemsRepeater");

                var items = Enumerable.Range(0, 400).Select(i => string.Format("{0}: {1}", i, lorem.Substring(0, 250)));

                repeater.ItemsSource = items;

                scroller.ViewChanged += (o, e) =>
                {
                    Log.Comment("ViewChanged: " + scroller.VerticalOffset);
                    viewChangedOffsets.Add(scroller.VerticalOffset);
                    if (!e.IsIntermediate)
                    {
                        viewChangeCompletedEvent.Set();
                    }
                };

                scroller.EffectiveViewportChanged += (o, args) =>
                {
                    effectiveViewChangeCompletedEvent.Set();
                };

                Content = root;

                root.Loaded += delegate
                {
                    rootLoadedEvent.Set();
                };
            });
            Verify.IsTrue(rootLoadedEvent.WaitOne(DefaultWaitTimeInMS));
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                repeater.GetOrCreateElement(100).StartBringIntoView();
                repeater.UpdateLayout();
            });

            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));
            IdleSynchronizer.Wait();
            Verify.AreEqual(1, viewChangedOffsets.Count);
            viewChangedOffsets.Clear();

            ValidateRealizedRange(repeater, 99, 106);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Scroll into view item 105 (already realized) w/ animation.");
                repeater.TryGetElement(105).StartBringIntoView(new BringIntoViewOptions
                {
                    VerticalAlignmentRatio = 0.5,
                    AnimationDesired       = true
                });
                repeater.UpdateLayout();
            });

            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));
            IdleSynchronizer.Wait();
            Verify.IsLessThanOrEqual(1, viewChangedOffsets.Count);
            viewChangedOffsets.Clear();
            ValidateRealizedRange(repeater, 99, 106);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Scroll item 0 to the top w/ animation and 0.5 vertical alignment.");
                repeater.GetOrCreateElement(0).StartBringIntoView(new BringIntoViewOptions
                {
                    VerticalAlignmentRatio = 0.5,
                    AnimationDesired       = true
                });
                repeater.UpdateLayout();
            });

            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));
            IdleSynchronizer.Wait();
            viewChangedOffsets.Clear();
            ValidateRealizedRange(repeater, 0, 6);

            RunOnUIThread.Execute(() =>
            {
                // You can't align the first group in the middle obviously.
                Verify.AreEqual(0, scroller.VerticalOffset);

                Log.Comment("Scroll to item 20.");
                repeater.GetOrCreateElement(20).StartBringIntoView(new BringIntoViewOptions
                {
                    VerticalAlignmentRatio = 0.0
                });
                repeater.UpdateLayout();
            });

            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));
            IdleSynchronizer.Wait();
            ValidateRealizedRange(repeater, 19, 26);
        }
        private void ViewportHeight(
            bool isScrollerParentSizeSet,
            bool isScrollerParentMaxSizeSet,
            VerticalAlignment scrollerVerticalAlignment,
            double scrollerContentHeight)
        {
            Log.Comment($"ViewportHeight test case - isScrollerParentSizeSet: {isScrollerParentSizeSet}, isScrollerParentMaxSizeSet: {isScrollerParentMaxSizeSet}, scrollerVerticalAlignment: {scrollerVerticalAlignment}, scrollerContentHeight: {scrollerContentHeight}");

            Border         border            = null;
            Scroller       scroller          = null;
            StackPanel     stackPanel        = null;
            Rectangle      rectangle         = null;
            AutoResetEvent borderLoadedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                rectangle = new Rectangle()
                {
                    Width  = 30,
                    Height = scrollerContentHeight
                };

                stackPanel = new StackPanel()
                {
                    BorderThickness   = new Thickness(5),
                    Margin            = new Thickness(7),
                    VerticalAlignment = VerticalAlignment.Top
                };
                stackPanel.Children.Add(rectangle);

                scroller = new Scroller()
                {
                    Content            = stackPanel,
                    ContentOrientation = ContentOrientation.Vertical,
                    VerticalAlignment  = scrollerVerticalAlignment
                };

                border = new Border()
                {
                    BorderThickness   = new Thickness(2),
                    Margin            = new Thickness(3),
                    VerticalAlignment = VerticalAlignment.Center,
                    Child             = scroller
                };
                if (isScrollerParentSizeSet)
                {
                    border.Width  = 300.0;
                    border.Height = 200.0;
                }
                if (isScrollerParentMaxSizeSet)
                {
                    border.MaxWidth  = 300.0;
                    border.MaxHeight = 200.0;
                }

                border.Loaded += (object sender, RoutedEventArgs e) =>
                {
                    Log.Comment("Border.Loaded event handler");
                    borderLoadedEvent.Set();
                };

                Log.Comment("Setting window content");
                MUXControlsTestApp.App.TestContentRoot = border;
            });

            WaitForEvent("Waiting for Border.Loaded event", borderLoadedEvent);
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                double expectedViewportHeight =
                    rectangle.Height + stackPanel.BorderThickness.Top + stackPanel.BorderThickness.Bottom +
                    stackPanel.Margin.Top + stackPanel.Margin.Bottom;

                double borderChildAvailableHeight = border.ActualHeight - border.BorderThickness.Top - border.BorderThickness.Bottom;

                if (expectedViewportHeight > borderChildAvailableHeight || scrollerVerticalAlignment == VerticalAlignment.Stretch)
                {
                    expectedViewportHeight = borderChildAvailableHeight;
                }

                Log.Comment($"border.ActualWidth: {border.ActualWidth}, border.ActualHeight: {border.ActualHeight}");
                Log.Comment($"Checking ViewportWidth - scroller.ViewportWidth: {scroller.ViewportWidth}, scroller.ActualWidth: {scroller.ActualWidth}");
                Verify.AreEqual(scroller.ViewportWidth, scroller.ActualWidth);

                Log.Comment($"Checking ViewportHeight - expectedViewportHeight: {expectedViewportHeight}, scroller.ViewportHeight: {scroller.ViewportHeight}, scroller.ActualHeight: {scroller.ActualHeight}");
                Verify.AreEqual(scroller.ViewportHeight, expectedViewportHeight);
                Verify.AreEqual(scroller.ViewportHeight, scroller.ActualHeight);
            });
        }
        public void CanShareSnapPointsInMultipleCollections()
        {
            Scroller scroller1 = null;
            Scroller scroller2 = null;
            Scroller scroller3 = null;

            ScrollSnapPoint scrollSnapPoint1 = null;
            ScrollSnapPoint scrollSnapPoint2 = null;
            ScrollSnapPoint scrollSnapPoint3 = null;

            RepeatedScrollSnapPoint repeatedScrollSnapPoint1 = null;
            RepeatedScrollSnapPoint repeatedScrollSnapPoint2 = null;
            RepeatedScrollSnapPoint repeatedScrollSnapPoint3 = null;

            ZoomSnapPoint zoomSnapPoint1 = null;
            ZoomSnapPoint zoomSnapPoint2 = null;
            ZoomSnapPoint zoomSnapPoint3 = null;

            RunOnUIThread.Execute(() =>
            {
                scroller1 = new Scroller();
                scroller2 = new Scroller();
                scroller3 = new Scroller();

                scrollSnapPoint1 = new ScrollSnapPoint(snapPointValue: 10, alignment: ScrollSnapPointsAlignment.Near);
                scrollSnapPoint2 = new ScrollSnapPoint(snapPointValue: 20, alignment: ScrollSnapPointsAlignment.Near);
                scrollSnapPoint3 = new ScrollSnapPoint(snapPointValue: 30, alignment: ScrollSnapPointsAlignment.Near);

                repeatedScrollSnapPoint1 = new RepeatedScrollSnapPoint(offset:  10, interval: 10, start:  10, end: 100, alignment: ScrollSnapPointsAlignment.Near);
                repeatedScrollSnapPoint2 = new RepeatedScrollSnapPoint(offset: 200, interval: 10, start: 110, end: 200, alignment: ScrollSnapPointsAlignment.Near);
                repeatedScrollSnapPoint3 = new RepeatedScrollSnapPoint(offset: 300, interval: 10, start: 210, end: 300, alignment: ScrollSnapPointsAlignment.Near);

                zoomSnapPoint1 = new ZoomSnapPoint(snapPointValue: 1);
                zoomSnapPoint2 = new ZoomSnapPoint(snapPointValue: 2);
                zoomSnapPoint3 = new ZoomSnapPoint(snapPointValue: 3);

                scroller1.HorizontalSnapPoints.Add(scrollSnapPoint1);
                scroller1.HorizontalSnapPoints.Add(scrollSnapPoint2);
                scroller1.VerticalSnapPoints.Add(scrollSnapPoint1);
                scroller1.VerticalSnapPoints.Add(scrollSnapPoint3);

                scroller2.HorizontalSnapPoints.Add(repeatedScrollSnapPoint1);
                scroller2.HorizontalSnapPoints.Add(repeatedScrollSnapPoint2);
                scroller2.VerticalSnapPoints.Add(repeatedScrollSnapPoint1);
                scroller2.VerticalSnapPoints.Add(repeatedScrollSnapPoint3);

                scroller1.ZoomSnapPoints.Add(zoomSnapPoint1);
                scroller1.ZoomSnapPoints.Add(zoomSnapPoint2);
                scroller2.ZoomSnapPoints.Add(zoomSnapPoint1);
                scroller2.ZoomSnapPoints.Add(zoomSnapPoint3);

                scroller3.HorizontalSnapPoints.Add(scrollSnapPoint1);
                scroller3.HorizontalSnapPoints.Add(scrollSnapPoint1);
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Vector2 horizontalScrollSnapPoint11ApplicableZone = ScrollerTestHooks.GetHorizontalSnapPointActualApplicableZone(scroller1, scrollSnapPoint1);
                Vector2 verticalScrollSnapPoint11ApplicableZone   = ScrollerTestHooks.GetVerticalSnapPointActualApplicableZone(scroller1, scrollSnapPoint1);
                Log.Comment("horizontalScrollSnapPoint11ApplicableZone=" + horizontalScrollSnapPoint11ApplicableZone.ToString());
                Log.Comment("verticalScrollSnapPoint11ApplicableZone=" + verticalScrollSnapPoint11ApplicableZone.ToString());

                Vector2 horizontalScrollSnapPoint21ApplicableZone = ScrollerTestHooks.GetHorizontalSnapPointActualApplicableZone(scroller2, repeatedScrollSnapPoint1);
                Vector2 verticalScrollSnapPoint21ApplicableZone   = ScrollerTestHooks.GetVerticalSnapPointActualApplicableZone(scroller2, repeatedScrollSnapPoint1);
                Log.Comment("horizontalScrollSnapPoint21ApplicableZone=" + horizontalScrollSnapPoint21ApplicableZone.ToString());
                Log.Comment("verticalScrollSnapPoint21ApplicableZone=" + verticalScrollSnapPoint21ApplicableZone.ToString());

                Vector2 zoomSnapPoint11ApplicableZone = ScrollerTestHooks.GetZoomSnapPointActualApplicableZone(scroller1, zoomSnapPoint1);
                Vector2 zoomSnapPoint21ApplicableZone = ScrollerTestHooks.GetZoomSnapPointActualApplicableZone(scroller2, zoomSnapPoint1);
                Log.Comment("zoomSnapPoint11ApplicableZone=" + zoomSnapPoint11ApplicableZone.ToString());
                Log.Comment("zoomSnapPoint21ApplicableZone=" + zoomSnapPoint21ApplicableZone.ToString());

                int combinationCount11 = ScrollerTestHooks.GetHorizontalSnapPointCombinationCount(scroller1, scrollSnapPoint1);
                int combinationCount31 = ScrollerTestHooks.GetHorizontalSnapPointCombinationCount(scroller3, scrollSnapPoint1);
                Log.Comment("combinationCount11=" + combinationCount11);
                Log.Comment("combinationCount31=" + combinationCount31);

                Log.Comment("Expecting different applicable zones for ScrollSnapPoint in horizontal and vertical collections");
                Verify.AreEqual <float>(15.0f, horizontalScrollSnapPoint11ApplicableZone.Y);
                Verify.AreEqual <float>(20.0f, verticalScrollSnapPoint11ApplicableZone.Y);

                Log.Comment("Expecting identical applicable zones for RepeatedScrollSnapPoint in horizontal and vertical collections");
                Verify.AreEqual <float>(10.0f, horizontalScrollSnapPoint21ApplicableZone.X);
                Verify.AreEqual <float>(10.0f, verticalScrollSnapPoint21ApplicableZone.X);
                Verify.AreEqual <float>(100.0f, horizontalScrollSnapPoint21ApplicableZone.Y);
                Verify.AreEqual <float>(100.0f, verticalScrollSnapPoint21ApplicableZone.Y);

                Log.Comment("Expecting different applicable zones for ZoomSnapPoint in two zoom collections");
                Verify.AreEqual <float>(1.5f, zoomSnapPoint11ApplicableZone.Y);
                Verify.AreEqual <float>(2.0f, zoomSnapPoint21ApplicableZone.Y);

                Log.Comment("Expecting different combination counts for ScrollSnapPoint in two horizontal collections");
                Verify.AreEqual <int>(0, combinationCount11);
                Verify.AreEqual <int>(1, combinationCount31);
            });
        }
        public void BasicMargin()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                Log.Comment("Skipping test on RS1.");
                return;
            }

            const double   c_Margin = 50.0;
            Scroller       scroller = null;
            Rectangle      rectangleScrollerContent = null;
            AutoResetEvent scrollerLoadedEvent      = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                rectangleScrollerContent = new Rectangle();
                scroller = new Scroller();

                SetupDefaultUI(scroller, rectangleScrollerContent, scrollerLoadedEvent);
            });

            WaitForEvent("Waiting for Loaded event", scrollerLoadedEvent);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Adding positive Margin to Scroller.Content");
                rectangleScrollerContent.Margin = new Thickness(c_Margin);
            });

            // Try to jump beyond maximum offsets
            ScrollTo(
                scroller,
                c_defaultUIScrollerContentWidth + 2 * c_Margin - c_defaultUIScrollerWidth + 10.0,
                c_defaultUIScrollerContentHeight + 2 * c_Margin - c_defaultUIScrollerHeight + 10.0,
                AnimationMode.Disabled,
                SnapPointsMode.Ignore,
                hookViewChanged: true,
                isAnimationsEnabledOverride: null,
                c_defaultUIScrollerContentWidth + 2 * c_Margin - c_defaultUIScrollerWidth,
                c_defaultUIScrollerContentHeight + 2 * c_Margin - c_defaultUIScrollerHeight);

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Adding negative Margin to Scroller.Content");
                rectangleScrollerContent.Margin = new Thickness(-c_Margin);
            });

            // Try to jump beyond maximum offsets
            ScrollTo(
                scroller,
                c_defaultUIScrollerContentWidth - 2 * c_Margin - c_defaultUIScrollerWidth + 10.0,
                c_defaultUIScrollerContentHeight - 2 * c_Margin - c_defaultUIScrollerHeight + 10.0,
                AnimationMode.Disabled,
                SnapPointsMode.Ignore,
                hookViewChanged: false,
                isAnimationsEnabledOverride: null,
                c_defaultUIScrollerContentWidth - 2 * c_Margin - c_defaultUIScrollerWidth,
                c_defaultUIScrollerContentHeight - 2 * c_Margin - c_defaultUIScrollerHeight);
        }
        public void VerifySingleSelection()
        {
            string             navItemPresenter1CurrentState = string.Empty;
            string             navItemPresenter2CurrentState = string.Empty;
            NavigationView     navView   = null;
            NavigationViewItem menuItem1 = null;
            NavigationViewItem menuItem2 = null;

            RunOnUIThread.Execute(() =>
            {
                navView = new NavigationView();
                Content = navView;

                menuItem1         = new NavigationViewItem();
                menuItem2         = new NavigationViewItem();
                menuItem1.Content = "Item 1";
                menuItem2.Content = "Item 2";

                navView.MenuItems.Add(menuItem1);
                navView.MenuItems.Add(menuItem2);
                navView.Width = 1008; // forces the control into Expanded mode so that the menu renders
                Content.UpdateLayout();

                var menuItemLayoutRoot         = VisualTreeHelper.GetChild(menuItem1, 0) as FrameworkElement;
                var navItemPresenter           = VisualTreeHelper.GetChild(menuItemLayoutRoot, 0) as FrameworkElement;
                var navItemPresenterLayoutRoot = VisualTreeHelper.GetChild(navItemPresenter, 0) as FrameworkElement;
                var statesGroups = VisualStateManager.GetVisualStateGroups(navItemPresenterLayoutRoot);

                foreach (var visualStateGroup in statesGroups)
                {
                    Log.Comment($"VisualStateGroup1: Name={visualStateGroup.Name}, CurrentState={visualStateGroup.CurrentState.Name}");

                    visualStateGroup.CurrentStateChanged += (object sender, VisualStateChangedEventArgs e) =>
                    {
                        Log.Comment($"VisualStateChangedEventArgs1: Name={e.Control.Name}, OldState={e.OldState.Name}, NewState={e.NewState.Name}");
                        navItemPresenter1CurrentState = e.NewState.Name;
                    };
                }

                menuItemLayoutRoot         = VisualTreeHelper.GetChild(menuItem2, 0) as FrameworkElement;
                navItemPresenter           = VisualTreeHelper.GetChild(menuItemLayoutRoot, 0) as FrameworkElement;
                navItemPresenterLayoutRoot = VisualTreeHelper.GetChild(navItemPresenter, 0) as FrameworkElement;
                statesGroups = VisualStateManager.GetVisualStateGroups(navItemPresenterLayoutRoot);

                foreach (var visualStateGroup in statesGroups)
                {
                    Log.Comment($"VisualStateGroup2: Name={visualStateGroup.Name}, CurrentState={visualStateGroup.CurrentState.Name}");

                    visualStateGroup.CurrentStateChanged += (object sender, VisualStateChangedEventArgs e) =>
                    {
                        Log.Comment($"VisualStateChangedEventArgs2: Name={e.Control.Name}, OldState={e.OldState.Name}, NewState={e.NewState.Name}");
                        navItemPresenter2CurrentState = e.NewState.Name;
                    };
                }

                Verify.IsFalse(menuItem1.IsSelected);
                Verify.IsFalse(menuItem2.IsSelected);
                Verify.AreEqual(null, navView.SelectedItem);

                menuItem1.IsSelected = true;
                Content.UpdateLayout();
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual("Selected", navItemPresenter1CurrentState);
                Verify.AreEqual(string.Empty, navItemPresenter2CurrentState);

                Verify.IsTrue(menuItem1.IsSelected);
                Verify.IsFalse(menuItem2.IsSelected);
                Verify.AreEqual(menuItem1, navView.SelectedItem);

                menuItem2.IsSelected = true;
                Content.UpdateLayout();
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual("Normal", navItemPresenter1CurrentState);
                Verify.AreEqual("Selected", navItemPresenter2CurrentState);

                Verify.IsTrue(menuItem2.IsSelected);
                Verify.IsFalse(menuItem1.IsSelected, "MenuItem1 should have been deselected when MenuItem2 was selected");
                Verify.AreEqual(menuItem2, navView.SelectedItem);
            });
        }
Пример #28
0
        public void VerifyCurrentAnchor()
        {
            if (PlatformConfiguration.IsDebugBuildConfiguration())
            {
                // Test is failing in chk configuration due to:
                // Bug #1726 Test Failure: RepeaterTests.VerifyCurrentAnchor
                Log.Warning("Skipping test for Debug builds.");
                return;
            }

            ItemsRepeater           rootRepeater = null;
            ScrollViewer            scrollViewer = null;
            ItemsRepeaterScrollHost scrollhost   = null;
            ManualResetEvent        viewChanged  = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                scrollhost = (ItemsRepeaterScrollHost)XamlReader.Load(
                    @"<controls:ItemsRepeaterScrollHost Width='400' Height='600'
                     xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                     xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                     xmlns:controls='using:Microsoft.UI.Xaml.Controls'>
                    <controls:ItemsRepeaterScrollHost.Resources>
                        <DataTemplate x:Key='ItemTemplate' >
                            <TextBlock Text='{Binding}' Height='50'/>
                        </DataTemplate>
                    </controls:ItemsRepeaterScrollHost.Resources>
                    <ScrollViewer x:Name='scrollviewer'>
                        <controls:ItemsRepeater x:Name='rootRepeater' ItemTemplate='{StaticResource ItemTemplate}' VerticalCacheLength='0' />
                    </ScrollViewer>
                </controls:ItemsRepeaterScrollHost>");

                rootRepeater              = (ItemsRepeater)scrollhost.FindName("rootRepeater");
                scrollViewer              = (ScrollViewer)scrollhost.FindName("scrollviewer");
                scrollViewer.ViewChanged += (sender, args) =>
                {
                    if (!args.IsIntermediate)
                    {
                        viewChanged.Set();
                    }
                };

                rootRepeater.ItemsSource = Enumerable.Range(0, 500);
                Content = scrollhost;
            });

            // scroll down several times and validate current anchor
            for (int i = 1; i < 10; i++)
            {
                IdleSynchronizer.Wait();
                RunOnUIThread.Execute(() =>
                {
                    scrollViewer.ChangeView(null, i * 200, null);
                });

                Verify.IsTrue(viewChanged.WaitOne(DefaultWaitTimeInMS));
                viewChanged.Reset();

                RunOnUIThread.Execute(() =>
                {
                    Verify.AreEqual(i * 200, scrollViewer.VerticalOffset);
                    var anchor = PlatformConfiguration.IsOSVersionLessThan(OSVersion.Redstone5) ?
                                 scrollhost.CurrentAnchor :
                                 scrollViewer.CurrentAnchor;
                    var anchorIndex = rootRepeater.GetElementIndex(anchor);
                    Log.Comment("CurrentAnchor: " + anchorIndex);
                    Verify.AreEqual(i * 4, anchorIndex);
                });
            }
        }
        private NavigationView SetupNavigationViewScrolling(NavigationViewPaneDisplayMode paneDisplayMode = NavigationViewPaneDisplayMode.Auto)
        {
            NavigationView navView = null;

            RunOnUIThread.Execute(() =>
            {
                navView = new NavigationView();
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #1", Icon = new SymbolIcon(Symbol.Undo)
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #2", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItemHeader()
                {
                    Content = "Item #3"
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #4", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #5", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItemSeparator());
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #7", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #8", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #9", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #10", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItemHeader()
                {
                    Content = "Item #11"
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #12", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #13", Icon = new SymbolIcon(Symbol.Cut)
                });
                navView.MenuItems.Add(new NavigationViewItemSeparator());
                navView.MenuItems.Add(new NavigationViewItem()
                {
                    Content = "Item #15", Icon = new SymbolIcon(Symbol.Cut)
                });

                navView.IsBackButtonVisible        = NavigationViewBackButtonVisible.Visible;
                navView.IsSettingsVisible          = true;
                navView.PaneDisplayMode            = paneDisplayMode;
                navView.OpenPaneLength             = 120.0;
                navView.ExpandedModeThresholdWidth = 600.0;
                navView.CompactModeThresholdWidth  = 400.0;
                navView.Width   = 800.0;
                navView.Height  = 600.0;
                navView.Content = "This test should have enough NavigationViewItems to scroll.";
                Content         = navView;
                Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().TryEnterFullScreenMode();
            });

            IdleSynchronizer.Wait();
            return(navView);
        }
        public void ValidateTwoScrollersScenario()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
            {
                Log.Warning("Skipping since version is less than RS5 and effective viewport feature is not available below RS5");
                return;
            }

            var      realizationRects   = new List <Rect>();
            Scroller horizontalScroller = null;
            Scroller verticalScroller   = null;
            var      horizontalViewChangeCompletedEvent = new AutoResetEvent(false);
            var      verticalViewChangeCompletedEvent   = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var repeater = new ItemsRepeater()
                {
                    Layout = GetMonitoringLayout(new Size(500, 500), realizationRects),
                    HorizontalCacheLength = 0.0,
                    VerticalCacheLength   = 0.0
                };

                horizontalScroller = new Scroller
                {
                    Child = repeater,
                    IsChildAvailableHeightConstrained = true
                };

                // Placing a Grid in between two Scroller controls to avoid
                // unsupported combined use of facades and ElementCompositionPreview.
                var grid = new Grid();
                grid.Children.Add(horizontalScroller);

                verticalScroller = new Scroller
                {
                    Child  = grid,
                    Width  = 200,
                    Height = 200,
                    IsChildAvailableWidthConstrained = true
                };

                Content = verticalScroller;
                Content.UpdateLayout();

                Verify.AreEqual(2, realizationRects.Count);
                Verify.AreEqual(new Rect(0, 0, 0, 0), realizationRects[0]);
                Verify.AreEqual(new Rect(0, 0, 200, 200), realizationRects[1]);
                realizationRects.Clear();

                horizontalScroller.ViewChangeCompleted += (Scroller sender, ScrollerViewChangeCompletedEventArgs args) =>
                {
                    horizontalViewChangeCompletedEvent.Set();
                };

                verticalScroller.ViewChangeCompleted += (Scroller sender, ScrollerViewChangeCompletedEventArgs args) =>
                {
                    verticalViewChangeCompletedEvent.Set();
                };
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                verticalScroller.ChangeOffsets(new ScrollerChangeOffsetsOptions(0.0, 100.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints));
            });
            Verify.IsTrue(verticalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(0, 100, 200, 200), realizationRects.Last());
                realizationRects.Clear();

                // Max viewport offset is (300, 300). Horizontal viewport offset
                // is expected to get coerced from 400 to 300.
                horizontalScroller.ChangeOffsets(new ScrollerChangeOffsetsOptions(400.0, 100.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints));
            });
            Verify.IsTrue(horizontalViewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(300, 100, 200, 200), realizationRects.Last());
                realizationRects.Clear();
            });
        }