public void VerifyCorrectionsInNonScrollableDirection()
        {
            ItemsRepeater           rootRepeater = null;
            ScrollViewer            scrollViewer = null;
            ItemsRepeaterScrollHost scrollhost   = null;
            ManualResetEvent        viewChanged  = new ManualResetEvent(false);

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

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

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

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

                Verify.IsTrue(viewChanged.WaitOne(DefaultWaitTimeInMS));
                viewChanged.Reset();
            }
        }
        public void BasicMarginAndAlignment()
        {
            if (PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone4))
            {
                //BUGBUG Bug 19277312: MUX Scroller tests fail on RS5_Release
                return;
            }

            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                // Skipping this test on pre-RS2 since it uses Visual's Translation property.
                return;
            }

            const float    c_smallZoomFactor        = 0.15f;
            const double   c_Margin                 = 40.0;
            Scroller       scroller                 = null;
            Rectangle      rectangleScrollerContent = null;
            AutoResetEvent scrollerLoadedEvent      = new AutoResetEvent(false);
            float          horizontalOffset         = 0.0f;
            float          verticalOffset           = 0.0f;
            float          zoomFactor               = 1.0f;
            Compositor     compositor               = null;

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

                SetupDefaultUI(scroller, rectangleScrollerContent, scrollerLoadedEvent);

                Log.Comment("Adding positive Margin to Scroller.Content");
                rectangleScrollerContent.Margin = new Thickness(c_Margin);
                compositor = Window.Current.Compositor;
            });

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

            // Jump to absolute small zoomFactor to make the content smaller than the viewport.
            ChangeZoomFactor(scroller, c_smallZoomFactor, 0.0f, 0.0f, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Covering Stretch/Strech alignments");
                Verify.AreEqual(rectangleScrollerContent.HorizontalAlignment, HorizontalAlignment.Stretch);
                Verify.AreEqual(rectangleScrollerContent.VerticalAlignment, VerticalAlignment.Stretch);
            });

            SpyTranslationAndScale(scroller, compositor, out horizontalOffset, out verticalOffset, out zoomFactor);

            Verify.IsTrue(Math.Abs(horizontalOffset - 20.0f) < c_defaultOffsetResultTolerance);
            Verify.IsTrue(Math.Abs(verticalOffset - 15.0f) < c_defaultOffsetResultTolerance);
            Verify.AreEqual(zoomFactor, c_smallZoomFactor);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Covering Left/Top alignments");
                rectangleScrollerContent.HorizontalAlignment = HorizontalAlignment.Left;
                rectangleScrollerContent.VerticalAlignment   = VerticalAlignment.Top;
            });

            SpyTranslationAndScale(scroller, compositor, out horizontalOffset, out verticalOffset, out zoomFactor);

            Verify.IsTrue(Math.Abs(horizontalOffset + 34.0f) < c_defaultOffsetResultTolerance);
            Verify.IsTrue(Math.Abs(verticalOffset + 34.0f) < c_defaultOffsetResultTolerance);
            Verify.AreEqual(zoomFactor, c_smallZoomFactor);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Covering Right/Bottom alignments");
                rectangleScrollerContent.HorizontalAlignment = HorizontalAlignment.Right;
                rectangleScrollerContent.VerticalAlignment   = VerticalAlignment.Bottom;
            });

            SpyTranslationAndScale(scroller, compositor, out horizontalOffset, out verticalOffset, out zoomFactor);

            Verify.IsTrue(Math.Abs(horizontalOffset - 74.0f) < c_defaultOffsetResultTolerance);
            Verify.IsTrue(Math.Abs(verticalOffset - 64.0f) < c_defaultOffsetResultTolerance);
            Verify.AreEqual(zoomFactor, c_smallZoomFactor);

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Covering Center/Center alignments");
                rectangleScrollerContent.HorizontalAlignment = HorizontalAlignment.Center;
                rectangleScrollerContent.VerticalAlignment   = VerticalAlignment.Center;
            });

            SpyTranslationAndScale(scroller, compositor, out horizontalOffset, out verticalOffset, out zoomFactor);

            Verify.IsTrue(Math.Abs(horizontalOffset - 20.0f) < c_defaultOffsetResultTolerance);
            Verify.IsTrue(Math.Abs(verticalOffset - 15.0f) < c_defaultOffsetResultTolerance);
            Verify.AreEqual(zoomFactor, c_smallZoomFactor);
        }
        public void ImageWithConstrainedHeight()
        {
            if (PlatformConfiguration.IsOsVersionGreaterThan(OSVersion.Redstone4))
            {
                //BUGBUG Bug 19277312: MUX Scroller tests fail on RS5_Release
                return;
            }

            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                // Skipping this test on pre-RS2 since it uses Visual's Translation property.
                return;
            }

            const float    c_smallZoomFactor    = 0.5f;
            const float    c_largeZoomFactor    = 2.0f;
            const double   c_imageWidth         = 250.0;
            const double   c_topMargin          = 40.0;
            const double   c_bottomMargin       = 10.0;
            Scroller       scroller             = null;
            Image          imageScrollerContent = null;
            AutoResetEvent scrollerLoadedEvent  = new AutoResetEvent(false);
            Compositor     compositor           = null;

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

                Uri uri = new Uri("ms-appx:/Assets/ingredient3.png");
                Verify.IsNotNull(uri);
                imageScrollerContent.Source = new BitmapImage(uri);
                imageScrollerContent.Margin = new Thickness(0, c_topMargin, 0, c_bottomMargin);
                scroller.Content            = imageScrollerContent;
                scroller.Background         = new Media.SolidColorBrush(Colors.Chartreuse);

                SetupDefaultUI(scroller, rectangleScrollerContent: null, scrollerLoadedEvent: scrollerLoadedEvent);

                // Constraining the Image height and making the Scroller smaller than the Image
                imageScrollerContent.Width  = c_imageWidth;
                scroller.ContentOrientation = ContentOrientation.Horizontal;
                compositor = Window.Current.Compositor;
            });

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

            // Jump to absolute small zoomFactor to make the content smaller than the viewport.
            ChangeZoomFactor(scroller, c_smallZoomFactor, 0.0f, 0.0f, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Stretch,
                expectedHorizontalOffset: (float)(c_defaultUIScrollerWidth - c_imageWidth * c_smallZoomFactor) / 2.0f, // 87.5
                expectedMinPosition: (float)(-c_defaultUIScrollerHeight * c_smallZoomFactor / 2.0),                    // -50
                expectedZoomFactor: c_smallZoomFactor);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Top,
                expectedHorizontalOffset: (float)(c_defaultUIScrollerWidth - c_imageWidth * c_smallZoomFactor) / 2.0f, // 87.5
                expectedMinPosition: 0.0f,
                expectedZoomFactor: c_smallZoomFactor);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Bottom,
                expectedHorizontalOffset: (float)(c_defaultUIScrollerWidth - c_imageWidth * c_smallZoomFactor) / 2.0f, // 87.5
                expectedMinPosition: (float)(-c_defaultUIScrollerHeight * c_smallZoomFactor),                          // -100
                expectedZoomFactor: c_smallZoomFactor);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Center,
                expectedHorizontalOffset: (float)(c_defaultUIScrollerWidth - c_imageWidth * c_smallZoomFactor) / 2.0f, // 87.5
                expectedMinPosition: (float)(-c_defaultUIScrollerHeight * c_smallZoomFactor / 2.0),                    // -50
                expectedZoomFactor: c_smallZoomFactor);

            // Jump to absolute large zoomFactor to make the content larger than the viewport.
            ChangeZoomFactor(scroller, c_largeZoomFactor, 0.0f, 0.0f, ScrollerViewKind.Absolute, ScrollerViewChangeKind.DisableAnimation);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Stretch,
                expectedHorizontalOffset: 0.0f,
                expectedMinPosition: 0.0f,
                expectedZoomFactor: c_largeZoomFactor);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Top,
                expectedHorizontalOffset: 0.0f,
                expectedMinPosition: 0.0f,
                expectedZoomFactor: c_largeZoomFactor);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Bottom,
                expectedHorizontalOffset: 0.0f,
                expectedMinPosition: 0.0f,
                expectedZoomFactor: c_largeZoomFactor);

            ValidateContentWithConstrainedHeight(
                compositor,
                scroller,
                content: imageScrollerContent,
                verticalAlignment: VerticalAlignment.Center,
                expectedHorizontalOffset: 0.0f,
                expectedMinPosition: 0.0f,
                expectedZoomFactor: c_largeZoomFactor);
        }
        public void VerifyVSMStatesForPhotosAndInitials()
        {
            PersonPicture personPicture     = null;
            TextBlock     initialsTextBlock = null;

            RunOnUIThread.Execute(() =>
            {
                personPicture = new PersonPicture();
                MUXControlsTestApp.App.TestContentRoot = personPicture;
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                initialsTextBlock     = (TextBlock)VisualTreeUtils.FindVisualChildByName(personPicture, "InitialsTextBlock");
                personPicture.IsGroup = true;
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(initialsTextBlock.FontFamily.Source, "Segoe MDL2 Assets");
                Verify.AreEqual(initialsTextBlock.Text, "\xE716");

                personPicture.IsGroup  = false;
                personPicture.Initials = "JS";
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(initialsTextBlock.FontFamily.Source, "Segoe UI");
                Verify.AreEqual(initialsTextBlock.Text, "JS");

                personPicture.Initials = "";
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(initialsTextBlock.FontFamily.Source, "Segoe MDL2 Assets");
                Verify.AreEqual(initialsTextBlock.Text, "\xE77B");

                // Make sure that custom FontFamily takes effect after the control is created
                // and also goes back to the MDL2 font after setting IsGroup = true.
                personPicture.FontFamily = new FontFamily("Segoe UI Emoji");
                personPicture.Initials   = "👍";
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(initialsTextBlock.FontFamily.Source, "Segoe UI Emoji");
                Verify.AreEqual(initialsTextBlock.Text, "👍");

                personPicture.IsGroup = true;
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(initialsTextBlock.FontFamily.Source, "Segoe MDL2 Assets");
                Verify.AreEqual(initialsTextBlock.Text, "\xE716");
            });
        }
        public void VerifySingleSelection()
        {
            string             navItemPresenter1CurrentState = string.Empty;
            string             navItemPresenter2CurrentState = string.Empty;
            NavigationView     navView   = null;
            NavigationViewItem menuItem1 = null;
            NavigationViewItem menuItem2 = null;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                Verify.IsTrue(menuItem2.IsSelected);
                Verify.IsFalse(menuItem1.IsSelected, "MenuItem1 should have been deselected when MenuItem2 was selected");
                Verify.AreEqual(menuItem2, navView.SelectedItem);
            });
        }
        public void ColorPickerTest()
        {
            RunOnUIThread.Execute(() =>
            {
                ColorPicker colorPicker = new ColorPicker();
                Verify.IsNotNull(colorPicker);

                Verify.AreEqual(Colors.White, colorPicker.Color);
                Verify.IsNull(colorPicker.PreviousColor);
                Verify.IsFalse(colorPicker.IsAlphaEnabled);
                Verify.IsTrue(colorPicker.IsColorSpectrumVisible);
                Verify.IsTrue(colorPicker.IsColorPreviewVisible);
                Verify.IsTrue(colorPicker.IsColorSliderVisible);
                Verify.IsTrue(colorPicker.IsAlphaSliderVisible);
                Verify.IsFalse(colorPicker.IsMoreButtonVisible);
                Verify.IsTrue(colorPicker.IsColorChannelTextInputVisible);
                Verify.IsTrue(colorPicker.IsAlphaTextInputVisible);
                Verify.IsTrue(colorPicker.IsHexInputVisible);
                Verify.AreEqual(0, colorPicker.MinHue);
                Verify.AreEqual(359, colorPicker.MaxHue);
                Verify.AreEqual(0, colorPicker.MinSaturation);
                Verify.AreEqual(100, colorPicker.MaxSaturation);
                Verify.AreEqual(0, colorPicker.MinValue);
                Verify.AreEqual(100, colorPicker.MaxValue);
                Verify.AreEqual(ColorSpectrumShape.Box, colorPicker.ColorSpectrumShape);
                Verify.AreEqual(ColorSpectrumComponents.HueSaturation, colorPicker.ColorSpectrumComponents);

                // Clamping the min and max properties changes the color value,
                // so let's test this new value before we change those.
                colorPicker.Color = Colors.Green;
                Verify.AreEqual(Colors.Green, colorPicker.Color);

                colorPicker.PreviousColor                  = Colors.Red;
                colorPicker.IsAlphaEnabled                 = true;
                colorPicker.IsColorSpectrumVisible         = false;
                colorPicker.IsColorPreviewVisible          = false;
                colorPicker.IsColorSliderVisible           = false;
                colorPicker.IsAlphaSliderVisible           = false;
                colorPicker.IsMoreButtonVisible            = true;
                colorPicker.IsColorChannelTextInputVisible = false;
                colorPicker.IsAlphaTextInputVisible        = false;
                colorPicker.IsHexInputVisible              = false;
                colorPicker.MinHue                  = 10;
                colorPicker.MaxHue                  = 300;
                colorPicker.MinSaturation           = 10;
                colorPicker.MaxSaturation           = 90;
                colorPicker.MinValue                = 10;
                colorPicker.MaxValue                = 90;
                colorPicker.ColorSpectrumShape      = ColorSpectrumShape.Ring;
                colorPicker.ColorSpectrumComponents = ColorSpectrumComponents.HueValue;

                Verify.AreNotEqual(Colors.Green, colorPicker.Color);
                Verify.AreEqual(Colors.Red, colorPicker.PreviousColor);
                Verify.IsTrue(colorPicker.IsAlphaEnabled);
                Verify.IsFalse(colorPicker.IsColorSpectrumVisible);
                Verify.IsFalse(colorPicker.IsColorPreviewVisible);
                Verify.IsFalse(colorPicker.IsColorSliderVisible);
                Verify.IsFalse(colorPicker.IsAlphaSliderVisible);
                Verify.IsTrue(colorPicker.IsMoreButtonVisible);
                Verify.IsFalse(colorPicker.IsColorChannelTextInputVisible);
                Verify.IsFalse(colorPicker.IsAlphaTextInputVisible);
                Verify.IsFalse(colorPicker.IsHexInputVisible);
                Verify.AreEqual(10, colorPicker.MinHue);
                Verify.AreEqual(300, colorPicker.MaxHue);
                Verify.AreEqual(10, colorPicker.MinSaturation);
                Verify.AreEqual(90, colorPicker.MaxSaturation);
                Verify.AreEqual(10, colorPicker.MinValue);
                Verify.AreEqual(90, colorPicker.MaxValue);
                Verify.AreEqual(ColorSpectrumShape.Ring, colorPicker.ColorSpectrumShape);
                Verify.AreEqual(ColorSpectrumComponents.HueValue, colorPicker.ColorSpectrumComponents);
            });
        }
        public void ValidateDataTemplateSelectorAsItemTemplate()
        {
            RunOnUIThread.Execute(() =>
            {
                var dataTemplateOdd = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                            <TextBlock Text='{Binding}' Height='30' />
                        </DataTemplate>");
                var dataTemplateEven = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                            <TextBlock Text='{Binding}' Height='40' />
                        </DataTemplate>");
                ItemsRepeater repeater = null;
                const int numItems     = 10;
                var selector           = new MySelector()
                {
                    TemplateOdd  = dataTemplateOdd,
                    TemplateEven = dataTemplateEven
                };

                Content = CreateAndInitializeRepeater
                          (
                    itemsSource: Enumerable.Range(0, numItems),
                    elementFactory: selector,
                    layout: new StackLayout(),
                    repeater: ref repeater
                          );

                Content.UpdateLayout();
                Verify.AreEqual(numItems, VisualTreeHelper.GetChildrenCount(repeater));
                for (int i = 0; i < numItems; i++)
                {
                    var element = (TextBlock)repeater.TryGetElement(i);
                    Verify.AreEqual(i.ToString(), element.Text);
                    Verify.AreEqual(i % 2 == 0 ? 40 : 30, element.Height);
                }

                repeater.ItemsSource = null;
                Content.UpdateLayout();

                // In versions below RS5 we faked the recycling behaivor on data template
                // so we can get to the recycle pool that we addded internally in ItemsRepeater.
                if (PlatformConfiguration.IsOSVersionLessThan(OSVersion.Redstone5))
                {
                    // All the created items should be in the recycle pool now.
                    var oddPool     = RecyclePool.GetPoolInstance(dataTemplateOdd);
                    var oddElements = GetAllElementsFromPool(oddPool);
                    Verify.AreEqual(5, oddElements.Count);
                    foreach (var element in oddElements)
                    {
                        Verify.AreEqual(30, ((TextBlock)element).Height);
                    }

                    var evenPool     = RecyclePool.GetPoolInstance(dataTemplateEven);
                    var evenElements = GetAllElementsFromPool(evenPool);
                    Verify.AreEqual(5, evenElements.Count);
                    foreach (var element in evenElements)
                    {
                        Verify.AreEqual(40, ((TextBlock)element).Height);
                    }
                }
            });
        }
        public void CanPinFocusedElements()
        {
            // Setup a grouped repeater scenario with two groups each containing two items.
            var data = new ObservableCollection <ObservableCollection <string> >(Enumerable
                                                                                 .Range(0, 2)
                                                                                 .Select(i => new ObservableCollection <string>(Enumerable
                                                                                                                                .Range(0, 2)
                                                                                                                                .Select(j => string.Format("Item #{0}.{1}", i, j)))));

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    Verify.AreEqual(-1, innerRepeaters[1].GetElementIndex(itemElements[1][1]));
                }
            });
        }
        public void ExpanderAutomationPeerTest()
        {
            RunOnUIThread.Execute(() =>
            {
                var root = (StackPanel)XamlReader.Load(
                    @"<StackPanel xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' 
                             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
                             xmlns:primitives='using:Microsoft.UI.Xaml.Controls.Primitives'
                             xmlns:controls='using:Microsoft.UI.Xaml.Controls'> 
                             <controls:Expander x:Name ='ExpandedExpander' AutomationProperties.Name='ExpandedExpander' IsExpanded='True' Margin='12' HorizontalAlignment='Left'>
                                <controls:Expander.Header>
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition />
                                            <ColumnDefinition Width='80'/>
                                        </Grid.ColumnDefinitions>
                                        <StackPanel Margin='0,14,0,16'>
                                            <TextBlock AutomationProperties.Name='test' Text='This expander is expanded by default.'  Margin='0,0,0,4' />
                                            <TextBlock Text='This is the second line of text.' />
                                        </StackPanel>
                                        <ToggleSwitch Grid.Column='1'/>
                                    </Grid>
                                </controls:Expander.Header>
                                <Button AutomationProperties.AutomationId = 'ExpandedExpanderContent'> Content </Button>
                             </controls:Expander>
                                    </StackPanel>");

                Content = root;
                Content.UpdateLayout();

                var expander = VisualTreeHelper.GetChild(root, 0) as Expander;

                expander.IsExpanded = true;
                Content.UpdateLayout();

                var grid             = VisualTreeHelper.GetChild(expander, 0);
                var toggleButton     = VisualTreeHelper.GetChild(grid, 0);
                var toggleButtonGrid = VisualTreeHelper.GetChild(toggleButton, 0);
                var contentPresenter = VisualTreeHelper.GetChild(toggleButtonGrid, 0);
                var grid2            = VisualTreeHelper.GetChild(contentPresenter, 0);
                var stackPanel       = VisualTreeHelper.GetChild(grid2, 0);
                var textBlock1       = VisualTreeHelper.GetChild(stackPanel, 0) as TextBlock;
                var textBlock2       = VisualTreeHelper.GetChild(stackPanel, 1) as TextBlock;
                var toggleSwitch     = VisualTreeHelper.GetChild(grid2, 1) as ToggleSwitch;

                var border = VisualTreeHelper.GetChild(grid, 1);
                var expanderContentBorder           = VisualTreeHelper.GetChild(border, 0);
                var expanderContentContentPresenter = VisualTreeHelper.GetChild(expanderContentBorder, 0);
                var button = VisualTreeHelper.GetChild(expanderContentContentPresenter, 0) as Button;

                Verify.AreEqual("ExpandedExpander", AutomationProperties.GetName(expander));

                // Verify ExpandedExpander header content are included in the accessibility tree
                Verify.AreEqual(AutomationProperties.GetAccessibilityView(textBlock1), AccessibilityView.Content);
                Verify.AreEqual(AutomationProperties.GetAccessibilityView(textBlock2), AccessibilityView.Content);
                Verify.AreEqual(AutomationProperties.GetAccessibilityView(toggleSwitch), AccessibilityView.Content);

                // Verify ExpandedExpander content is included in the accessibility tree
                Verify.AreEqual(AutomationProperties.GetAccessibilityView(button), AccessibilityView.Content);

                expander.IsExpanded = false;
                Content.UpdateLayout();

                // Verify ExpandedExpander content is not included in the accessibility tree and not readable once collapsed
                Verify.AreNotEqual(AutomationProperties.GetAccessibilityView(button), AccessibilityView.Raw);
            });
        }
        public void ValidateElementIndexChangedEventOnStableReset()
        {
            CustomItemsSource dataSource = null;

            RunOnUIThread.Execute(() => dataSource = new CustomItemsSourceWithUniqueId(Enumerable.Range(0, 10).ToList()));

            var repeater = SetupRepeater(dataSource);

            RunOnUIThread.Execute(() =>
            {
                List <int> preparedIndices = new List <int>();
                List <int> clearedIndices  = new List <int>();
                List <KeyValuePair <int, int> > changedIndices = new List <KeyValuePair <int, int> >();

                repeater.ElementPrepared += (sender, args) =>
                {
                    preparedIndices.Add(args.Index);
                };

                repeater.ElementClearing += (sender, args) =>
                {
                    clearedIndices.Add(sender.GetElementIndex(args.Element));
                };

                repeater.ElementIndexChanged += (sender, args) =>
                {
                    changedIndices.Add(new KeyValuePair <int, int>(args.OldIndex, args.NewIndex));
                };

                Log.Comment("(UniqueId Reset) Insert in realized range: Inserting 1 item at index 1");
                dataSource.Insert(index: 1, count: 1, reset: true, valueStart: 2000);
                repeater.UpdateLayout();

                Verify.AreEqual(1, preparedIndices.Count);
                Verify.AreEqual(1, preparedIndices[0]);
                Verify.AreEqual(1, changedIndices.Count);
                Verify.IsTrue(changedIndices.Contains(new KeyValuePair <int, int>(1, 2)));
                foreach (var ch in changedIndices)
                {
                    Log.Comment("Changed " + ch.Key + " " + ch.Value);
                }
                Verify.AreEqual(1, clearedIndices.Count);
                Verify.AreEqual(2, clearedIndices[0]);

                preparedIndices.Clear();
                clearedIndices.Clear();
                changedIndices.Clear();

                Log.Comment("(UniqueId Reset) Remove in realized range: Removing 1 item at index 0");
                dataSource.Remove(index: 0, count: 1, reset: true);
                repeater.UpdateLayout();
                Verify.AreEqual(1, clearedIndices.Count);
                Verify.AreEqual(0, clearedIndices[0]);
                foreach (var ch in changedIndices)
                {
                    Log.Comment("Changed " + ch.Key + " " + ch.Value);
                }
                Verify.AreEqual(1, preparedIndices.Count);
                Verify.AreEqual(2, preparedIndices[0]);
                Verify.AreEqual(2, changedIndices.Count);
                Verify.IsTrue(changedIndices.Contains(new KeyValuePair <int, int>(1, 0)));
                Verify.IsTrue(changedIndices.Contains(new KeyValuePair <int, int>(2, 1)));
            });
        }
        public void ValidateElementClearingOrderFromFlowLayout()
        {
            ItemsSourceView dataSource = null;

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

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

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

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

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

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

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

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

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

            RunOnUIThread.Execute(() =>
            {
                // Validate order is backwards 14, 13, 12, 11
                for (int i = 0; i < 4; i++)
                {
                    Verify.AreEqual(14 - i, clearedIndices[i]);
                }
            });
        }
        public void ValidateElementEvents()
        {
            CustomItemsSource dataSource = null;

            RunOnUIThread.Execute(() => dataSource = new CustomItemsSource(Enumerable.Range(0, 10).ToList()));

            var repeater = SetupRepeater(dataSource);

            RunOnUIThread.Execute(() =>
            {
                List <int> preparedIndices = new List <int>();
                List <int> clearedIndices  = new List <int>();
                List <KeyValuePair <int, int> > changedIndices = new List <KeyValuePair <int, int> >();

                repeater.ElementPrepared += (sender, args) =>
                {
                    preparedIndices.Add(args.Index);
                };

                repeater.ElementClearing += (sender, args) =>
                {
                    clearedIndices.Add(sender.GetElementIndex(args.Element));
                };

                repeater.ElementIndexChanged += (sender, args) =>
                {
                    changedIndices.Add(new KeyValuePair <int, int>(args.OldIndex, args.NewIndex));
                };

                Log.Comment("Insert in realized range: Inserting 1 item at index 1");
                dataSource.Insert(index: 1, count: 1, reset: false);
                repeater.UpdateLayout();

                Verify.AreEqual(1, preparedIndices.Count);
                Verify.AreEqual(1, preparedIndices[0]);
                Verify.AreEqual(2, changedIndices.Count);
                Verify.IsTrue(changedIndices.Contains(new KeyValuePair <int, int>(1, 2)));
                Verify.IsTrue(changedIndices.Contains(new KeyValuePair <int, int>(2, 3)));
                Verify.AreEqual(1, clearedIndices.Count);
                Verify.AreEqual(3, clearedIndices[0]);

                preparedIndices.Clear();
                clearedIndices.Clear();
                changedIndices.Clear();

                Log.Comment("Remove in realized range: Removing 1 item at index 0");
                dataSource.Remove(index: 0, count: 1, reset: false);
                repeater.UpdateLayout();
                Verify.AreEqual(1, clearedIndices.Count);
                Verify.AreEqual(0, clearedIndices[0]);

                if (PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
                {
                    Verify.AreEqual(0, preparedIndices.Count);
                }
                else
                {
                    Verify.AreEqual(1, preparedIndices.Count);
                    Verify.AreEqual(2, preparedIndices[0]);
                }

                Verify.AreEqual(2, changedIndices.Count);
                Verify.IsTrue(changedIndices.Contains(new KeyValuePair <int, int>(1, 0)));
                Verify.IsTrue(changedIndices.Contains(new KeyValuePair <int, int>(2, 1)));
            });
        }
        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 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 #15
0
        public void CanReplaceSingleItem()
        {
            CustomItemsSource dataSource = null;

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

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

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

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

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

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

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

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

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

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

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

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(4, realized);
            });
        }
Example #16
0
        public void ValidateOneScrollViewerScenario()
        {
            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();
            });
        }
        public void ColorSpectrumTest()
        {
            RunOnUIThread.Execute(() =>
            {
                ColorSpectrum colorSpectrum = new ColorSpectrum();
                Verify.IsNotNull(colorSpectrum);

                Verify.AreEqual(Colors.White, colorSpectrum.Color);
                Verify.AreEqual(new Vector4()
                {
                    X = 0.0f, Y = 0.0f, Z = 1.0f, W = 1.0f
                }, colorSpectrum.HsvColor);
                Verify.AreEqual(0, colorSpectrum.MinHue);
                Verify.AreEqual(359, colorSpectrum.MaxHue);
                Verify.AreEqual(0, colorSpectrum.MinSaturation);
                Verify.AreEqual(100, colorSpectrum.MaxSaturation);
                Verify.AreEqual(0, colorSpectrum.MinValue);
                Verify.AreEqual(100, colorSpectrum.MaxValue);
                Verify.AreEqual(ColorSpectrumShape.Box, colorSpectrum.Shape);
                Verify.AreEqual(ColorSpectrumComponents.HueSaturation, colorSpectrum.Components);

                colorSpectrum.Color         = Colors.Green;
                colorSpectrum.MinHue        = 10;
                colorSpectrum.MaxHue        = 300;
                colorSpectrum.MinSaturation = 10;
                colorSpectrum.MaxSaturation = 90;
                colorSpectrum.MinValue      = 10;
                colorSpectrum.MaxValue      = 90;
                colorSpectrum.Shape         = ColorSpectrumShape.Ring;
                colorSpectrum.Components    = ColorSpectrumComponents.HueValue;

                Verify.AreEqual(Colors.Green, colorSpectrum.Color);

                // We'll probably encounter some level of rounding error here,
                // so we want to check that the HSV color is *close* to what's expected,
                // not exactly equal.
                Verify.IsLessThan(Math.Abs(colorSpectrum.HsvColor.X - 120.0), 0.1);
                Verify.IsLessThan(Math.Abs(colorSpectrum.HsvColor.Y - 1.0), 0.1);
                Verify.IsLessThan(Math.Abs(colorSpectrum.HsvColor.Z - 0.5), 0.1);

                Verify.AreEqual(10, colorSpectrum.MinHue);
                Verify.AreEqual(300, colorSpectrum.MaxHue);
                Verify.AreEqual(10, colorSpectrum.MinSaturation);
                Verify.AreEqual(90, colorSpectrum.MaxSaturation);
                Verify.AreEqual(10, colorSpectrum.MinValue);
                Verify.AreEqual(90, colorSpectrum.MaxValue);
                Verify.AreEqual(ColorSpectrumShape.Ring, colorSpectrum.Shape);
                Verify.AreEqual(ColorSpectrumComponents.HueValue, colorSpectrum.Components);

                colorSpectrum.HsvColor = new Vector4()
                {
                    X = 120.0f, Y = 1.0f, Z = 1.0f, W = 1.0f
                };

                Verify.AreEqual(Color.FromArgb(255, 0, 255, 0), colorSpectrum.Color);
                Verify.AreEqual(new Vector4()
                {
                    X = 120.0f, Y = 1.0f, Z = 1.0f, W = 1.0f
                }, colorSpectrum.HsvColor);
            });
        }
Example #18
0
        public void ValidateTwoScrollViewerScenario()
        {
            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 #19
0
        // Test AlwaysUseFallback property
        void RunAcrylicAlwaysUseFallback()
        {
            // Need to set override flags here manually since we don't want to
            // unset them until worker thread actions are complete
            MaterialHelperTestApi.IgnoreAreEffectsFast     = true;
            MaterialHelperTestApi.SimulateDisabledByPolicy = false;

            SetAcrylicBrush(AcrylicBackgroundSource.Backdrop);

            // Run these tests off-thread as they need to poll for brush status changes that are deferred by transition animations.
            Task.Run(async() =>
            {
                // If we are in fallback mode already due to policy, skip the test
                if (await VerifyAcrylicWithPolling())
                {
                    bool[] results = { false, false, false, false };

                    RunOnUIThread.Execute(() =>
                    {
                        // Set AlwaysUseFallback, verify we are using the expected fallback color
                        _acrylicBrush.AlwaysUseFallback = true;
                    });
                    results[0] = await VerifyFallbackColorWithPolling();

                    RunOnUIThread.Execute(() =>
                    {
                        // Change fallback color while in fallback, veryify fallback brush is updated
                        _acrylicBrush.FallbackColor = Colors.Purple;
                    });
                    results[1] = await VerifyFallbackColorWithPolling();

                    RunOnUIThread.Execute(() =>
                    {
                        // Unset AlwaysUseFallback, verify we are using acrylic again
                        _acrylicBrush.AlwaysUseFallback = false;
                    });
                    results[2] = await VerifyAcrylicWithPolling();

                    RunOnUIThread.Execute(() =>
                    {
                        // Change fallback color while not in fallback, then force fallback and verify color
                        _acrylicBrush.FallbackColor     = Colors.Orange;
                        _acrylicBrush.AlwaysUseFallback = true;
                    });
                    results[3] = await VerifyFallbackColorWithPolling();

                    bool result         = results[0] && results[1] && results[2] && results[3];
                    string resultString = System.String.Format("({0},{1},{2},{3})", results[0], results[1], results[2], results[3]);

                    RunOnUIThread.Execute(() =>
                    {
                        // Unset all override flags to avoid impacting subsequent tests
                        MaterialHelperTestApi.IgnoreAreEffectsFast     = false;
                        MaterialHelperTestApi.SimulateDisabledByPolicy = false;

                        TestResult.Text = "AcrylicAlwaysUseFallback: " + (result ? "Passed" : ("Failed " + resultString));
                    });
                }
                else
                {
                    RunOnUIThread.Execute(() =>
                    {
                        // Unset all override flags to avoid impacting subsequent tests
                        MaterialHelperTestApi.IgnoreAreEffectsFast     = false;
                        MaterialHelperTestApi.SimulateDisabledByPolicy = false;

                        TestResult.Text = "AcrylicAlwaysUseFallback: Skipped";
                    });
                }
            });
        }
Example #20
0
        [TestProperty("Ignore", "True")] // TODO 19581880: Re-enable after investigating and fixing the test failures.
#endif
        public void CanGrowCacheBufferWithScrollViewer()
        {
            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;
                        measureRealizationRects.Add(ctx.RealizationRect);
                        return(new Size(1000, 2000));
                    },

                    ArrangeLayoutFunc = (finalSize, context) =>
                    {
                        var ctx = (VirtualizingLayoutContext)context;
                        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 ValidateRecycling()
        {
            RunOnUIThread.Execute(() =>
            {
                var elementFactory = new RecyclingElementFactory()
                {
                    RecyclePool = new RecyclePool(),
                };
                elementFactory.Templates["even"] = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                        <TextBlock Text='even' />
                    </DataTemplate>");
                elementFactory.Templates["odd"] = (DataTemplate)XamlReader.Load(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                        <TextBlock Text='odd' />
                    </DataTemplate>");

                elementFactory.SelectTemplateKey +=
                    delegate(RecyclingElementFactory sender, SelectTemplateEventArgs args)
                {
                    args.TemplateKey = ((int)args.DataContext % 2 == 0) ? "even" : "odd";
                };

                const int numItems     = 10;
                ItemsRepeater repeater = new ItemsRepeater()
                {
                    ItemsSource  = Enumerable.Range(0, numItems),
                    ItemTemplate = elementFactory,
                };

                var context         = (ElementFactoryGetArgs)RepeaterTestHooks.CreateRepeaterElementFactoryGetArgs();
                context.Parent      = repeater;
                var clearContext    = (ElementFactoryRecycleArgs)RepeaterTestHooks.CreateRepeaterElementFactoryRecycleArgs();
                clearContext.Parent = repeater;

                // Element0 is of type even, a new one should be created
                context.Data = 0;
                var element0 = elementFactory.GetElement(context);
                Verify.IsNotNull(element0);
                Verify.AreEqual("even", (element0 as TextBlock).Text);
                clearContext.Element = element0;
                elementFactory.RecycleElement(clearContext);

                // Element1 is of type odd, a new one should be created
                context.Data = 1;
                var element1 = elementFactory.GetElement(context);
                Verify.IsNotNull(element1);
                Verify.AreNotSame(element0, element1);
                Verify.AreEqual("odd", (element1 as TextBlock).Text);
                clearContext.Element = element1;
                elementFactory.RecycleElement(clearContext);

                // Element0 should be recycled for element2
                context.Data = 2;
                var element2 = elementFactory.GetElement(context);
                Verify.AreEqual("even", (element2 as TextBlock).Text);
                Verify.AreSame(element0, element2);

                // Element1 should be recycled for element3
                context.Data = 3;
                var element3 = elementFactory.GetElement(context);
                Verify.AreEqual("odd", (element3 as TextBlock).Text);
                Verify.AreSame(element1, element3);
            });
        }
Example #22
0
        [TestProperty("Ignore", "True")] // TODO 19581880: Re-enable after investigating and fixing the test failures.
#endif
        public void CanBringIntoViewElements()
        {
            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'
                             ElementFactory='{StaticResource ElementFactory}'
                             Layout='{StaticResource VerticalStackLayout}'
                             HorizontalCacheLength='0'
                             VerticalCacheLength='0' />
                         </ScrollViewer>
                       </Grid>"));

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

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

                repeater.ItemsSource = items;

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

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

                Content = root;

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

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

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

            ValidateRealizedRange(repeater, 99, 106);

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

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

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

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

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

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

            Verify.IsTrue(viewChangeCompletedEvent.WaitOne(DefaultWaitTimeInMS));
            IdleSynchronizer.Wait();
            ValidateRealizedRange(repeater, 19, 26);
        }
        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);
            });
        }
Example #24
0
        public void ValidateBasicScrollViewerScenario()
        {
            var          realizationRects = new List <Rect>();
            ScrollViewer scrollViewer     = null;

            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,
                    HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden,
                    VerticalScrollBarVisibility   = ScrollBarVisibility.Hidden,
                };

                Content = scrollViewer;
                Content.UpdateLayout();

                // 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(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.ChangeView(null, 100.0, 1.0f, disableAnimation: true);
            });
            IdleSynchronizer.Wait();

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

                // 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();

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

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

            RunOnUIThread.Execute(() =>
            {
                Verify.AreEqual(new Rect(150, 50, 100, 150), realizationRects.Last());
                realizationRects.Clear();
            });
        }
        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();
                Application.Current.MainWindow.WindowState = WindowState.Maximized;
            });

            IdleSynchronizer.Wait();
            return(navView);
        }
Example #26
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());
            });
        }
        public void BasicMargin()
        {
            if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone2))
            {
                Log.Comment("Skipping test on RS1.");
                return;
            }

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

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

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

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

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

            // Try to jump beyond maximum offsets
            ChangeOffsets(
                scroller,
                c_defaultUIScrollerContentWidth + 2 * c_Margin - c_defaultUIScrollerWidth + 10.0,
                c_defaultUIScrollerContentHeight + 2 * c_Margin - c_defaultUIScrollerHeight + 10.0,
                ScrollerViewKind.Absolute,
                ScrollerViewChangeKind.DisableAnimation,
                ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints,
                true /*hookViewChanged*/,
                c_defaultUIScrollerContentWidth + 2 * c_Margin - c_defaultUIScrollerWidth,
                c_defaultUIScrollerContentHeight + 2 * c_Margin - c_defaultUIScrollerHeight);

            IdleSynchronizer.Wait();

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

            // Try to jump beyond maximum offsets
            ChangeOffsets(
                scroller,
                c_defaultUIScrollerContentWidth - 2 * c_Margin - c_defaultUIScrollerWidth + 10.0,
                c_defaultUIScrollerContentHeight - 2 * c_Margin - c_defaultUIScrollerHeight + 10.0,
                ScrollerViewKind.Absolute,
                ScrollerViewChangeKind.DisableAnimation,
                ScrollerViewChangeSnapPointRespect.IgnoreSnapPoints,
                false /*hookViewChanged*/,
                c_defaultUIScrollerContentWidth - 2 * c_Margin - c_defaultUIScrollerWidth,
                c_defaultUIScrollerContentHeight - 2 * c_Margin - c_defaultUIScrollerHeight);
        }
Example #28
0
        public void VerifyCustomItemTemplate()
        {
            RadioButtons radioButtons  = null;
            RadioButtons radioButtons2 = null;

            RunOnUIThread.Execute(() =>
            {
                radioButtons             = new RadioButtons();
                radioButtons.ItemsSource = new List <string>()
                {
                    "Option 1", "Option 2"
                };

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

                radioButtons.ItemTemplate = itemTemplate;

                radioButtons2             = new RadioButtons();
                radioButtons2.ItemsSource = new List <string>()
                {
                    "Option 1", "Option 2"
                };

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

                radioButtons2.ItemTemplate = itemTemplate2;

                var stackPanel = new StackPanel();
                stackPanel.Children.Add(radioButtons);
                stackPanel.Children.Add(radioButtons2);

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

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                var radioButton1 = radioButtons.ContainerFromIndex(0) as RadioButton;
                var radioButton2 = radioButtons2.ContainerFromIndex(0) as RadioButton;
                Verify.IsNotNull(radioButton1, "Our custom ItemTemplate should have been wrapped in a RadioButton.");
                Verify.IsNotNull(radioButton2, "Our custom ItemTemplate should have been wrapped in a RadioButton.");

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

                testCondition = radioButton2.Foreground is SolidColorBrush brush2 && brush2.Color == Colors.Blue;
                Verify.IsTrue(testCondition, "The foreground color of the RadioButton should have been [blue].");
            });
        }
Example #29
0
        public async Task 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);

            await RunOnUIThread.ExecuteAsync(() =>
            {
                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();
            });

            await TestServices.WindowHelper.WaitForIdle();

            await RunOnUIThread.ExecuteAsync(() =>
            {
                ValidateTabNavigationOrder(repeater);
            });

            IdleSynchronizer.Wait();

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

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

            await RunOnUIThread.ExecuteAsync(() =>
            {
                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();
            });

            await TestServices.WindowHelper.WaitForIdle();

            await RunOnUIThread.ExecuteAsync(() =>
            {
                ValidateTabNavigationOrder(repeater);
            });
        }
        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);
                });
            }
            // }
        }