Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
8f2e320
WinUI CV2 implementation using ItemsRepeater
karthikraja-arumugam Dec 23, 2025
be0e5e4
Grouping and Selection fixes
SuthiYuvaraj Jan 2, 2026
1d00e77
Update ItemsViewHandler2.Windows.cs
SuthiYuvaraj Jan 2, 2026
9b83815
Header/Footer Fix
SuthiYuvaraj Jan 5, 2026
a9491ea
WinUI CV2 extension class included
karthikraja-arumugam Jan 5, 2026
3593fca
Grouping and Selection fixes
SuthiYuvaraj Jan 2, 2026
69fff2a
Update ItemsViewHandler2.Windows.cs
SuthiYuvaraj Jan 2, 2026
9a0aa91
Header/Footer Fix
SuthiYuvaraj Jan 5, 2026
8cd66f4
Update ItemsViewHandler2.Windows.cs
SuthiYuvaraj Jan 6, 2026
dddac39
ScrollBar and RemainingThreshold fix
SuthiYuvaraj Jan 6, 2026
6ab7577
Update for ItemsViewExtensions
SuthiYuvaraj Jan 6, 2026
c9d72dd
ItemsLayout and Scrolling Fix
SuthiYuvaraj Jan 7, 2026
a6c0d47
Fix for ItemSizingStatergy and KeepItemsInView
SuthiYuvaraj Jan 8, 2026
06add2c
ScrollBarChanges
SuthiYuvaraj Jan 9, 2026
ab3feea
Update ItemsViewHandler2.Windows.cs
SuthiYuvaraj Jan 19, 2026
76fa1d5
EmptyView Fix
SuthiYuvaraj Jan 19, 2026
7dc9c12
Selection and VisualStates
SuthiYuvaraj Jan 20, 2026
8e178ae
Fix for Itemspacing
SuthiYuvaraj Jan 23, 2026
f3539c7
Null check for crash issues
SuthiYuvaraj Jan 29, 2026
644172c
DataTemplate Selector and CollectionChanged fix
SuthiYuvaraj Feb 2, 2026
c1de96f
Fix changes
SuthiYuvaraj Feb 2, 2026
755d230
ScrollTo Group
SuthiYuvaraj Feb 2, 2026
63daf70
commit for Groups and Orientation
SuthiYuvaraj Feb 4, 2026
c775793
ItemsUpdatingScrollMode
SuthiYuvaraj Feb 4, 2026
2f309e1
Fixed non template grouped scenario
devanathan-vaithiyanathan Feb 6, 2026
6ffd4c4
Fixed h-grid with header
devanathan-vaithiyanathan Feb 6, 2026
fc17ac6
Fix GridLayout with Span(Non template scenario), text are truncated
devanathan-vaithiyanathan Feb 9, 2026
e0dac41
Fix MeasureFirstItem with URL image return wrong size
devanathan-vaithiyanathan Feb 9, 2026
205a660
Fix for CollectionView Selection maintain issue
devanathan-vaithiyanathan Feb 9, 2026
0b642fa
Fix for flickering on horizontal scroll
SuthiYuvaraj Feb 10, 2026
987fa5a
Proper cleanup code changes
SuthiYuvaraj Feb 11, 2026
be82ceb
Fix orientation and KeepScrollOffset
SuthiYuvaraj Feb 11, 2026
29d317b
SnapPoints
SuthiYuvaraj Feb 12, 2026
c23a2e2
fixed 33487
devanathan-vaithiyanathan Feb 16, 2026
2640311
Fixed MeasureFirstItem with Template changes
devanathan-vaithiyanathan Feb 18, 2026
6216ead
Fix for Unloaded CV with ScrollTo Operation
devanathan-vaithiyanathan Feb 20, 2026
744fe75
Update CollectionViewHandler2.Windows.cs
SuthiYuvaraj Feb 24, 2026
77ea32c
commit for review concern
SuthiYuvaraj Feb 24, 2026
3399965
Merge remote-tracking branch 'origin/BugFixes_WinUI_CV2' into CV2-Man…
devanathan-vaithiyanathan Feb 25, 2026
14022d7
Update CollectionViewHandler2.Windows.cs
devanathan-vaithiyanathan Feb 25, 2026
a6e5e72
Fix 32543
devanathan-vaithiyanathan Feb 25, 2026
f8e67fe
Review code changes
SuthiYuvaraj Feb 26, 2026
e282e84
fix-review changes
SuthiYuvaraj Feb 26, 2026
4816fde
review changes addressed
devanathan-vaithiyanathan Feb 26, 2026
6f2745a
alignment added
devanathan-vaithiyanathan Feb 26, 2026
b4b80d3
Merge remote-tracking branch 'origin/BugFixes_WinUI_CV2' into CV2-Man…
devanathan-vaithiyanathan Feb 26, 2026
dab56ec
Alignment issue resolved
devanathan-vaithiyanathan Feb 26, 2026
22f5d1e
conflicts resolved
devanathan-vaithiyanathan Feb 26, 2026
983e3e9
Fix 31899 (Windows)
devanathan-vaithiyanathan Feb 26, 2026
fec4d7c
Fixed inline unwire review concern
devanathan-vaithiyanathan Feb 26, 2026
9ecaebb
Fix 28212
devanathan-vaithiyanathan Feb 27, 2026
28dfefb
Addressed test case failed scenario
devanathan-vaithiyanathan Mar 2, 2026
98ef6d3
Fix UITest failure 27797
devanathan-vaithiyanathan Mar 3, 2026
d176076
Update ObservableItemTemplateCollection2.cs
SuthiYuvaraj Mar 3, 2026
0dee2e8
Merge remote-tracking branch 'origin/BugFixes_WinUI_CV2' into CV2-Man…
devanathan-vaithiyanathan Mar 4, 2026
18601d9
Fix UITest 22320(IEnumerable rendering)
devanathan-vaithiyanathan Mar 4, 2026
3d4c390
Fix UITest failure for 26187
devanathan-vaithiyanathan Mar 5, 2026
169c84f
Fix for LayoutOptions
SuthiYuvaraj Mar 5, 2026
42ad7c9
Fix UITest failure for 31899
devanathan-vaithiyanathan Mar 5, 2026
13ce089
Preselection fix
SuthiYuvaraj Mar 7, 2026
8eca9fe
Fix for PullToRefresh and SnapPoints with scrollviewer
SuthiYuvaraj Mar 8, 2026
ff46997
fix for gridwidth and Margin from open issues
SuthiYuvaraj Mar 8, 2026
d649fc3
Fix for margin and pointerover
SuthiYuvaraj Mar 8, 2026
d7ceb91
Merge branch 'BugFixes_WinUI_CV2' of https://github.com/dotnet/maui i…
SuthiYuvaraj Mar 8, 2026
2753562
EmptyViewVisibility Changes
SuthiYuvaraj Mar 8, 2026
b9d173e
Fix for grouping and scrollviewindex change
SuthiYuvaraj Mar 9, 2026
1a1e815
Fix CV MultipleSelection PreviousText wrong value in event
devanathan-vaithiyanathan Mar 9, 2026
cf645ce
Update MauiItemsView.cs
SuthiYuvaraj Mar 9, 2026
d0a416d
Merge remote-tracking branch 'origin/CV2-ManualTesting-BugFixes' into…
SuthiYuvaraj Mar 10, 2026
31c3b69
fix for scroll and unwanted changes
SuthiYuvaraj Mar 10, 2026
59f880e
EmptyView measure code removal
SuthiYuvaraj Mar 10, 2026
cacb4e1
Fix Grouping Failures
SuthiYuvaraj Mar 11, 2026
ca661b2
CornerRadius
SuthiYuvaraj Mar 12, 2026
cea35a7
Disable selection on groupheader/Footer
SuthiYuvaraj Mar 12, 2026
f9f4c4f
SnapPoints changes
SuthiYuvaraj Mar 16, 2026
f730d5d
BuildProperties added
SuthiYuvaraj Mar 23, 2026
b5ffba8
Merge remote-tracking branch 'origin/net11.0' into BugFixes_WinUI_CV2
SuthiYuvaraj Mar 23, 2026
9f402ae
Cv2 enabled
SuthiYuvaraj Mar 24, 2026
c369e88
Update ItemsView.cs
SuthiYuvaraj Mar 25, 2026
4dda524
Measurefirstitem issue
SuthiYuvaraj Mar 29, 2026
4b1eafd
Update RuntimeFeature.cs
SuthiYuvaraj Apr 2, 2026
2c044c2
Merge branch 'net11.0' into BugFixes_WinUI_CV2
SuthiYuvaraj Apr 8, 2026
eec4aa9
remove the selectionborder for vsm
SuthiYuvaraj Apr 10, 2026
5624070
Merge branch 'net11.0' into BugFixes_WinUI_CV2
SuthiYuvaraj Apr 13, 2026
bf9096c
Update PublicAPI.Unshipped.txt
SuthiYuvaraj Apr 14, 2026
7d0256f
Naming changes
SuthiYuvaraj Apr 20, 2026
351dd40
Review changes
SuthiYuvaraj Apr 21, 2026
506509e
25191 and 28656 MeasureFirstItem related changes added
devanathan-vaithiyanathan Apr 27, 2026
8ccae11
EmptyView viewport
SuthiYuvaraj May 5, 2026
01c27f8
SelectionUI changes
SuthiYuvaraj May 5, 2026
28a324c
Update ItemsViewHandler2.Windows.cs
SuthiYuvaraj May 11, 2026
cb13886
Drag and drop implementation
SuthiYuvaraj May 12, 2026
cbf2e6f
Update MauiItemsView.DragDrop.cs
SuthiYuvaraj May 12, 2026
ffa7d9d
Merge branch 'net11.0' into BugFixes_WinUI_CV2
SuthiYuvaraj May 21, 2026
2a57a59
Fix for review changes
SuthiYuvaraj May 21, 2026
a90b530
GroupableUniformGridLayout performance issue addressed
devanathan-vaithiyanathan May 21, 2026
39f44e9
Fix for animation code changes
SuthiYuvaraj May 29, 2026
7b1ec0a
Fix for review changes on phase2
SuthiYuvaraj Jun 3, 2026
1a41967
Committed the Cv2 build and UI test lane setup
Ahamed-Ali Jun 4, 2026
7d601ec
Folder created
Ahamed-Ali Jun 4, 2026
ed04882
Difference Image added for CV2
SuthiYuvaraj Jun 4, 2026
bfabd07
making CV2 as a default
SuthiYuvaraj Jun 4, 2026
9b8be4d
Changed the separate lane for windowscv1
Ahamed-Ali Jun 4, 2026
3b1b2ea
for windows cv1 folder
Ahamed-Ali Jun 4, 2026
fa5d726
Deleted the cv2 folder
Ahamed-Ali Jun 4, 2026
a5edeaa
Images added for CV1 folder and swapped the Cv2 images on windows
SuthiYuvaraj Jun 4, 2026
5533c71
Update ItemFactory.cs
SuthiYuvaraj Jun 4, 2026
d647819
Commit for image changes and testcases failure
SuthiYuvaraj Jun 5, 2026
8f120fd
Fix for image change
SuthiYuvaraj Jun 5, 2026
a06e9ac
image_diff_dummyCommit
SuthiYuvaraj Jun 8, 2026
ae96893
Fix for 28343
SuthiYuvaraj Jun 9, 2026
45cfe07
Create Issue28343_ProgressSpinnerDisabled.png
SuthiYuvaraj Jun 9, 2026
36bd180
Update ItemsViewHandler2.Windows.cs
SuthiYuvaraj Jun 9, 2026
23594db
Update Issue28343_ProgressSpinnerDisabled.png
SuthiYuvaraj Jun 10, 2026
036d05b
Update GroupedItemTemplateCollection2.cs
SuthiYuvaraj Jun 16, 2026
332324f
Fix for phase3 review
SuthiYuvaraj Jun 17, 2026
8619066
Update ObservableItemTemplateCollection2.cs
SuthiYuvaraj Jun 17, 2026
55b0bd4
Fix for cross pollination review
SuthiYuvaraj Jun 19, 2026
27171d2
Merge remote-tracking branch 'origin/net11.0' into temp-conflict-reso…
SuthiYuvaraj Jun 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions eng/cake/dotnet.cake
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ Task("uitests-apphost")
Information("Building with Material3 enabled");
properties.Add("UseMaterial3", "true");
}

var useWindowsCV1 = Argument("usewindowscv1", false);
if (useWindowsCV1)
{
Information("Building with UseWindowsCollectionView2Handler=false (CV1)");
properties.Add("UseWindowsCollectionView2Handler", "false");
}

if (useNuget)
{
Expand Down
8 changes: 8 additions & 0 deletions eng/devices/windows.cake
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,14 @@ Task("uitest")
SetEnvironmentVariable("WINDOWS_APP_PATH", TEST_APP);
SetEnvironmentVariable("APPIUM_LOG_FILE", $"{BINLOG_DIR}/appium_windows_{name}.log");

// Set TEST_CONFIGURATION_ARGS for handler selection and snapshot folder determination
var TEST_CONFIGURATION_ARGS = Argument("TEST_CONFIGURATION_ARGS", EnvironmentVariable("TEST_CONFIGURATION_ARGS") ?? "");
if (!string.IsNullOrEmpty(TEST_CONFIGURATION_ARGS))
{
Information("TEST_CONFIGURATION_ARGS: {0}", TEST_CONFIGURATION_ARGS);
SetEnvironmentVariable("TEST_CONFIGURATION_ARGS", TEST_CONFIGURATION_ARGS);
}

Information("Run UITests project {0}",PROJECT.FullPath);
RunTestWithLocalDotNet(PROJECT.FullPath, CONFIGURATION, localToolPath, noBuild: true, resultsFileNameWithoutExtension: $"{name}-{CONFIGURATION}-windows");
});
Expand Down
21 changes: 18 additions & 3 deletions eng/pipelines/common/ui-tests-build-sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ parameters:
headless: true
runtimeVariant: 'CoreCLR' #Mono, CoreCLR, NativeAOT
useMaterial3: false # NEW PARAMETER - Enable Material3 build
useWindowsCV1: false # NEW PARAMETER - Enable WindowsCollectionView1Handler testing (default false)

steps:
- ${{ if eq(parameters.platform, 'ios')}}:
Expand Down Expand Up @@ -75,6 +76,12 @@ steps:
Write-Host "Material3 is only supported for Android platform, ignoring useMaterial3 parameter"
}

# Add UseWindowsCV1 build argument if enabled
if (("${{ parameters.useWindowsCV1 }}" -eq "true") -and ("${{ parameters.platform }}" -eq "windows")) {
$buildCommand += " --usewindowscv1=true"
Write-Host "Building with UseWindowsCollectionView2Handler=false (CV1)"
}

Invoke-Expression $buildCommand
displayName: 'Build the samples'

Expand Down Expand Up @@ -107,9 +114,13 @@ steps:
artifact: ui-tests-samples-material3-coreclr

- publish: $(System.DefaultWorkingDirectory)/artifacts/bin
condition: and(eq('${{ parameters.platform }}' , 'windows'), succeeded())
condition: and(eq('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.useWindowsCV1 }}', 'false'), succeeded())
artifact: ui-tests-samples-windows

- publish: $(System.DefaultWorkingDirectory)/artifacts/bin
condition: and(eq('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.useWindowsCV1 }}', 'true'), succeeded())
artifact: ui-tests-samples-windows-cv1

- publish: $(System.DefaultWorkingDirectory)/artifacts/bin
condition: and(ne('${{ parameters.platform }}' , 'windows'), ne('${{ parameters.runtimeVariant }}' , 'NativeAOT'), ne('${{ parameters.runtimeVariant }}' , 'CoreCLR'), eq('${{ parameters.useMaterial3 }}', 'false'), failed())
artifact: ui-tests-samples_failed_$(System.JobAttempt)
Expand All @@ -128,8 +139,12 @@ steps:
artifact: ui-tests-samples-material3_failed_$(System.JobAttempt)

- publish: $(System.DefaultWorkingDirectory)/artifacts/bin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Warning: Duplicate Windows failure-artifact publish collides on the same artifact name

This newly added step (platform=windows + useWindowsCV1=false + failed()) publishes ui-tests-samples-windows_failed_$(System.JobAttempt) — the same artifact name used by the pre-existing generic Windows failure publish just below (L149-151, condition platform=windows + failed()). When a non-CV1 Windows sample build fails, both conditions are true and both steps publish the same artifact name in the same job, which Azure Pipelines rejects ("an artifact with the name … already exists"). The failure-diagnostics path then itself errors and can mask the real build failure.

Fix: make the conditions mutually exclusive — give the new (CV2) step a distinct name (e.g. ui-tests-samples-windows-cv2_failed_$(System.JobAttempt)) or remove the redundant generic block at L149-151.

(found by: gpt-5.5)

condition: and(ne('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.runtimeVariant }}' , 'CoreCLR'), eq('${{ parameters.useMaterial3 }}', 'true'), failed())
artifact: ui-tests-samples-material3-coreclr_failed_$(System.JobAttempt)
condition: and(eq('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.useWindowsCV1 }}', 'false'), failed())
artifact: ui-tests-samples-windows_failed_$(System.JobAttempt)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Config Impact — Duplicate pipeline-artifact name on the default Windows failure path.

This new block publishes ui-tests-samples-windows_failed_$(System.JobAttempt) for useWindowsCV1=false + windows + failed. The pre-existing catch-all just below (lines 149–151, and(platform=windows, failed())) publishes the same artifact name. useWindowsCV1 defaults to false, so on any default Windows build-sample failure both conditions are true and the second publish errors (An artifact with the name … already exists), polluting failure diagnostics on an already-failed job.

Fix: remove the now-redundant catch-all at lines 149–151 — the two specific blocks (142–143 for cv1=false, 146–147 for cv1=true) already cover all Windows failure cases.

Separately (💡, dormant): the old ui-tests-samples-material3-coreclr_failed publish was repurposed into the block above, so a CoreCLR+Material3 build failure now publishes no artifact while its success counterpart (lines 112–114) remains. No live impact today — the only Material3 stage builds with runtimeVariant: Mono, not CoreCLR — but the lane is now asymmetric.

Flagged by: 3/3 reviewers.


- publish: $(System.DefaultWorkingDirectory)/artifacts/bin
condition: and(eq('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.useWindowsCV1 }}', 'true'), failed())
artifact: ui-tests-samples-windows-cv1_failed_$(System.JobAttempt)

- publish: $(System.DefaultWorkingDirectory)/artifacts/bin
condition: and(eq('${{ parameters.platform }}' , 'windows'), failed())
Expand Down
8 changes: 7 additions & 1 deletion eng/pipelines/common/ui-tests-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ parameters:
configuration: "Release"
runtimeVariant: "CoreCLR"
useMaterial3: false # NEW PARAMETER - Enable Material3 build
useWindowsCV1: false # NEW PARAMETER - Enable WindowsCollectionView1Handler test configuration
testFilter: ''
headless: true
testConfigurationArgs: ''
Expand Down Expand Up @@ -43,10 +44,15 @@ steps:
artifact: ui-tests-samples-material3-coreclr

- task: DownloadPipelineArtifact@2
condition: eq('${{ parameters.platform }}' , 'windows')
condition: and(eq('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.useWindowsCV1 }}', 'false'))
inputs:
artifact: ui-tests-samples-windows

- task: DownloadPipelineArtifact@2
condition: and(eq('${{ parameters.platform }}' , 'windows'), eq('${{ parameters.useWindowsCV1 }}', 'true'))
inputs:
artifact: ui-tests-samples-windows-cv1

- ${{ if eq(parameters.platform, 'ios')}}:
- bash: |
chmod +x $(System.DefaultWorkingDirectory)/eng/scripts/clean-bot.sh
Expand Down
54 changes: 54 additions & 0 deletions eng/pipelines/common/ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ stages:
runtimeVariant: "CoreCLR"
skipProvisioning: ${{ parameters.skipProvisioning }}

# Windows CV1 Build Stage - Separate build with UseWindowsCollectionView2Handler=false
- stage: build_ui_tests_windows_cv1
displayName: Build UITests Windows CV1 Sample App
dependsOn: []
jobs:
- job: build_ui_tests_windows_cv1
displayName: Build Sample App (Windows CV1)
workspace:
clean: all
pool: ${{ parameters.windowsBuildPool }}
variables:
APPIUM_HOME: $(System.DefaultWorkingDirectory)/.appium/
steps:
- template: ui-tests-build-sample.yml
parameters:
platform: windows
runtimeVariant: "CoreCLR"
useWindowsCV1: true
skipProvisioning: ${{ parameters.skipProvisioning }}
- stage: android_ui_tests_coreclr
displayName: Android UITests CoreClr
dependsOn: build_ui_tests_coreclr
Expand Down Expand Up @@ -425,6 +444,41 @@ stages:
platform: 'Windows'
artifactName: 'uitest-snapshot-results-windows-$(System.StageName)-$(System.JobName)-$(System.JobAttempt)'

# Windows CV1 UI Tests - Testing CollectionView with UseWindowsCollectionView2Handler=false
- stage: winui_ui_tests_cv1
displayName: WinUI UITests CV1
dependsOn: build_ui_tests_windows_cv1
jobs:
- ${{ each project in parameters.projects }}:
- ${{ if ne(project.winui, '') }}:
- job: CV1_winui_ui_tests_${{ project.name }}
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
workspace:
clean: all
displayName: ${{ coalesce(project.desc, project.name) }} (CV1)
pool: ${{ parameters.windowsPool }}
variables:
APPIUM_HOME: $(System.DefaultWorkingDirectory)\.appium\
steps:
- template: ui-tests-steps.yml
parameters:
platform: windows
version: "10.0.19041.0"
device: windows10
path: ${{ project.winui }}
app: ${{ project.app }}
provisionatorChannel: ${{ parameters.provisionatorChannel }}
runtimeVariant: "CoreCLR"
useWindowsCV1: true
testFilter: "CollectionView"
testConfigurationArgs: "UseWindowsCV1:true"
skipProvisioning: ${{ parameters.skipProvisioning }}

# Collect and publish Windows CV1 snapshot diffs
- template: ui-tests-collect-snapshot-diffs.yml
parameters:
platform: 'Windows CV1'
artifactName: 'uitest-snapshot-results-windows-cv1-$(System.StageName)-$(System.JobName)-$(System.JobAttempt)'
- stage: maccatalyst_ui_tests_coreclr
displayName: MacCatalyst UITests CoreCLR
dependsOn: build_ui_tests_coreclr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@
Condition="'$(UseMaterial3)' != ''"
Value="$(UseMaterial3)"
Trim="true" />
<RuntimeHostConfigurationOption Include="Microsoft.Maui.RuntimeFeature.IsWindowsCollectionView2HandlerEnabled"
Condition="'$(UseWindowsCollectionView2Handler)' != ''"
Value="$(UseWindowsCollectionView2Handler)"
Trim="true" />
</ItemGroup>
</Target>

Expand Down
107 changes: 107 additions & 0 deletions src/Controls/src/Core/Handlers/Items/ItemsViewExtensions.Windows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using System;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Platform;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using WASDKScrollBarVisibility = Microsoft.UI.Xaml.Controls.ScrollBarVisibility;
using WASDKScrollingScrollBarVisibility = Microsoft.UI.Xaml.Controls.ScrollingScrollBarVisibility;

namespace Microsoft.Maui.Controls.Handlers.Items
{
internal static class ItemsViewExtensions
{
internal static FrameworkElement RealizeEmptyViewTemplate(object? bindingContext, DataTemplate? emptyViewTemplate, IMauiContext mauiContext, ref View? mauiEmptyView, BindableObject? container = null)
{
if (emptyViewTemplate is null)
{
return CreateDefaultEmptyViewTextBlock(bindingContext);
}

// Pass the owning ItemsView as the container so DataTemplateSelector
// implementations can inspect it (parity with iOS/Android/Tizen).
var template = emptyViewTemplate.SelectDataTemplate(bindingContext, container);

var view = template.CreateContent() as View;
if (view is not null)
{
view.BindingContext = bindingContext;
}

return RealizeEmptyView(view, mauiContext, ref mauiEmptyView);
}

static TextBlock CreateDefaultEmptyViewTextBlock(object? bindingContext)
{
return new TextBlock
{
HorizontalAlignment = Microsoft.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Microsoft.UI.Xaml.VerticalAlignment.Center,
Text = bindingContext?.ToString() ?? string.Empty
};
}
internal static FrameworkElement RealizeEmptyView(View? view, IMauiContext mauiContext, ref View? mauiEmptyView)
{
mauiEmptyView = view ?? throw new ArgumentNullException(nameof(view));

var handler = view.ToHandler(mauiContext);
var platformView = handler.ContainerView ?? handler.PlatformView;

return platformView as FrameworkElement ?? throw new InvalidOperationException("Unable to convert view to FrameworkElement");
}

internal static FrameworkElement RealizeHeaderFooterTemplate(object? bindingContext, DataTemplate? template, IMauiContext mauiContext, ref View? mauiView, BindableObject? container = null)
{
if (template is null)
{
return new TextBlock
{
Text = bindingContext?.ToString() ?? string.Empty,
Margin = new Microsoft.UI.Xaml.Thickness(0, 5, 0, 5)
};
}

// Pass the owning ItemsView as the container so DataTemplateSelector
// implementations can inspect it (parity with iOS/Android/Tizen).
var dataTemplate = template.SelectDataTemplate(bindingContext, container);
var view = dataTemplate.CreateContent() as View;
if (view is not null)
{
view.BindingContext = bindingContext;
}

return RealizeHeaderFooterView(view, mauiContext, ref mauiView);
}

internal static FrameworkElement RealizeHeaderFooterView(View? view, IMauiContext mauiContext, ref View? mauiView)
{
mauiView = view ?? throw new ArgumentNullException(nameof(view));

var handler = view.ToHandler(mauiContext);
var platformView = handler.ContainerView ?? handler.PlatformView;

return platformView as FrameworkElement ?? throw new InvalidOperationException("Unable to convert view to FrameworkElement");
}

/// <summary>
/// Applies MAUI margin and layout options to a WinUI element that hosts a MAUI View
/// (e.g., CollectionView header/footer placed in a WinUI ContentControl).
/// The cross-platform layout system never applies these because the element
/// is not inside a MAUI layout.
/// </summary>
internal static void ApplyMauiLayoutProperties(View? mauiView, FrameworkElement? platformElement)
{
if (mauiView is null || platformElement is null)
{
return;
}

// Apply MAUI margin as WinUI margin
var margin = mauiView.Margin;
platformElement.Margin = new Microsoft.UI.Xaml.Thickness(margin.Left, margin.Top, margin.Right, margin.Bottom);

// Map HorizontalOptions/VerticalOptions to WinUI alignment
platformElement.UpdateHorizontalOptions(mauiView);
platformElement.UpdateVerticalOptions(mauiView);
}
}
}
22 changes: 2 additions & 20 deletions src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,11 @@ protected virtual void UpdateEmptyView()

if (emptyViewTemplate is DataTemplate template)
{
_emptyView = RealizeEmptyViewTemplate(emptyView, template);
_emptyView = ItemsViewExtensions.RealizeEmptyViewTemplate(emptyView, template, MauiContext, ref _formsEmptyView, Element);
}
else if (emptyView is View view)
{
_emptyView = RealizeEmptyView(view);
_emptyView = ItemsViewExtensions.RealizeEmptyView(view, MauiContext, ref _formsEmptyView);
}
else
{
Expand Down Expand Up @@ -535,24 +535,6 @@ void ScrollViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
HandleScroll(_scrollViewer);
}

FrameworkElement RealizeEmptyViewTemplate(object bindingContext, DataTemplate emptyViewTemplate)
{
var template = emptyViewTemplate.SelectDataTemplate(bindingContext, ItemsView);
var templatedElement = template.CreateContent() as View;
templatedElement.BindingContext = bindingContext;
return RealizeEmptyView(templatedElement);
}

FrameworkElement RealizeEmptyView(View view)
{
_formsEmptyView = view ?? throw new ArgumentNullException(nameof(view));

var handler = view.ToHandler(MauiContext);
var platformView = handler.ContainerView ?? handler.PlatformView;

return platformView as FrameworkElement;
}

internal void HandleScroll(ScrollViewer scrollViewer)
{
var itemsViewScrolledEventArgs = new ItemsViewScrolledEventArgs
Expand Down
Loading
Loading