-
Notifications
You must be signed in to change notification settings - Fork 2k
[WinUI][CV2] CollectionView2 Handler Implementation for Windows #34600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8f2e320
be0e5e4
1d00e77
9b83815
a9491ea
3593fca
69fff2a
9a0aa91
8cd66f4
dddac39
6ab7577
c9d72dd
a6c0d47
06add2c
ab3feea
76fa1d5
7dc9c12
8e178ae
f3539c7
644172c
c1de96f
755d230
63daf70
c775793
2f309e1
6ffd4c4
fc17ac6
e0dac41
205a660
0b642fa
987fa5a
be82ceb
29d317b
c23a2e2
2640311
6216ead
744fe75
77ea32c
3399965
14022d7
a6e5e72
f8e67fe
e282e84
4816fde
6f2745a
b4b80d3
dab56ec
22f5d1e
983e3e9
fec4d7c
9ecaebb
28dfefb
98ef6d3
d176076
0dee2e8
18601d9
3d4c390
169c84f
42ad7c9
13ce089
8eca9fe
ff46997
d649fc3
d7ceb91
2753562
b9d173e
1a1e815
cf645ce
d0a416d
31c3b69
59f880e
cacb4e1
ca661b2
cea35a7
f9f4c4f
f730d5d
b5ffba8
9f402ae
c369e88
4dda524
4b1eafd
2c044c2
eec4aa9
5624070
bf9096c
7d0256f
351dd40
506509e
8ccae11
01c27f8
28a324c
cb13886
cbf2e6f
ffa7d9d
2a57a59
a90b530
39f44e9
7b1ec0a
1a41967
7d601ec
ed04882
bfabd07
9b8be4d
3b1b2ea
fa5d726
a5edeaa
5533c71
d647819
8f120fd
a06e9ac
ae96893
45cfe07
36bd180
23594db
036d05b
332324f
8619066
55b0bd4
27171d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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')}}: | ||
|
|
@@ -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' | ||
|
|
||
|
|
@@ -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) | ||
|
|
@@ -128,8 +139,12 @@ steps: | |
| artifact: ui-tests-samples-material3_failed_$(System.JobAttempt) | ||
|
|
||
| - publish: $(System.DefaultWorkingDirectory)/artifacts/bin | ||
| 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) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This new block publishes Fix: remove the now-redundant catch-all at lines 149–151 — the two specific blocks (142–143 for Separately (💡, dormant): the old 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()) | ||
|
|
||
| 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); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This newly added step (
platform=windows+useWindowsCV1=false+failed()) publishesui-tests-samples-windows_failed_$(System.JobAttempt)— the same artifact name used by the pre-existing generic Windows failure publish just below (L149-151, conditionplatform=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)