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  = 200.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 ChangeOffsetsWhileScrollControllersAreAttached()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                Log.Comment("Skipping failing test on RS1.");
                return;
            }

            ScrollPresenter             scrollPresenter = null;
            Rectangle                   rectangleScrollPresenterContent = null;
            CompositionScrollController horizontalScrollController      = null;
            CompositionScrollController verticalScrollController        = null;
            AutoResetEvent              loadedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                // We need the styles of the CompositionScrollController, so let's load them
                App.AppendResourceDictionaryToMergedDictionaries(App.AdditionStylesXaml);

                rectangleScrollPresenterContent = new Rectangle();
                scrollPresenter            = new ScrollPresenter();
                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);
                };

                scrollPresenter.HorizontalScrollController = horizontalScrollController;
                scrollPresenter.VerticalScrollController   = verticalScrollController;

                SetupUIWithScrollControllers(
                    scrollPresenter,
                    rectangleScrollPresenterContent,
                    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(
                scrollPresenter,
                (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 2.0,
                (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 2.0,
                ScrollingAnimationMode.Disabled,
                ScrollingSnapPointsMode.Ignore,
                hookViewChanged: true,
                isAnimationsEnabledOverride: null,
                expectedFinalHorizontalOffset: (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 2.0,
                expectedFinalVerticalOffset: (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 2.0);

            Log.Comment("Animate to offsets");
            ScrollTo(
                scrollPresenter,
                (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 4.0,
                (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 4.0,
                ScrollingAnimationMode.Enabled,
                ScrollingSnapPointsMode.Ignore,
                hookViewChanged: false,
                isAnimationsEnabledOverride: null,
                expectedFinalHorizontalOffset: (c_defaultUIScrollPresenterContentWidth - c_defaultUIScrollPresenterWidth) / 4.0,
                expectedFinalVerticalOffset: (c_defaultUIScrollPresenterContentHeight - c_defaultUIScrollPresenterHeight) / 4.0);

            Log.Comment("Jump to zoomFactor 2.0");
            ZoomTo(
                scrollPresenter,
                2.0f,
                0.0f,
                0.0f,
                ScrollingAnimationMode.Disabled,
                ScrollingSnapPointsMode.Ignore,
                hookViewChanged: false);

            Log.Comment("Animate to zoomFactor 1.5");
            ZoomTo(
                scrollPresenter,
                1.5f,
                0.0f,
                0.0f,
                ScrollingAnimationMode.Enabled,
                ScrollingSnapPointsMode.Ignore,
                hookViewChanged: false);
        }
Example #3
0
        public void ValidateRecycledElementOwnerAffinity()
        {
            RunOnUIThread.Execute(() =>
            {
                ItemsRepeater repeater1 = null;
                ItemsRepeater repeater2 = null;
                const int numItems      = 10;
                var dataCollection      = new ObservableCollection <int>(Enumerable.Range(0, numItems));
                const string recycleKey = "key";

                var dataSource   = MockItemsSource.CreateDataSource <int>(dataCollection, true);
                var layout       = new StackLayout();
                var recyclePool  = new RecyclePool();
                var itemTemplate = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
						 <TextBlock Text='{Binding}' />
					</DataTemplate>"                    );

                repeater1 = new ItemsRepeater()
                {
                    ItemsSource  = dataSource,
                    Layout       = layout,
                    ItemTemplate = new RecyclingElementFactoryDerived()
                    {
                        Templates            = { { "key", itemTemplate } },
                        RecyclePool          = recyclePool,
                        SelectTemplateIdFunc = (object data, UIElement owner) => recycleKey
                    }
                };

                repeater2 = new ItemsRepeater()
                {
                    ItemsSource  = dataSource,
                    Layout       = layout,
                    ItemTemplate = new RecyclingElementFactoryDerived()
                    {
                        Templates            = { { "key", itemTemplate } },
                        RecyclePool          = recyclePool,
                        SelectTemplateIdFunc = (object data, UIElement owner) => recycleKey
                    }
                };

                var root = new StackPanel();
                root.Children.Add(repeater1);
                root.Children.Add(repeater2);

                Content = new ItemsRepeaterScrollHost()
                {
                    Width        = 400,
                    Height       = 400,
                    ScrollViewer = new ScrollViewer()
                    {
                        Content = root
                    }
                };

                Content.UpdateLayout();
                Verify.AreEqual(numItems, VisualTreeHelper.GetChildrenCount(repeater1));
                Verify.AreEqual(numItems, VisualTreeHelper.GetChildrenCount(repeater2));

                // Throw all the elements into the recycle pool
                dataCollection.Clear();
                Content.UpdateLayout();

                for (int i = 0; i < numItems; i++)
                {
                    var element1 = (FrameworkElement)recyclePool.TryGetElement(recycleKey, repeater1);
                    Verify.AreSame(repeater1, element1.Parent);

                    var element2 = (FrameworkElement)recyclePool.TryGetElement(recycleKey, repeater2);
                    Verify.AreSame(repeater2, element2.Parent);
                }
            });
        }
Example #4
0
        public void VerifyAppBarButtonChevronMarginsDoNotCollide()
        {
            StackPanel       root                       = null;
            ManualResetEvent rootLoadedEvent            = new ManualResetEvent(false);
            CommandBar       commandBar                 = null;
            ManualResetEvent commandBarSizeChangedEvent = new ManualResetEvent(false);
            AppBarButton     appBarButton               = null;

            RunOnUIThread.Execute(() =>
            {
                root = (StackPanel)XamlReader.Load(
                    @"<StackPanel xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' 
                        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'> 
                            <StackPanel.Resources>
                                <Visibility x:Key='AppBarButtonHasFlyoutChevronVisibility'>Visible</Visibility>
                                <x:String x:Key='AppBarButtonFlyoutGlyph'>&#xE972;</x:String>
                                <Thickness x:Key='AppBarButtonSubItemChevronMargin'>-22,20,12,0</Thickness>
                                <Thickness x:Key='AppBarButtonSubItemChevronLabelOnRightMargin'>-6,20,12,0</Thickness>
                                <MenuFlyout x:Key='MenuFlyout' Placement='Bottom'>
                                    <MenuFlyoutItem Text='Item 1'/>
                                    <MenuFlyoutItem Text='Item 2'/>
                                    <MenuFlyoutItem Text='Item 3'/>
                                </MenuFlyout>
                            </StackPanel.Resources>
                            <CommandBar x:Name='CommandBar' DefaultLabelPosition='Right'>
                                <AppBarButton Label='Add' Icon='Add' Flyout='{StaticResource MenuFlyout}'/>
                                <AppBarSeparator />
                                <AppBarButton x:Name='LastAppBarButton' Label='Add' Icon='Add' Flyout='{StaticResource MenuFlyout}'/>
                                <AppBarSeparator />
                                <CommandBar.SecondaryCommands>
                                    <AppBarButton Icon='Add' Label='Add' />
                                </CommandBar.SecondaryCommands>
                            </CommandBar>
                      </StackPanel>");

                root.Loaded            += (sender, args) => { rootLoadedEvent.Set(); };
                commandBar              = (CommandBar)root.FindName("CommandBar");
                commandBar.SizeChanged += (sender, args) => { commandBarSizeChangedEvent.Set(); };
                appBarButton            = (AppBarButton)root.FindName("LastAppBarButton");

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

            rootLoadedEvent.WaitOne();
            IdleSynchronizer.Wait();

            FontIcon subItemChevron = null;

            RunOnUIThread.Execute(() =>
            {
                subItemChevron = (FontIcon)GetVisualChildByName(appBarButton, "SubItemChevron");

                Verify.AreEqual((Thickness)root.Resources["AppBarButtonSubItemChevronLabelOnRightMargin"], subItemChevron.Margin);

                commandBarSizeChangedEvent.Reset();
                commandBar.Width = 0;
            });

            commandBarSizeChangedEvent.WaitOne();
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                commandBarSizeChangedEvent.Reset();
                commandBar.Width = double.NaN;
            });

            commandBarSizeChangedEvent.WaitOne();
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual((Thickness)root.Resources["AppBarButtonSubItemChevronLabelOnRightMargin"], subItemChevron.Margin);
            });
        }
        public void ChangeOffsetsWithAttachedBiDirectionalScrollController()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                Log.Comment("Skipping failing test on RS1.");
                return;
            }

            ScrollPresenter scrollPresenter = null;
            Rectangle       rectangleScrollPresenterContent             = null;
            BiDirectionalScrollController biDirectionalScrollController = null;
            AutoResetEvent loadedEvent          = new AutoResetEvent(false);
            AutoResetEvent scrollCompletedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                // We need the styles of the CompositionScrollController, so let's load them
                App.AppendResourceDictionaryToMergedDictionaries(App.AdditionStylesXaml);

                rectangleScrollPresenterContent = new Rectangle();
                scrollPresenter = new ScrollPresenter();
                biDirectionalScrollController = new BiDirectionalScrollController();

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

                scrollPresenter.HorizontalScrollController = biDirectionalScrollController.HorizontalScrollController;
                scrollPresenter.VerticalScrollController   = biDirectionalScrollController.VerticalScrollController;

                SetupUIWithBiDirectionalScrollController(
                    scrollPresenter,
                    rectangleScrollPresenterContent,
                    biDirectionalScrollController,
                    loadedEvent);

                biDirectionalScrollController.ScrollCompleted += (BiDirectionalScrollController sender, BiDirectionalScrollControllerScrollingScrollCompletedEventArgs args) =>
                {
                    Log.Comment("ChangeOffset completed. OffsetsChangeCorrelationId=" + args);

                    Log.Comment("Setting completion event");
                    scrollCompletedEvent.Set();
                };
            });

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

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("BiDirectionalScrollController size={0}, {1}", biDirectionalScrollController.ActualWidth, biDirectionalScrollController.ActualHeight);
            });

            Log.Comment("Jump to zoomFactor 0.75");
            ZoomTo(
                scrollPresenter,
                0.75f,
                0.0f,
                0.0f,
                ScrollingAnimationMode.Disabled,
                ScrollingSnapPointsMode.Ignore);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Jumping to offsets");
                biDirectionalScrollController.ScrollTo(
                    (c_defaultUIScrollPresenterContentWidth * 0.75 - c_defaultUIScrollPresenterWidth) / 4.0,
                    (c_defaultUIScrollPresenterContentHeight * 0.75 - c_defaultUIScrollPresenterHeight) / 4.0,
                    ScrollingAnimationMode.Disabled);
            });

            WaitForEvent("Waiting for operation completion", scrollCompletedEvent);

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual((c_defaultUIScrollPresenterContentWidth * 0.75 - c_defaultUIScrollPresenterWidth) / 4.0, scrollPresenter.HorizontalOffset);
                Verify.AreEqual((c_defaultUIScrollPresenterContentHeight * 0.75 - c_defaultUIScrollPresenterHeight) / 4.0, scrollPresenter.VerticalOffset);

                Log.Comment("Animating to offsets");
                biDirectionalScrollController.ScrollTo(
                    (c_defaultUIScrollPresenterContentWidth * 0.75 - c_defaultUIScrollPresenterWidth) / 2.0,
                    (c_defaultUIScrollPresenterContentHeight * 0.75 - c_defaultUIScrollPresenterHeight) / 2.0,
                    ScrollingAnimationMode.Enabled);

                scrollCompletedEvent.Reset();
            });

            WaitForEvent("Waiting for operation completion", scrollCompletedEvent);

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual((c_defaultUIScrollPresenterContentWidth * 0.75 - c_defaultUIScrollPresenterWidth) / 2.0, scrollPresenter.HorizontalOffset);
                Verify.AreEqual((c_defaultUIScrollPresenterContentHeight * 0.75 - c_defaultUIScrollPresenterHeight) / 2.0, scrollPresenter.VerticalOffset);
            });
        }
        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();
            }
        }
Example #7
0
        public void ValidateXBindWithoutPhasing()
        {
            ItemsRepeater    repeater  = null;
            int              numPhases = 1; // Just Phase 0 for x:Bind
            ManualResetEvent ElementLoadedCompleted = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var itemTemplate = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                            <Button Width='100' Height='100'/>
                        </DataTemplate>");
                repeater = new ItemsRepeater()
                {
                    ItemsSource  = Enumerable.Range(0, 10),
                    ItemTemplate = new CustomElementFactory(numPhases),
                    Layout       = new StackLayout(),
                };

                repeater.ElementPrepared += (sender, args) =>
                {
                    if (args.Index == expectedLastRealizedIndex)
                    {
                        Log.Comment("Item 8 Created!");
                        ElementLoadedCompleted.Set();
                    }
                };

                Content = new ItemsRepeaterScrollHost()
                {
                    Width        = 400,
                    Height       = 400,
                    ScrollViewer = new ScrollViewer
                    {
                        Content = repeater
                    }
                };
            });

            if (ElementLoadedCompleted.WaitOne(TimeSpan.FromMilliseconds(2000)))
            {
                RunOnUIThread.Execute(() =>
                {
                    var calls = ElementPhasingManager.ProcessedCalls;

                    Verify.AreEqual(calls.Count, 9);
                    calls[0].RemoveAt(0); // Remove the create we did for first measure.
                    foreach (var index in calls.Keys)
                    {
                        var phases = calls[index];
                        Verify.AreEqual(1, phases.Count); // Just phase 0
                    }

                    ElementPhasingManager.ProcessedCalls.Clear();
                });
            }
            else
            {
                Verify.Fail("Failed on waiting on build tree.");
            }
        }
        private void AnchoringWithOffsetCoercion(bool reduceAnchorOffset)
        {
            using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper())
            {
                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();

                ChangeOffsets(scroller, 0.0, 600.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints);

                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);
                });
            }
        }
        public void AnchoringAtRepeaterMiddle()
        {
            using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper())
            {
                using (PrivateLoggingHelper privateLoggingHelper = new PrivateLoggingHelper("Scroller"))
                {
                    Scroller       scroller                 = null;
                    AutoResetEvent scrollerLoadedEvent      = new AutoResetEvent(false);
                    AutoResetEvent scrollerViewChangedEvent = new AutoResetEvent(false);

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

                        SetupRepeaterAnchoringUI(scroller, scrollerLoadedEvent);

                        scroller.HorizontalAnchorRatio = double.NaN;
                        scroller.VerticalAnchorRatio   = 0.5;
                    });

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

                    ChangeZoomFactor(scroller, 2.0f, 0.0f, 0.0f, ScrollerViewKind.Absolute, ScrollerViewChangeKind.AllowAnimation);
                    ChangeOffsets(scroller, 0.0, 250.0, ScrollerViewKind.Absolute, ScrollerViewChangeKind.AllowAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints, false /*hookViewChanged*/);

                    ItemsRepeater  repeater   = null;
                    TestDataSource dataSource = null;

                    RunOnUIThread.Execute(() =>
                    {
                        repeater   = (scroller.Content as Border).Child as ItemsRepeater;
                        dataSource = repeater.ItemsSource as TestDataSource;

                        scroller.ViewChanged += delegate(Scroller sender, object args) {
                            scrollerViewChangedEvent.Set();
                        };

                        Log.Comment("Inserting items at the beginning");
                        dataSource.Insert(0 /*index*/, 2 /*count*/);
                    });

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

                    RunOnUIThread.Execute(() =>
                    {
                        Log.Comment("Scroller offset change expected");
                        Verify.AreEqual(scroller.VerticalOffset, 520.0);
                    });

                    RunOnUIThread.Execute(() =>
                    {
                        scrollerViewChangedEvent.Reset();

                        Log.Comment("Removing items from the beginning");
                        dataSource.Remove(0 /*index*/, 2 /*count*/);
                    });

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

                    RunOnUIThread.Execute(() =>
                    {
                        Log.Comment("Scroller offset change expected");
                        Verify.AreEqual(scroller.VerticalOffset, 250.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())
            {
                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);

                ChangeZoomFactor(scroller, 2.0f, 0.0f, 0.0f, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation);

                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;
                    }
                });

                ChangeOffsets(scroller, horizontalOffset, verticalOffset, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints, 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);
                });
            }
        }
        private void AnchoringElementWithResizedViewport(Orientation orientation, double viewportSizeChange)
        {
            using (ScrollerTestHooksHelper scrollerTestHooksHelper = new ScrollerTestHooksHelper())
            {
                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);

                ChangeZoomFactor(scroller, 2.0f, 0.0f, 0.0f, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation);

                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;
                    }
                });

                ChangeOffsets(scroller, horizontalOffset, verticalOffset, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation, ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints, 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);
                    }
                });
            }
        }
Example #12
0
        public void ValidateElementAnimator()
        {
            ItemsRepeater          repeater = null;
            ElementAnimatorDerived animator = null;
            var data           = new ObservableCollection <string>(Enumerable.Range(0, 10).Select(i => string.Format("Item #{0}", i)));
            var renderingEvent = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var elementFactory               = new RecyclingElementFactory();
                elementFactory.RecyclePool       = new RecyclePool();
                elementFactory.Templates["Item"] = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> 
						  <TextBlock Text='{Binding}' Height='50' />
					  </DataTemplate>"                    );

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

                repeater = new ItemsRepeater()
                {
                    ItemsSource  = data,
                    ItemTemplate = elementFactory,
                };

                Content = new ItemsRepeaterScrollHost()
                {
                    Width        = 400,
                    Height       = 800,
                    ScrollViewer = new ScrollViewer
                    {
                        Content = repeater
                    }
                };
            });

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

            List <CallInfo> showCalls         = new List <CallInfo>();
            List <CallInfo> hideCalls         = new List <CallInfo>();
            List <CallInfo> boundsChangeCalls = new List <CallInfo>();

            RunOnUIThread.Execute(() =>
            {
                animator = new ElementAnimatorDerived()
                {
                    HasShowAnimationValue         = true,
                    HasHideAnimationValue         = true,
                    HasBoundsChangeAnimationValue = true,
                    StartShowAnimationFunc        = (UIElement element, AnimationContext context) =>
                    {
                        showCalls.Add(new CallInfo(repeater.GetElementIndex(element), context));
                    },

                    StartHideAnimationFunc = (UIElement element, AnimationContext context) =>
                    {
                        hideCalls.Add(new CallInfo(repeater.GetElementIndex(element), context));
                    },

                    StartBoundsChangeAnimationFunc = (UIElement element, AnimationContext context, Rect oldBounds, Rect newBounds) =>
                    {
                        boundsChangeCalls.Add(new CallInfo(repeater.GetElementIndex(element), context, oldBounds, newBounds));
                    }
                };
                repeater.Animator = animator;

                renderingEvent.Reset();
                data.Insert(0, "new item");
                data.RemoveAt(2);
            });

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

            Verify.AreEqual(1, showCalls.Count);
            var call = showCalls[0];

            Verify.AreEqual(0, call.Index);
            Verify.AreEqual(AnimationContext.CollectionChangeAdd, call.Context);

            Verify.AreEqual(1, hideCalls.Count);
            call = hideCalls[0];
            Verify.AreEqual(-1, call.Index);             // not in the repeater anymore
            Verify.AreEqual(AnimationContext.CollectionChangeRemove, call.Context);

            Verify.AreEqual(1, boundsChangeCalls.Count);
            call = boundsChangeCalls[0];
            Verify.AreEqual(1, call.Index);
            Verify.AreEqual(AnimationContext.CollectionChangeAdd | AnimationContext.CollectionChangeRemove, call.Context);
            Verify.AreEqual(0, call.OldBounds.Y);
            Verify.AreEqual(50, call.NewBounds.Y);

            showCalls.Clear();
            hideCalls.Clear();
            boundsChangeCalls.Clear();

            // Hookup just for show animations and validate.
            RunOnUIThread.Execute(() =>
            {
                animator.HasShowAnimationValue         = true;
                animator.HasHideAnimationValue         = false;
                animator.HasBoundsChangeAnimationValue = false;

                renderingEvent.Reset();
                data.Insert(0, "new item");
                data.RemoveAt(2);
            });

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

            Verify.AreEqual(1, showCalls.Count);
            call = showCalls[0];
            Verify.AreEqual(0, call.Index);
            Verify.AreEqual(AnimationContext.CollectionChangeAdd, call.Context);

            Verify.AreEqual(0, hideCalls.Count);
            Verify.AreEqual(0, boundsChangeCalls.Count);
        }
        public void VerifyCustomItemTemplate()
        {
            BreadcrumbBar breadcrumb  = null;
            BreadcrumbBar breadcrumb2 = null;

            RunOnUIThread.Execute(() =>
            {
                breadcrumb             = new BreadcrumbBar();
                breadcrumb.ItemsSource = new List <string>()
                {
                    "Node 1", "Node 2"
                };

                // Set a custom ItemTemplate to be wrapped in a BreadcrumbBarItem.
                var itemTemplate = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                            <TextBlock Text='{Binding}'/>
                        </DataTemplate>");

                breadcrumb.ItemTemplate = itemTemplate;

                breadcrumb2             = new BreadcrumbBar();
                breadcrumb2.ItemsSource = new List <string>()
                {
                    "Node 1", "Node 2"
                };

                // Set a custom ItemTemplate which is already a BreadcrumbBarItem. No wrapping should be performed.
                var itemTemplate2 = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                            xmlns:controls='using:Microsoft.UI.Xaml.Controls'>
                            <controls:BreadcrumbBarItem Foreground='Blue'>
                              <TextBlock Text = '{Binding}'/>
                            </controls:BreadcrumbBarItem>
                        </DataTemplate>");

                breadcrumb2.ItemTemplate = itemTemplate2;

                var stackPanel = new StackPanel();
                stackPanel.Children.Add(breadcrumb);
                stackPanel.Children.Add(breadcrumb2);

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

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                ItemsRepeater breadcrumbItemsRepeater  = (ItemsRepeater)breadcrumb.FindVisualChildByName("PART_ItemsRepeater");
                ItemsRepeater breadcrumbItemsRepeater2 = (ItemsRepeater)breadcrumb2.FindVisualChildByName("PART_ItemsRepeater");
                Verify.IsNotNull(breadcrumbItemsRepeater, "The underlying items repeater could not be retrieved");
                Verify.IsNotNull(breadcrumbItemsRepeater2, "The underlying items repeater could not be retrieved");

                var breadcrumbNode1 = breadcrumbItemsRepeater.TryGetElement(1) as BreadcrumbBarItem;
                var breadcrumbNode2 = breadcrumbItemsRepeater2.TryGetElement(1) as BreadcrumbBarItem;
                Verify.IsNotNull(breadcrumbNode1, "Our custom ItemTemplate should have been wrapped in a BreadcrumbBarItem.");
                Verify.IsNotNull(breadcrumbNode2, "Our custom ItemTemplate should have been wrapped in a BreadcrumbBarItem.");

                // change this conditions
                bool testCondition = !(breadcrumbNode1.Foreground is SolidColorBrush brush && brush.Color == Colors.Blue);
                Verify.IsTrue(testCondition, "Default foreground color of the BreadcrumbBarItem should not have been [blue].");

                testCondition = breadcrumbNode2.Foreground is SolidColorBrush brush2 && brush2.Color == Colors.Blue;
                Verify.IsTrue(testCondition, "The foreground color of the BreadcrumbBarItem should have been [blue].");
            });
        }
        public void VerifyDropdownItemTemplateWithNoControl()
        {
            BreadcrumbBar breadcrumb = null;

            RunOnUIThread.Execute(() =>
            {
                breadcrumb             = new BreadcrumbBar();
                breadcrumb.ItemsSource = new List <string>()
                {
                    "Node 1", "Node 2"
                };

                // Set a custom ItemTemplate to be wrapped in a BreadcrumbBarItem.
                var itemTemplate = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                            <TextBlock Text='{Binding}'/>
                        </DataTemplate>");

                breadcrumb.ItemTemplate = itemTemplate;

                var stackPanel   = new StackPanel();
                stackPanel.Width = 60;
                stackPanel.Children.Add(breadcrumb);

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

            IdleSynchronizer.Wait();

            Button ellipsisButton = null;

            RunOnUIThread.Execute(() =>
            {
                ItemsRepeater breadcrumbItemsRepeater = (ItemsRepeater)breadcrumb.FindVisualChildByName("PART_ItemsRepeater");
                Verify.IsNotNull(breadcrumbItemsRepeater, "The underlying items repeater (1) could not be retrieved");

                var breadcrumbNode1 = breadcrumbItemsRepeater.TryGetElement(0) as BreadcrumbBarItem;
                Verify.IsNotNull(breadcrumbNode1, "Our custom ItemTemplate (1) should have been wrapped in a BreadcrumbBarItem.");

                ellipsisButton = (Button)breadcrumbNode1.FindVisualChildByName("PART_ItemButton");
                Verify.IsNotNull(ellipsisButton, "The ellipsis item (1) could not be retrieved");

                var automationPeer    = new ButtonAutomationPeer(ellipsisButton);
                var invokationPattern = automationPeer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
                invokationPattern?.Invoke();
            });

            // GetOpenPopups returns empty list in RS3. The scenario works, this just seems to be a
            // test/infra issue in RS3, so filtering it out for now.
            if (PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone3))
            {
                IdleSynchronizer.Wait();

                RunOnUIThread.Execute(() =>
                {
                    var flyout = VisualTreeHelper.GetOpenPopups(Window.Current).Last();
                    Verify.IsNotNull(flyout, "Flyout could not be retrieved");
                    var ellipsisItemsRepeater = TestUtilities.FindDescendents <ItemsRepeater>(flyout).Single();
                    Verify.IsNotNull(ellipsisItemsRepeater, "The underlying flyout items repeater (1) could not be retrieved");

                    ellipsisItemsRepeater.Loaded += (object sender, RoutedEventArgs e) =>
                    {
                        TextBlock ellipsisNode1 = ellipsisItemsRepeater.TryGetElement(0) as TextBlock;
                        Verify.IsNotNull(ellipsisNode1, "Our flyout ItemTemplate (1) should have been wrapped in a TextBlock.");

                        // change this conditions
                        bool testCondition = !(ellipsisNode1.Foreground is SolidColorBrush brush && brush.Color == Colors.Blue);
                        Verify.IsTrue(testCondition, "Default foreground color of the BreadcrumbBarItem should not have been [blue].");
                    };
                });
            }
        }
        public void VerifyCurrentAnchor()
        {
            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);
                });
            }
        }
Example #16
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);
                    }
                });
            }
        }
        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);
                });
            }
            // }
        }
        [TestProperty("TestPass:IncludeOnlyOn", "Desktop")] // TeachingTip doesn't appear to show up correctly in OneCore.
        public void TeachingTipBackgroundTest()
        {
            TeachingTip     teachingTip = null, teachingTipLightDismiss = null;
            SolidColorBrush blueBrush = null;
            Brush           lightDismissBackgroundBrush = null;
            var             loadedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                Grid root           = new Grid();
                teachingTip         = new TeachingTip();
                teachingTip.Loaded += (object sender, RoutedEventArgs args) => { loadedEvent.Set(); };

                teachingTipLightDismiss = new TeachingTip();
                teachingTipLightDismiss.IsLightDismissEnabled = true;

                // Set LightDismiss background before show... it shouldn't take effect in the tree
                blueBrush = new SolidColorBrush(Colors.Blue);
                teachingTipLightDismiss.Background = blueBrush;

                root.Resources.Add("TeachingTip", teachingTip);
                root.Resources.Add("TeachingTipLightDismiss", teachingTipLightDismiss);

                lightDismissBackgroundBrush = MUXControlsTestApp.App.Current.Resources["TeachingTipTransientBackground"] as Brush;
                Verify.IsNotNull(lightDismissBackgroundBrush, "lightDismissBackgroundBrush");

                teachingTip.IsOpen             = true;
                teachingTipLightDismiss.IsOpen = true;

                MUXControlsTestApp.App.TestContentRoot = root;
            });

            IdleSynchronizer.Wait();
            loadedEvent.WaitOne();
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                var redBrush = new SolidColorBrush(Colors.Red);
                teachingTip.SetValue(TeachingTip.BackgroundProperty, redBrush);
                Verify.AreSame(redBrush, teachingTip.GetValue(TeachingTip.BackgroundProperty) as Brush);
                Verify.AreSame(redBrush, teachingTip.Background);

                teachingTip.Background = blueBrush;
                Verify.AreSame(blueBrush, teachingTip.Background);

                {
                    var popup      = TeachingTipTestHooks.GetPopup(teachingTip);
                    var child      = popup.Child;
                    var grandChild = VisualTreeHelper.GetChild(child, 0);
                    Verify.AreSame(blueBrush, ((Grid)grandChild).Background, "Checking TeachingTip.Background TemplateBinding works");
                }

                {
                    var popup       = TeachingTipTestHooks.GetPopup(teachingTipLightDismiss);
                    var child       = popup.Child;
                    var grandChild  = VisualTreeHelper.GetChild(child, 0);
                    var actualBrush = ((Grid)grandChild).Background;
                    Log.Comment("Checking LightDismiss TeachingTip Background is using resource for first invocation");
                    if (lightDismissBackgroundBrush != actualBrush)
                    {
                        if (actualBrush is SolidColorBrush actualSolidBrush)
                        {
                            string teachingTipMessage = $"LightDismiss TeachingTip Background is SolidColorBrush with color {actualSolidBrush.Color}";
                            Log.Comment(teachingTipMessage);
                            Verify.Fail(teachingTipMessage);
                        }
                        else
                        {
                            Verify.AreSame(lightDismissBackgroundBrush, actualBrush, "Checking LightDismiss TeachingTip Background is using resource for first invocation");
                        }
                    }
                }

                teachingTip.IsLightDismissEnabled = true;
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(blueBrush.Color, ((SolidColorBrush)teachingTip.Background).Color);

                var popup      = TeachingTipTestHooks.GetPopup(teachingTip);
                var child      = popup.Child as Grid;
                var grandChild = VisualTreeHelper.GetChild(child, 0);
                var grandChildBackgroundBrush = ((Grid)grandChild).Background;
                //If we can no longer cast the background brush to a solid color brush then changing the
                //IsLightDismissEnabled has changed the background as we expected it to.
                if (grandChildBackgroundBrush is SolidColorBrush)
                {
                    Verify.AreNotEqual(blueBrush.Color, ((SolidColorBrush)grandChildBackgroundBrush).Color);
                }
            });
        }
        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));
            });
        }
Example #20
0
        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();
            });
        }
Example #21
0
        public void ValidatePhaseInvokeAndOrdering()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone2))
            {
                Log.Warning("Skipping: GetAvailableSize API is only available in RS3 and above.");
                return;
            }

            ItemsRepeater    repeater           = null;
            int              numPhases          = 6; // 0 to 5
            ManualResetEvent buildTreeCompleted = new ManualResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var itemTemplate = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                            <Button Width='100' Height='100'/>
                        </DataTemplate>");
                repeater = new ItemsRepeater()
                {
                    ItemsSource  = Enumerable.Range(0, 10),
                    ItemTemplate = new CustomElementFactory(numPhases),
                    Layout       = new StackLayout(),
                };

                repeater.ElementPrepared += (sender, args) =>
                {
                    if (args.Index == expectedLastRealizedIndex)
                    {
                        Log.Comment("Item 8 Created!");
                        RepeaterTestHooks.BuildTreeCompleted += (sender1, args1) =>
                        {
                            buildTreeCompleted.Set();
                        };
                    }
                };

                Content = new ItemsRepeaterScrollHost()
                {
                    Width        = 400,
                    Height       = 400,
                    ScrollViewer = new ScrollViewer
                    {
                        Content = repeater
                    }
                };

                // CompositionTarget.Rendering += (sender, args) => { Log.Comment("Rendering"); }; // debugging aid
            });

            if (buildTreeCompleted.WaitOne(TimeSpan.FromMilliseconds(2000)))
            {
                RunOnUIThread.Execute(() =>
                {
                    var calls = ElementPhasingManager.ProcessedCalls;

                    Verify.AreEqual(9, calls.Count);
                    calls[0].RemoveAt(0); // Remove the create we did for first measure.
                    foreach (var index in calls.Keys)
                    {
                        var phases = calls[index];
                        Verify.AreEqual(6, phases.Count);
                        for (int i = 0; i < phases.Count; i++)
                        {
                            Verify.AreEqual(i, phases[i]);
                        }
                    }

                    ElementPhasingManager.ProcessedCalls.Clear();
                });
            }
            else
            {
                Verify.Fail("Failed on waiting on build tree.");
            }
        }
Example #22
0
        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();
            });
        }
Example #23
0
        public void VerifyNumberBoxCornerRadius()
        {
            /*
             * if (PlatformConfiguration.IsOSVersionLessThan(OSVersion.Redstone5))
             * {
             *  Log.Warning("NumberBox CornerRadius property is not available pre-rs5");
             *  return;
             * }
             */

            var numberBox = SetupNumberBox();

            RepeatButton spinButtonDown = null;
            TextBox      textBox        = null;

            RunOnUIThread.Execute(() =>
            {
                // first test: Uniform corner radius of '2' with no spin buttons shown
                numberBox.SpinButtonPlacementMode = NumberBoxSpinButtonPlacementMode.Hidden;
                numberBox.CornerRadius            = new CornerRadius(2);

                Content.UpdateLayout();

                textBox = TestUtilities.FindDescendents <TextBox>(numberBox).Where(e => e.Name == "InputBox").Single();
                Verify.AreEqual(new CornerRadius(2, 2, 2, 2), textBox.GetCornerRadius());

                // second test: Uniform corner radius of '2' with spin buttons in inline mode (T-rule applies now)
                numberBox.SpinButtonPlacementMode = NumberBoxSpinButtonPlacementMode.Inline;
                Content.UpdateLayout();

                spinButtonDown = TestUtilities.FindDescendents <RepeatButton>(numberBox).Where(e => e.Name == "DownSpinButton").Single();

                Verify.AreEqual(new CornerRadius(2, 0, 0, 2), textBox.GetCornerRadius());
                Verify.AreEqual(new CornerRadius(0, 2, 2, 0), spinButtonDown.GetCornerRadius());

                // third test: Set uniform corner radius to '4' with spin buttons in inline mode
                numberBox.CornerRadius = new CornerRadius(4);
            });
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                // This check makes sure that updating the CornerRadius values of the numberbox in inline mode
                // does not break the T-rule.
                Verify.AreEqual(new CornerRadius(4, 0, 0, 4), textBox.GetCornerRadius());
                Verify.AreEqual(new CornerRadius(0, 4, 4, 0), spinButtonDown.GetCornerRadius());

                // fourth test: Update the spin button placement mode to 'compact' and verify that all corners
                // of the textbox are now rounded again
                numberBox.SpinButtonPlacementMode = NumberBoxSpinButtonPlacementMode.Compact;
                Content.UpdateLayout();

                Verify.AreEqual(new CornerRadius(4), textBox.GetCornerRadius());

                // fifth test: Check corner radius of 0 in compact mode.
                numberBox.CornerRadius = new CornerRadius(0);
                Content.UpdateLayout();

                Verify.AreEqual(new CornerRadius(0), textBox.GetCornerRadius());
            });
        }
Example #24
0
        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 ChangeOffsetsWithAdditionalVelocityAndAttachedBiDirectionalScrollController()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                Log.Comment("Skipping failing test on RS1.");
                return;
            }

            ScrollPresenter scrollPresenter = null;
            Rectangle       rectangleScrollPresenterContent             = null;
            BiDirectionalScrollController biDirectionalScrollController = null;
            AutoResetEvent loadedEvent          = new AutoResetEvent(false);
            AutoResetEvent scrollCompletedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                // We need the styles of the CompositionScrollController, so let's load them
                App.AppendResourceDictionaryToMergedDictionaries(App.AdditionStylesXaml);

                rectangleScrollPresenterContent = new Rectangle();
                scrollPresenter = new ScrollPresenter();
                biDirectionalScrollController = new BiDirectionalScrollController();

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

                scrollPresenter.HorizontalScrollController = biDirectionalScrollController.HorizontalScrollController;
                scrollPresenter.VerticalScrollController   = biDirectionalScrollController.VerticalScrollController;

                SetupUIWithBiDirectionalScrollController(
                    scrollPresenter,
                    rectangleScrollPresenterContent,
                    biDirectionalScrollController,
                    loadedEvent);

                biDirectionalScrollController.ScrollCompleted += (BiDirectionalScrollController sender, BiDirectionalScrollControllerScrollingScrollCompletedEventArgs args) =>
                {
                    Log.Comment("AddScrollVelocity completed. OffsetsChangeCorrelationId=" + args);

                    Log.Comment("Setting completion event");
                    scrollCompletedEvent.Set();
                };
            });

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

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("BiDirectionalScrollController size={0}, {1}", biDirectionalScrollController.ActualWidth, biDirectionalScrollController.ActualHeight);
            });

            Log.Comment("Jump to zoomFactor 0.75");
            ZoomTo(
                scrollPresenter,
                0.75f,
                0.0f,
                0.0f,
                ScrollingAnimationMode.Disabled,
                ScrollingSnapPointsMode.Ignore);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Adding velocity to offsets, with default inertia decay rates");
                biDirectionalScrollController.AddScrollVelocity(
                    new Vector2(100.0f) /*offsetsVelocity*/, null /*inertiaDecayRate*/);
            });

            WaitForEvent("Waiting for operation completion", scrollCompletedEvent);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("scrollPresenter.HorizontalOffset={0}", scrollPresenter.HorizontalOffset);
                Log.Comment("scrollPresenter.VerticalOffset={0}", scrollPresenter.VerticalOffset);

                Verify.IsTrue(scrollPresenter.HorizontalOffset > 20.0);
                Verify.IsTrue(scrollPresenter.VerticalOffset > 20.0);

                Log.Comment("Adding negative velocity to offsets, with custom inertia decay rates");
                biDirectionalScrollController.AddScrollVelocity(
                    new Vector2(-50.0f) /*offsetsVelocity*/, new Vector2(0.9f) /*inertiaDecayRate*/);

                scrollCompletedEvent.Reset();
            });

            WaitForEvent("Waiting for operation completion", scrollCompletedEvent);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("scrollPresenter.HorizontalOffset={0}", scrollPresenter.HorizontalOffset);
                Log.Comment("scrollPresenter.VerticalOffset={0}", scrollPresenter.VerticalOffset);

                Verify.IsTrue(scrollPresenter.HorizontalOffset < 20.0);
                Verify.IsTrue(scrollPresenter.VerticalOffset < 20.0);

                Log.Comment("Adding velocity to offsets, with no inertia decay rates");
                biDirectionalScrollController.AddScrollVelocity(
                    new Vector2(200.0f) /*offsetsVelocity*/, new Vector2(0.0f) /*inertiaDecayRate*/);

                scrollCompletedEvent.Reset();
            });

            WaitForEvent("Waiting for operation completion", scrollCompletedEvent);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("scrollPresenter.HorizontalOffset={0}", scrollPresenter.HorizontalOffset);
                Log.Comment("scrollPresenter.VerticalOffset={0}", scrollPresenter.VerticalOffset);

                Verify.AreEqual(600.0, scrollPresenter.HorizontalOffset);
                Verify.AreEqual(250.0, scrollPresenter.VerticalOffset);
            });
        }
Example #26
0
        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, 101, 109);

            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);
        }
        public void ValidateTabNavigation()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone2))
            {
                Log.Warning("Test is disabled on anything lower than RS3 because the GetChildrenInTabFocusOrder API is not available on previous versions.");
                return;
            }

            ItemsRepeater repeater         = null;
            ScrollViewer  scrollViewer     = null;
            var           data             = new ObservableCollection <string>(Enumerable.Range(0, 50).Select(i => "Item #" + i));
            var           viewChangedEvent = new AutoResetEvent(false);

            RunOnUIThread.Execute(() =>
            {
                var itemTemplate = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                            <Button Content='{Binding}' Height='100' />
                        </DataTemplate>");

                var elementFactory = new RecyclingElementFactory()
                {
                    RecyclePool = new RecyclePool(),
                    Templates   =
                    {
                        { "itemTemplate", itemTemplate },
                    }
                };

                Content = CreateAndInitializeRepeater
                          (
                    data,
                    new StackLayout(),
                    elementFactory,
                    ref repeater,
                    ref scrollViewer
                          );

                scrollViewer.ViewChanged += (s, e) =>
                {
                    if (!e.IsIntermediate)
                    {
                        viewChangedEvent.Set();
                    }
                };

                repeater.TabFocusNavigation = KeyboardNavigationMode.Local;
                Content.UpdateLayout();
                ValidateTabNavigationOrder(repeater);
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                // Move window - disconnected
                scrollViewer.ChangeView(null, 2000, null, true);
            });

            Verify.IsTrue(viewChangedEvent.WaitOne(DefaultWaitTimeInMS), "Waiting for final ViewChanged event.");
            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                ValidateTabNavigationOrder(repeater);

                // Delete a couple of elements and validate we
                // ignore unrealized elements.
                // First visible element is expected to be index 20.
                while (data.Count > 21)
                {
                    data.RemoveAt(21);
                }

                repeater.UpdateLayout();
                ValidateTabNavigationOrder(repeater);
            });
        }
Example #28
0
        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();
            });
        }
Example #29
0
        // [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());
            });
        }
        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);
            });
        }