Skip to content

Commit

Permalink
Allow ItemsRepeater's layout to take non virtualizing layouts (#222)
Browse files Browse the repository at this point in the history
* fix debug_test configuration

* fix back version

* updates. still need to add the adapter.

* add the adapter to go from virtualizing context to non-virtualizing context.

* adding a test

* cr fixes

* undo changes to solution file
  • Loading branch information
ranjeshj authored Jan 25, 2019
1 parent 2e6920c commit db7b371
Show file tree
Hide file tree
Showing 18 changed files with 338 additions and 41 deletions.
12 changes: 6 additions & 6 deletions dev/Generated/ItemsRepeater.properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ void ItemsRepeaterProperties::EnsureProperties()
s_LayoutProperty =
InitializeDependencyProperty(
L"Layout",
winrt::name_of<winrt::VirtualizingLayout>(),
winrt::name_of<winrt::Layout>(),
winrt::name_of<winrt::ItemsRepeater>(),
false /* isAttached */,
ValueHelper<winrt::VirtualizingLayout>::BoxedDefaultValue(),
ValueHelper<winrt::Layout>::BoxedDefaultValue(),
nullptr);
}
if (!s_VerticalCacheLengthProperty)
Expand Down Expand Up @@ -166,14 +166,14 @@ winrt::IInspectable ItemsRepeaterProperties::ItemTemplate()
return ValueHelper<winrt::IInspectable>::CastOrUnbox(static_cast<ItemsRepeater*>(this)->GetValue(s_ItemTemplateProperty));
}

void ItemsRepeaterProperties::Layout(winrt::VirtualizingLayout const& value)
void ItemsRepeaterProperties::Layout(winrt::Layout const& value)
{
static_cast<ItemsRepeater*>(this)->SetValue(s_LayoutProperty, ValueHelper<winrt::VirtualizingLayout>::BoxValueIfNecessary(value));
static_cast<ItemsRepeater*>(this)->SetValue(s_LayoutProperty, ValueHelper<winrt::Layout>::BoxValueIfNecessary(value));
}

winrt::VirtualizingLayout ItemsRepeaterProperties::Layout()
winrt::Layout ItemsRepeaterProperties::Layout()
{
return ValueHelper<winrt::VirtualizingLayout>::CastOrUnbox(static_cast<ItemsRepeater*>(this)->GetValue(s_LayoutProperty));
return ValueHelper<winrt::Layout>::CastOrUnbox(static_cast<ItemsRepeater*>(this)->GetValue(s_LayoutProperty));
}

void ItemsRepeaterProperties::VerticalCacheLength(double value)
Expand Down
4 changes: 2 additions & 2 deletions dev/Generated/ItemsRepeater.properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class ItemsRepeaterProperties
void ItemTemplate(winrt::IInspectable const& value);
winrt::IInspectable ItemTemplate();

void Layout(winrt::VirtualizingLayout const& value);
winrt::VirtualizingLayout Layout();
void Layout(winrt::Layout const& value);
winrt::Layout Layout();

void VerticalCacheLength(double value);
double VerticalCacheLength();
Expand Down
44 changes: 44 additions & 0 deletions dev/Repeater/APITests/Common/NonVirtualStackLayout.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

#if !BUILD_WINDOWS
using NonVirtualizingLayoutContext = Microsoft.UI.Xaml.Controls.NonVirtualizingLayoutContext;
using NonVirtualizingLayout = Microsoft.UI.Xaml.Controls.NonVirtualizingLayout;
#endif

namespace Windows.UI.Xaml.Tests.MUXControls.ApiTests.RepeaterTests.Common
{
public class NonVirtualStackLayout : NonVirtualizingLayout
{
protected override Size MeasureOverride(NonVirtualizingLayoutContext context, Size availableSize)
{
double extentHeight = 0.0;
double extentWidth = 0.0;
foreach (var element in context.Children)
{
element.Measure(availableSize);
extentHeight += element.DesiredSize.Height;
extentWidth = Math.Max(extentWidth, element.DesiredSize.Width);
}

return new Size(extentWidth, extentHeight);
}

protected override Size ArrangeOverride(NonVirtualizingLayoutContext context, Size finalSize)
{
double offset = 0.0;
foreach (var element in context.Children)
{
element.Arrange(new Rect(0, offset, element.DesiredSize.Width, element.DesiredSize.Height));
offset += element.DesiredSize.Height;
}

return finalSize;
}
}
}
33 changes: 31 additions & 2 deletions dev/Repeater/APITests/LayoutTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void ValidateMappingAndAutoRecycling()
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 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
Expand Down Expand Up @@ -100,6 +100,35 @@ public void ValidateMappingAndAutoRecycling()
});
}

[TestMethod]
public void ValidateNonVirtualLayoutWithItemsRepeater()
{
RunOnUIThread.Execute(() =>
{
var repeater = new ItemsRepeater();
repeater.Layout = new NonVirtualStackLayout();
repeater.ItemsSource = Enumerable.Range(0, 10);
repeater.ItemTemplate = (DataTemplate)XamlReader.Load(
@"<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 ScrollAnchorProvider CreateAndInitializeRepeater(
object itemsSource,
VirtualizingLayout layout,
Expand All @@ -120,7 +149,7 @@ private ScrollAnchorProvider CreateAndInitializeRepeater(
VerticalCacheLength = 0,
};

scrollViewer = new ScrollViewer()
scrollViewer = new ScrollViewer()
{
Content = repeater
};
Expand Down
1 change: 1 addition & 0 deletions dev/Repeater/APITests/Repeater_APITests.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Common\LayoutExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\FlowLayoutDerived.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\NamedGroup.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\NonVirtualStackLayout.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\OrientationBasedMeasures.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\RecyclingViewGeneratorDerived.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\Mocks\MockItemsSource.cs" />
Expand Down
18 changes: 12 additions & 6 deletions dev/Repeater/ItemsRepeater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,12 @@ void ItemsRepeater::ItemTemplate(winrt::IElementFactory const& value)
SetValue(s_itemTemplateProperty, value);
}

winrt::VirtualizingLayout ItemsRepeater::Layout()
winrt::Layout ItemsRepeater::Layout()
{
return m_layout;
}

void ItemsRepeater::Layout(winrt::VirtualizingLayout const& value)
void ItemsRepeater::Layout(winrt::Layout const& value)
{
SetValue(s_layoutProperty, value);
}
Expand Down Expand Up @@ -477,7 +477,7 @@ void ItemsRepeater::OnPropertyChanged(const winrt::DependencyPropertyChangedEven
}
else if (property == s_layoutProperty)
{
OnLayoutChanged(safe_cast<winrt::VirtualizingLayout>(args.OldValue()), safe_cast<winrt::VirtualizingLayout>(args.NewValue()));
OnLayoutChanged(safe_cast<winrt::Layout>(args.OldValue()), safe_cast<winrt::Layout>(args.NewValue()));
}
else if (property == s_animatorProperty)
{
Expand Down Expand Up @@ -596,7 +596,10 @@ void ItemsRepeater::OnDataSourcePropertyChanged(const winrt::ItemsSourceView& ol
-1 /* oldIndex */);
args.Action();

m_layout.OnItemsChangedCore(GetLayoutContext(), newValue, args);
if (auto virtualLayout = m_layout.try_as<winrt::VirtualizingLayout>())
{
virtualLayout.OnItemsChangedCore(GetLayoutContext(), newValue, args);
}

InvalidateMeasure();
}
Expand Down Expand Up @@ -633,7 +636,7 @@ void ItemsRepeater::OnItemTemplateChanged(const winrt::IElementFactory& oldValu
#endif
}

void ItemsRepeater::OnLayoutChanged(const winrt::VirtualizingLayout& oldValue, const winrt::VirtualizingLayout& newValue)
void ItemsRepeater::OnLayoutChanged(const winrt::Layout& oldValue, const winrt::Layout& newValue)
{
if (m_isLayoutInProgress)
{
Expand Down Expand Up @@ -706,7 +709,10 @@ void ItemsRepeater::OnDataSourceChanged(const winrt::IInspectable& sender, const

if (m_layout)
{
m_layout.OnItemsChangedCore(GetLayoutContext(), sender, args);
if (auto virtualLayout = m_layout.as<winrt::VirtualizingLayout>())
{
virtualLayout.OnItemsChangedCore(GetLayoutContext(), sender, args);
}
}
}

Expand Down
8 changes: 4 additions & 4 deletions dev/Repeater/ItemsRepeater.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ class ItemsRepeater :
winrt::IElementFactory ItemTemplate();
void ItemTemplate(winrt::IElementFactory const& value);

winrt::VirtualizingLayout Layout();
void Layout(winrt::VirtualizingLayout const& value);
winrt::Layout Layout();
void Layout(winrt::Layout const& value);

winrt::ElementAnimator Animator();
void Animator(winrt::ElementAnimator const& value);
Expand Down Expand Up @@ -170,7 +170,7 @@ class ItemsRepeater :

void OnDataSourcePropertyChanged(const winrt::ItemsSourceView& oldValue, const winrt::ItemsSourceView& newValue);
void OnItemTemplateChanged(const winrt::IElementFactory& oldValue, const winrt::IElementFactory& newValue);
void OnLayoutChanged(const winrt::VirtualizingLayout& oldValue, const winrt::VirtualizingLayout& newValue);
void OnLayoutChanged(const winrt::Layout& oldValue, const winrt::Layout& newValue);
void OnAnimatorChanged(const winrt::ElementAnimator& oldValue, const winrt::ElementAnimator& newValue);

void OnDataSourceChanged(const winrt::IInspectable& sender, const winrt::NotifyCollectionChangedEventArgs& args);
Expand All @@ -193,7 +193,7 @@ class ItemsRepeater :
winrt::Microsoft::UI::Xaml::Controls::IElementFactoryShim m_itemTemplateWrapper{ nullptr };
#endif

winrt::VirtualizingLayout m_layout{ nullptr };
winrt::Layout m_layout{ nullptr };
winrt::ElementAnimator m_animator{ nullptr };

tracker_ref<winrt::VirtualizingLayoutContext> m_layoutContext{ this };
Expand Down
2 changes: 1 addition & 1 deletion dev/Repeater/ItemsRepeater.idl
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ unsealed runtimeclass ItemsRepeater : Windows.UI.Xaml.FrameworkElement
Object ItemTemplate { get; set; };
#endif

VirtualizingLayout Layout { get; set; };
Layout Layout { get; set; };

[WUXC_VERSION_PREVIEW]
{
Expand Down
27 changes: 22 additions & 5 deletions dev/Repeater/Layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ namespace
throw winrt::hresult_not_implemented();
}
}

winrt::NonVirtualizingLayoutContext GetNonVirtualizingLayoutContext(winrt::LayoutContext const& context)
{
if (auto nonVirtualizingContext = context.try_as<winrt::NonVirtualizingLayoutContext>())
{
return nonVirtualizingContext;
}
else if (auto virtualizingContext = context.try_as<winrt::VirtualizingLayoutContext>())
{
auto adapter = winrt::get_self<VirtualizingLayoutContext>(virtualizingContext)->GetNonVirtualizingContextAdapter();
return adapter;
}
else
{
throw winrt::hresult_not_implemented();
}
}
}


Expand All @@ -51,7 +68,7 @@ void Layout::InitializeForContext(winrt::LayoutContext const& context)
}
else if (auto nonVirtualizingLayout = get_strong().try_as<winrt::INonVirtualizingLayoutOverrides>())
{
auto nonVirtualizingContext = context.try_as<winrt::NonVirtualizingLayoutContext>();
auto nonVirtualizingContext = GetNonVirtualizingLayoutContext(context);
return nonVirtualizingLayout.InitializeForContextCore(nonVirtualizingContext);
}
else
Expand All @@ -70,7 +87,7 @@ void Layout::UninitializeForContext(winrt::LayoutContext const& context)
}
else if (auto nonVirtualizingLayout = spThis.try_as<winrt::INonVirtualizingLayoutOverrides>())
{
auto nonVirtualizingContext = context.try_as<winrt::NonVirtualizingLayoutContext>();
auto nonVirtualizingContext = GetNonVirtualizingLayoutContext(context);
return nonVirtualizingLayout.UninitializeForContextCore(nonVirtualizingContext);
}
else
Expand All @@ -92,7 +109,7 @@ winrt::Size Layout::Measure(
}
else if (auto nonVirtualizingLayout = spThis.try_as<winrt::INonVirtualizingLayoutOverrides>())
{
auto nonVirtualizingContext = context.try_as<winrt::NonVirtualizingLayoutContext>();
auto nonVirtualizingContext = GetNonVirtualizingLayoutContext(context);
return nonVirtualizingLayout.MeasureOverride(nonVirtualizingContext, availableSize);
}
else
Expand All @@ -113,7 +130,7 @@ winrt::Size Layout::Arrange(
}
else if (auto nonVirtualizingLayout = spThis.try_as<winrt::INonVirtualizingLayoutOverrides>())
{
auto nonVirtualizingContext = context.try_as<winrt::NonVirtualizingLayoutContext>();
auto nonVirtualizingContext = GetNonVirtualizingLayoutContext(context);
return nonVirtualizingLayout.ArrangeOverride(nonVirtualizingContext, finalSize);
}
else
Expand Down Expand Up @@ -157,4 +174,4 @@ void Layout::InvalidateArrange()
m_arrangeInvalidatedEventSource(*this, nullptr);
}

#pragma endregion
#pragma endregion
2 changes: 2 additions & 0 deletions dev/Repeater/Repeater.vcxitems
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)VirtualizationInfo.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)VirtualizingLayout.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)VirtualizingLayoutContext.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)VirtualLayoutContextAdapter.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)AnimationManager.cpp" />
Expand Down Expand Up @@ -145,5 +146,6 @@
<ClCompile Include="$(MSBuildThisFileDirectory)VirtualizationInfo.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)VirtualizingLayout.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)VirtualizingLayoutContext.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)VirtualLayoutContextAdapter.cpp" />
</ItemGroup>
</Project>
4 changes: 2 additions & 2 deletions dev/Repeater/RepeaterFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ void ItemsRepeater::EnsureProperties()
s_layoutProperty =
InitializeDependencyProperty(
L"Layout",
winrt::name_of<winrt::VirtualizingLayout>(),
winrt::name_of<winrt::Layout>(),
winrt::name_of<winrt::ItemsRepeater>(),
false /* isAttached */,
winrt::StackLayout() /* defaultValue */,
Expand Down Expand Up @@ -119,4 +119,4 @@ void ItemsRepeater::OnPropertyChanged(
const winrt::DependencyPropertyChangedEventArgs& args)
{
winrt::get_self<ItemsRepeater>(sender.as<winrt::ItemsRepeater>())->OnPropertyChanged(args);
}
}
2 changes: 1 addition & 1 deletion dev/Repeater/TestUI/Repeater_TestUI.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Samples\CircleLayoutDemo\CircleLayoutSamplePage.xaml.cs">
<DependentUpon>CircleLayoutSamplePage.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Samples\StackLayoutSamples\NonVirtual\NonVIrtualStackLayout.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Samples\StackLayoutSamples\NonVirtual\NonVirtualStackLayout.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Samples\CollectionChangeDemo.xaml.cs">
<DependentUpon>CollectionChangeDemo.xaml</DependentUpon>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,11 @@
</Style>
</Grid.Resources>
<ScrollViewer>
<controls:LayoutPanel>
<controls:LayoutPanel.Layout>
<controls:ItemsRepeater x:Name="repeater">
<controls:ItemsRepeater.Layout>
<local:NonVirtualStackLayout />
</controls:LayoutPanel.Layout>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
</controls:LayoutPanel>
</controls:ItemsRepeater.Layout>
</controls:ItemsRepeater>
</ScrollViewer>
</Grid>
</Page>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Specialized;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using System.Linq;

#if !BUILD_WINDOWS
using ItemsSourceView = Microsoft.UI.Xaml.Controls.ItemsSourceView;
Expand All @@ -21,6 +22,7 @@ public sealed partial class NonVirtualStackLayoutSamplePage : Page
public NonVirtualStackLayoutSamplePage()
{
this.InitializeComponent();
repeater.ItemsSource = Enumerable.Range(0, 10);
}
}
}
Loading

0 comments on commit db7b371

Please sign in to comment.