Esempio n. 1
0
        public void ValidateStackLayoutDisabledVirtualizationWithItemsRepeater()
        {
            RunOnUIThread.Execute(() =>
            {
                var repeater    = new ItemsRepeater();
                var stackLayout = new StackLayout();
                stackLayout.DisableVirtualization = true;
                repeater.Layout       = stackLayout;
                repeater.ItemsSource  = Enumerable.Range(0, 10);
                repeater.ItemTemplate = (DataTemplate)XamlReader.Parse(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                         <Button Content='{Binding}' Height='100' />
                    </DataTemplate>");

                var scrollViewer = new ScrollViewer()
                {
                    Content = repeater
                };
                scrollViewer.Height = 100;
                Content             = scrollViewer;
                Content.UpdateLayout();

                for (int i = 0; i < repeater.ItemsSourceView.Count; i++)
                {
                    var child = repeater.TryGetElement(i) as Button;
                    Verify.IsNotNull(child);
                }
            });
        }
Esempio n. 2
0
        private ItemsRepeaterScrollHost CreateAndInitializeRepeater(
            object itemsSource,
            VirtualizingLayout layout,
            object elementFactory,
            ref ItemsRepeater repeater,
            ref ScrollViewer scrollViewer)
        {
            repeater = new ItemsRepeater()
            {
                ItemsSource           = itemsSource,
                Layout                = layout,
                ItemTemplate          = elementFactory,
                HorizontalCacheLength = 0,
                VerticalCacheLength   = 0,
            };

            scrollViewer = new ScrollViewer()
            {
                Content = repeater
            };

            return(new ItemsRepeaterScrollHost()
            {
                Width = 400,
                Height = 400,
                ScrollViewer = scrollViewer
            });
        }
Esempio n. 3
0
        public void ValidateStackLayoutDoesNotRetainIncorrectMinorWidth()
        {
            RunOnUIThread.Execute(() =>
            {
                var repeater = new ItemsRepeater()
                {
                    ItemsSource = Enumerable.Range(0, 1)
                };

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

                Content.UpdateLayout();

                // Measure with large width.
                repeater.Measure(new Size(600, 100));
                Verify.AreEqual(600, repeater.DesiredSize.Width);
                // Measure with smaller width again before arrange.
                // StackLayout has to pick up the smaller width for its extent.
                repeater.Measure(new Size(300, 100));
                Verify.AreEqual(300, repeater.DesiredSize.Width);

                Content.UpdateLayout();
                Verify.AreEqual(400, repeater.ActualWidth);
            });
        }
        public void CanRemoveItemsStartingBeforeRealizedRange()
        {
            CustomItemsSource dataSource = null;

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

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

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

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

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Remove before realized range: start:(0)beforeView end:(1)beforeView.");
                dataSource.Remove(index: 0, count: 2, reset: false);
                repeater.UpdateLayout();

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

                Log.Comment("Remove before realized range: start:(0)beforeView end:(4)inview.");
                dataSource.Remove(index: 0, count: 5, reset: false);
                repeater.UpdateLayout();

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

                Log.Comment("Insert before realized range: Inserting 10 items at index 0");
                dataSource.Insert(index: 0, count: 10, reset: false);
                repeater.UpdateLayout();
                VerifyRealizedRange(repeater, dataSource);

                Log.Comment("Insert after realized range: Inserting 10 items at index 19");
                dataSource.Insert(index: 19, count: 10, reset: false);
                repeater.UpdateLayout();
                VerifyRealizedRange(repeater, dataSource);

                Log.Comment("Remove before realized range: start:(5)beforeView end:(25)afterView.");
                dataSource.Remove(index: 5, count: 20, reset: false);
                repeater.UpdateLayout();

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.IsLessThanOrEqual(3, realized);
            });
        }
        private int VerifyRealizedRange(ItemsRepeater repeater, CustomItemsSource dataSource)
        {
            int numRealized = 0;

            // trace
            Log.Comment("index:ItemsSourceView:Item");
            for (int i = 0; i < dataSource.Inner.Count; i++)
            {
                var element = repeater.TryGetElement(i);
                if (element != null)
                {
                    var data = ((TextBlock)element).Text;
                    Log.Comment("{0} {1}:[{2}]", i, dataSource.GetAt(i), data);
                    numRealized++;
                }
                else
                {
                    Log.Comment(i + ":[null]");
                }
            }

            // verify
            for (int i = 0; i < dataSource.Inner.Count; i++)
            {
                var element = repeater.TryGetElement(i);
                if (element != null)
                {
                    var data = ((TextBlock)element).Text;
                    Verify.AreEqual(dataSource.GetAt(i).ToString(), data);
                }
            }

            return(numRealized);
        }
Esempio n. 6
0
        public void ValidateDataContextGetsPropagated()
        {
            const string c_element1DataContext = "Element1_DataContext";

            RunOnUIThread.Execute(() =>
            {
                var data = new List <Button>()
                {
                    new Button()
                    {
                        Content     = "Element1_Content",
                        DataContext = c_element1DataContext
                    }
                };

                var elementFactory = new ElementFromElementElementFactory();

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

                Content = repeater;

                Content.UpdateLayout();

                // Verify that DataContext of data has propagated to the container
                var firstElement = repeater.TryGetElement(0) as Button;
                var retrievedDataContextItem1 = firstElement.DataContext as string;
                Verify.IsTrue(data[0] == firstElement.Content);
                Verify.IsTrue(retrievedDataContextItem1 == c_element1DataContext);
            });
        }
Esempio n. 7
0
        public void ValidateNonVirtualLayoutWithItemsRepeater()
        {
            RunOnUIThread.Execute(() =>
            {
                var repeater          = new ItemsRepeater();
                repeater.Layout       = new NonVirtualStackLayout();
                repeater.ItemsSource  = Enumerable.Range(0, 10);
                repeater.ItemTemplate = (DataTemplate)XamlReader.Parse(
                    @"<DataTemplate  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                         <Button Content='{Binding}' Height='100' />
                    </DataTemplate>");

                Content = repeater;
                Content.UpdateLayout();

                double expectedYOffset = 0;
                for (int i = 0; i < repeater.ItemsSourceView.Count; i++)
                {
                    var child = repeater.TryGetElement(i) as Button;
                    Verify.IsNotNull(child);
                    var layoutBounds = LayoutInformation.GetLayoutSlot(child);
                    Verify.AreEqual(expectedYOffset, layoutBounds.Y);
                    Verify.AreEqual(i, child.Content);
                    expectedYOffset += 100;
                }
            });
        }
        private ItemsRepeater SetupRepeater(CustomItemsSource dataSource, ElementFactory elementFactory, ref ScrollViewer scrollViewer, VirtualizingLayout layout)
        {
            var repeater = new ItemsRepeater()
            {
                ItemsSource           = dataSource,
                ItemTemplate          = elementFactory,
                Layout                = layout,
                VerticalCacheLength   = 0,
                HorizontalCacheLength = 0
            };

            scrollViewer = new ScrollViewer
            {
                Content = repeater
            };

            Content = new ItemsRepeaterScrollHost()
            {
                Width        = 200,
                Height       = 200,
                ScrollViewer = scrollViewer
            };

            Content.UpdateLayout();
            if (dataSource.Count > 0)
            {
                int realized = VerifyRealizedRange(repeater, dataSource);
                Verify.IsGreaterThan(realized, 0);
            }

            return(repeater);
        }
Esempio n. 9
0
        public void ValidateDataContextDoesNotGetOverwritten()
        {
            const string c_element1DataContext = "Element1_DataContext";

            RunOnUIThread.Execute(() =>
            {
                var data = new List <Button>()
                {
                    new Button()
                    {
                        Content     = "Element1_Content",
                        DataContext = c_element1DataContext
                    }
                };

                var elementFactory = new DataAsElementElementFactory();

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

                Content = repeater;

                Content.UpdateLayout();

                // Verify that DataContext is still the same
                var firstElement = repeater.TryGetElement(0) as Button;
                var retrievedDataContextItem1 = firstElement.DataContext as string;
                Verify.IsTrue(retrievedDataContextItem1 == c_element1DataContext);
            });
        }
Esempio n. 10
0
        // [TestMethod] Issue 1018
        public void ValidateFocusMoveOnElementClearedWithUniqueIds()
        {
            ItemsRepeater     repeater   = null;
            CustomItemsSource dataSource = null;

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

            repeater = SetupRepeater(dataSource, "<Button Content='{Binding}' Height='10' />");

            // dataSource: 0 1 2 3 4
            // Index 0 deleted, focus should be on the new element which has index 0
            SharedHelpers.RunActionsWithWait(
                new Action[]
            {
                () => { MoveFocusToIndex(repeater, 0); },
                () => { dataSource.Remove(0 /* index */, 1 /* count */, true /* reset*/); },
                () => { ValidateCurrentFocus(repeater, 0 /*expectedIndex */, "1" /* expectedContent */); }
            });

            // dataSource: 1 2 3 4
            // Last element deleted, focus should move to the previous element
            int lastIndex = dataSource.Inner.Count - 1;

            SharedHelpers.RunActionsWithWait(
                new Action[]
            {
                () => { MoveFocusToIndex(repeater, lastIndex); },
                () => { dataSource.Remove(lastIndex /* index */, 1 /* count */, true /* reset*/); },
                () => { ValidateCurrentFocus(repeater, 2 /*expectedIndex */, "3" /* expectedContent */); }
            });

            // dataSource: 1 2 3
            // Reset should keep the focused element as long as the unique id matches.
            SharedHelpers.RunActionsWithWait(
                new Action[]
            {
                () => { MoveFocusToIndex(repeater, 0); },
                () => { dataSource.Reset(); },
                () =>
                {
                    int newIndex = dataSource.Inner.IndexOf(1);
                    ValidateCurrentFocus(repeater, newIndex /*expectedIndex */, "1" /* expectedContent */);
                }
            });

            // dataSource: 1 2 3
            // Remove multiple elements
            SharedHelpers.RunActionsWithWait(
                new Action[]
            {
                () => { MoveFocusToIndex(repeater, 0); },
                () => { dataSource.Remove(0 /* index */, 2 /* count */, true /* reset*/); },
                () => { ValidateCurrentFocus(repeater, 0 /*expectedIndex */, "3" /* expectedContent */); }
            });
        }
Esempio n. 11
0
        private void ValidateCurrentFocus(ItemsRepeater repeater, int expectedIndex, string expectedContent)
        {
            var currentFocus        = Keyboard.FocusedElement as ContentControl;
            var currentFocusedIndex = repeater.GetElementIndex(currentFocus);

            Log.Comment("expectedIndex: " + expectedIndex + " actual : " + currentFocusedIndex);
            Verify.AreEqual(expectedIndex, currentFocusedIndex);
            Log.Comment("expectedContent: " + expectedContent + " actual : " + currentFocus.Content.ToString());
            Verify.AreEqual(expectedContent, currentFocus.Content.ToString());
        }
Esempio n. 12
0
        private ItemsRepeater CreateRepeater(object dataSource, object elementFactory)
        {
            var repeater = new ItemsRepeater
            {
                ItemsSource  = dataSource,
                ItemTemplate = elementFactory
            };

            repeater.Layout = CreateLayout(repeater);
            return(repeater);
        }
Esempio n. 13
0
        private ItemsRepeater CreateRepeater(object dataSource, object elementFactory, VirtualizingLayout layout = null)
        {
            var repeater = new ItemsRepeater
            {
                ItemsSource  = dataSource,
                ItemTemplate = elementFactory,
            };

            repeater.Layout = layout ?? CreateLayout(repeater);
            return(repeater);
        }
        public void CanMoveItem()
        {
            CustomItemsSource dataSource = null;

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

            RunOnUIThread.Execute(() =>
            {
                repeater = SetupRepeater(dataSource, ref scrollViewer);
                scrollViewer.ScrollChanged += (sender, args) =>
                {
                    if (args.HorizontalChange != 0 || args.VerticalChange != 0)
                    {
                        viewChangedEvent.Set();
                    }
                };
                scrollViewer.ChangeView(null, 400, 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("Move before realized range.");
                dataSource.Move(oldIndex: 0, newIndex: 1, count: 2, reset: false);
                repeater.UpdateLayout();

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

                Log.Comment("Move in realized range.");
                dataSource.Move(oldIndex: 3, newIndex: 5, count: 2, reset: false);
                repeater.UpdateLayout();

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

                Log.Comment("Move after realized range");
                dataSource.Move(oldIndex: 7, newIndex: 8, count: 2, reset: false);
                repeater.UpdateLayout();

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(4, realized);
            });
        }
Esempio n. 15
0
        public void ValidateMappingAndAutoRecycling()
        {
            ItemsRepeater repeater     = null;
            ScrollViewer  scrollViewer = null;

            RunOnUIThread.Execute(() =>
            {
                var layout = new MockVirtualizingLayout()
                {
                    MeasureLayoutFunc = (availableSize, context) =>
                    {
                        var element0 = context.GetOrCreateElementAt(index: 0);
                        // lookup - repeater will give back the same element and note that this element will not
                        // be pinned - i.e it will be auto recycled after a measure pass where GetElementAt(0) is not called.
                        var element0lookup = context.GetOrCreateElementAt(index: 0, options: ElementRealizationOptions.None);

                        var element1 = context.GetOrCreateElementAt(index: 1, options: ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);
                        // forcing a new element for index 1 that will be pinned (not auto recycled). This will be
                        // a completely new element. Repeater does not do the mapping/lookup when forceCreate is true.
                        var element1Clone = context.GetOrCreateElementAt(index: 1, options: ElementRealizationOptions.ForceCreate | ElementRealizationOptions.SuppressAutoRecycle);

                        Verify.AreSame(element0, element0lookup);
                        Verify.AreNotSame(element1, element1Clone);

                        element0.Measure(availableSize);
                        element1.Measure(availableSize);
                        element1Clone.Measure(availableSize);
                        return(new Size(100, 100));
                    },
                };

                Content = CreateAndInitializeRepeater(
                    itemsSource: Enumerable.Range(0, 5),
                    layout: layout,
                    elementFactory: GetDataTemplate("<Button>Hello</Button>"),
                    repeater: ref repeater,
                    scrollViewer: ref scrollViewer);

                Content.UpdateLayout();

                Verify.IsNotNull(repeater.TryGetElement(0));
                Verify.IsNotNull(repeater.TryGetElement(1));

                layout.MeasureLayoutFunc = null;

                repeater.InvalidateMeasure();
                Content.UpdateLayout();

                Verify.IsNull(repeater.TryGetElement(0));    // not pinned, should be auto recycled.
                Verify.IsNotNull(repeater.TryGetElement(1)); // pinned, should stay alive
            });
        }
        private void OnRecipeDeleted(object sender, RoutedEventArgs e)
        {
            if (_flatData != null)
            {
                // walk up the tree to find the container and repeater.
                var container = (FrameworkElement)sender;
                while (!(container.Parent is ItemsRepeater))
                {
                    container = (FrameworkElement)container.Parent;
                }

                ItemsRepeater repeater = (ItemsRepeater)container.Parent;
                int           index    = repeater.GetElementIndex(container);
                _flatData.RemoveAt(index);
            }
        }
        public void VerifyElement0OwnershipInUniformGridLayout()
        {
            CustomItemsSource dataSource = null;

            RunOnUIThread.Execute(() => dataSource = new CustomItemsSource(new List <int>()));
            ItemsRepeater repeater         = null;
            int           elementsCleared  = 0;
            int           elementsPrepared = 0;

            RunOnUIThread.Execute(() =>
            {
                repeater = SetupRepeater(dataSource, new UniformGridLayout());
                repeater.ElementPrepared += (sender, args) => { elementsPrepared++; };
                repeater.ElementClearing += (sender, args) => { elementsCleared++; };
            });

            IdleSynchronizer.Wait();

            RunOnUIThread.Execute(() =>
            {
                Log.Comment("Add two item");
                dataSource.Insert(index: 0, count: 1, reset: false);
                dataSource.Insert(index: 1, count: 1, reset: false);
                repeater.UpdateLayout();
                var realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(2, realized);

                Log.Comment("replace the first item");
                dataSource.Replace(index: 0, oldCount: 1, newCount: 1, reset: false);
                repeater.UpdateLayout();
                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(2, realized);

                Log.Comment("Remove two items");
                dataSource.Remove(index: 1, count: 1, reset: false);
                dataSource.Remove(index: 0, count: 1, reset: false);
                repeater.UpdateLayout();
                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(0, realized);

                Verify.AreEqual(elementsPrepared, elementsCleared);
            });
        }
        private void OnRecipeInserted(object sender, RoutedEventArgs e)
        {
            if (_flatData != null)
            {
                // walk up the tree to find the container and repeater.
                var container = (FrameworkElement)sender;
                while (!(container.Parent is ItemsRepeater))
                {
                    container = (FrameworkElement)container.Parent;
                }

                ItemsRepeater repeater = (ItemsRepeater)container.Parent;
                int           index    = repeater.GetElementIndex(container) + 1;
                _flatData.Insert(index, new Recipe()
                {
                    ImageUri    = new Uri("pack://application:,,,/Images/recipe0.png"),
                    Description = "added recipe",
                });
            }
        }
Esempio n. 19
0
        public void CanResetLayoutAfterUniqueIdReset()
        {
            var    data       = new WinRTCollection(Enumerable.Range(0, 2).Select(i => string.Format("Item #{0}", i)));
            object dataSource = null;

            RunOnUIThread.Execute(() => dataSource = MockItemsSource.CreateDataSource(data, supportsUniqueIds: true));
            ItemsRepeater repeater = SetupRepeater(dataSource);

            RunOnUIThread.Execute(() =>
            {
                var range           = new UIElement[] { repeater.TryGetElement(0), repeater.TryGetElement(1) };
                var clearedElements = new List <UIElement>();

                repeater.ElementClearing += (s, e) =>
                {
                    clearedElements.Add(e.Element);
                };

                // The realized elements will be sent to the unique id reset pool.
                // They haven't been cleared yet.
                data.Reset();
                Verify.AreEqual(0, clearedElements.Count);

                // This also cause elements to be sent to the unique id reset pool.
                // We are validating here that we are smart enough not send them there twice.
                // Doing so will cause an exception to be thrown.
                repeater.Layout = null;
                Verify.AreEqual(0, clearedElements.Count);

                repeater.UpdateLayout();

                // Layout runs. The elements in the reset pool are not used.
                // They should be cleared back to the view generator at this point.
                Verify.AreEqual(2, clearedElements.Count);
                Verify.AreEqual(range[0], clearedElements[0]);
                Verify.AreEqual(range[1], clearedElements[1]);
                Verify.IsNull(repeater.TryGetElement(0));
                Verify.IsNull(repeater.TryGetElement(1));
            });
        }
Esempio n. 20
0
        public void CanChangeFocusAfterUniqueIdReset()
        {
            var    data       = new WinRTCollection(Enumerable.Range(0, 2).Select(i => string.Format("Item #{0}", i)));
            object dataSource = null;

            RunOnUIThread.Execute(() => dataSource = MockItemsSource.CreateDataSource(data, supportsUniqueIds: true));
            ItemsRepeater repeater       = SetupRepeater(dataSource);
            Control       focusedElement = null;

            RunOnUIThread.Execute(() =>
            {
                focusedElement = (Control)repeater.TryGetElement(0);
                focusedElement.Focus();
            });

            IdleSynchronizer.Wait();
            RunOnUIThread.Execute(() =>
            {
                data.Reset();
            });

            IdleSynchronizer.Wait();
            RunOnUIThread.Execute(() =>
            {
                // Still focused.
                Verify.AreEqual(focusedElement, Keyboard.FocusedElement);

                // Change focused element.
                focusedElement = (Control)repeater.TryGetElement(1);
                focusedElement.Focus();
            });

            IdleSynchronizer.Wait();
            RunOnUIThread.Execute(() =>
            {
                // Focus is on the new element.
                Verify.AreEqual(focusedElement, Keyboard.FocusedElement);
            });
        }
Esempio n. 21
0
        public void ValidateNoScrollingSurfaceScenario()
        {
            RunOnUIThread.Execute(() =>
            {
                var realizationRects = new List <Rect>();

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

                Content = repeater;
                Content.UpdateLayout();

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

                //if (!PlatformConfiguration.IsOsVersionGreaterThanOrEqual(OSVersion.Redstone5))
                {
                    Verify.AreEqual(new Rect(0, 0, float.MaxValue, float.MaxValue), realizationRects[1]);
                }

                /*else
                 * {
                 *  // Using Effective Viewport
                 *  Verify.AreEqual(0, realizationRects[1].X);
                 *  // 32 pixel title bar and some tolerance for borders
                 *  Verify.IsLessThan(2.0, Math.Abs(realizationRects[1].Y - 32));
                 *  // Width/Height depends on the window size, so just
                 *  // validating something reasonable here to avoid flakiness.
                 *  Verify.IsLessThan(500.0, realizationRects[1].Width);
                 *  Verify.IsLessThan(500.0, realizationRects[1].Height);
                 * }*/

                realizationRects.Clear();
            });
        }
Esempio n. 22
0
        // Why does this test work?
        // When the elements get created from the RecyclingElementFactory, we get already "existing" data templates.
        // However, the reason for the crash in #2384 is that those "empty" data templates actually still had their data context
        // If that data context is not null, that means it did not get cleared when the element was recycled, which is the wrong behavior.
        // To check if the clearing is working correctly, we are checking this inside the ElementFactory's RecycleElement function.
        public void ValidateElementClearingClearsDataContext()
        {
            ItemsRepeater      repeater       = null;
            MockElementFactory elementFactory = null;
            int elementClearingRaisedCount    = 0;

            Log.Comment("Initialize ItemsRepeater");
            RunOnUIThread.Execute(() =>
            {
                elementFactory = new MockElementFactory()
                {
                    GetElementFunc = delegate(int index, UIElement owner) {
                        return(new Button()
                        {
                            Content = index
                        });
                    },

                    ClearElementFunc = delegate(UIElement element, UIElement owner) {
                        elementClearingRaisedCount++;
                        Verify.IsNull((element as FrameworkElement).DataContext);
                    }
                };

                repeater = CreateRepeater(Enumerable.Range(0, 100),
                                          elementFactory);

                repeater.Layout = new StackLayout();

                Content = repeater;
                repeater.UpdateLayout();

                repeater.ItemsSource = null;

                Log.Comment("Verify ItemsRepeater cleared data contexts correctly");
                Verify.IsTrue(elementClearingRaisedCount > 0, "ItemsRepeater should have cleared some elements");
            });
        }
Esempio n. 23
0
        private ItemsRepeater SetupRepeater(object dataSource, VirtualizingLayout layout, string itemContent, out ScrollViewer scrollViewer)
        {
            ItemsRepeater repeater = null;
            ScrollViewer  sv       = null;

            RunOnUIThread.Execute(() =>
            {
                var elementFactory               = new RecyclingElementFactory();
                elementFactory.RecyclePool       = new RecyclePool();
                elementFactory.Templates["Item"] = (DataTemplate)XamlReader.Parse(
                    @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'> " + itemContent + @"</DataTemplate>");

                repeater = new ItemsRepeater()
                {
                    ItemsSource           = dataSource,
                    ItemTemplate          = elementFactory,
                    Layout                = layout,
                    HorizontalCacheLength = 0.0,
                    VerticalCacheLength   = 0.0
                };

                sv = new ScrollViewer
                {
                    Content = repeater
                };

                Content = new ItemsRepeaterScrollHost()
                {
                    Width        = 200,
                    Height       = 200,
                    ScrollViewer = sv
                };
            });

            IdleSynchronizer.Wait();
            scrollViewer = sv;
            return(repeater);
        }
Esempio n. 24
0
        private VirtualizingLayout CreateLayout(ItemsRepeater repeater)
        {
            var layout   = new MockVirtualizingLayout();
            var children = new List <UIElement>();

            layout.MeasureLayoutFunc = (availableSize, context) =>
            {
                repeater.Tag = repeater.Tag ?? context;
                children.Clear();
                var itemCount = context.ItemCount;

                for (int i = 0; i < itemCount; ++i)
                {
                    var element = repeater.TryGetElement(i) ?? context.GetOrCreateElementAt(i);
                    element.Measure(availableSize);
                    children.Add(element);
                }

                return(new Size(10, 10));
            };

            return(layout);
        }
        public void EnsureReplaceOfAnchorDoesNotResetAllContainers()
        {
            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);
                repeater.ElementPrepared += (sender, args) => { elementsPrepared++; };
                repeater.ElementClearing += (sender, args) => { elementsCleared++; };
            });

            IdleSynchronizer.Wait();

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

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

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(3, realized);
            });
        }
Esempio n. 26
0
        private void MoveFocusToIndex(ItemsRepeater repeater, int index)
        {
            var element = repeater.TryGetElement(index) as Control;

            element.Focus();
        }
Esempio n. 27
0
        // [TestMethod] Issue 1018
        public void CanReuseElementsDuringUniqueIdReset()
        {
            var data = new WinRTCollection(Enumerable.Range(0, 2).Select(i => string.Format("Item #{0}", i)));
            List <UIElement>   mapping        = null;
            ItemsRepeater      repeater       = null;
            MockElementFactory elementFactory = null;
            ContentControl     focusedElement = null;

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

                Content = repeater;
                repeater.UpdateLayout();

                focusedElement = (ContentControl)repeater.TryGetElement(1);
                focusedElement.Focus();
            });
            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], Keyboard.FocusedElement);
            });
        }
        public void CanReplaceSingleItem()
        {
            CustomItemsSource dataSource = null;

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

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

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

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

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

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

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

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

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

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

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

                realized = VerifyRealizedRange(repeater, dataSource);
                Verify.AreEqual(4, realized);
            });
        }
Esempio n. 29
0
        // [TestMethod] Issue #1018
        public void CanPinFocusedElements()
        {
            // Setup a grouped repeater scenario with two groups each containing two items.
            var data = new ObservableCollection <ObservableCollection <string> >(Enumerable
                                                                                 .Range(0, 2)
                                                                                 .Select(i => new ObservableCollection <string>(Enumerable
                                                                                                                                .Range(0, 2)
                                                                                                                                .Select(j => string.Format("Item #{0}.{1}", i, j)))));

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

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

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

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

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

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

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

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

            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]));
                }
            });
        }
Esempio n. 30
0
        public void ValidateRecycledElementOwnerAffinity()
        {
            RunOnUIThread.Execute(() =>
            {
                ItemsRepeater repeater1 = null;
                ItemsRepeater repeater2 = null;
                const int numItems      = 10;
                var dataCollection      = new ObservableCollection <int>(Enumerable.Range(0, numItems));
                const string recycleKey = "key";

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

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

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

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

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

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

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

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

                    var element2 = (FrameworkElement)recyclePool.TryGetElement(recycleKey, repeater2);
                    Verify.AreSame(repeater2, element2.Parent);
                }
            });
        }