Skip to content

Commit 973b10a

Browse files
Merge branch 'main' into fix-segmenteditem-background-issue
2 parents 78520e6 + 19fc4de commit 973b10a

34 files changed

+1210
-495
lines changed

.github/workflows/build.yml

Lines changed: 60 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ on:
1717
merge_group:
1818

1919
env:
20-
DOTNET_VERSION: ${{ '9.0.x' }}
20+
DOTNET_VERSION: '9.0.310' # Only used by jobs that cannot access global.json (no checkout/artifact-only jobs)
2121
ENABLE_DIAGNOSTICS: true
2222
MSBUILD_VERBOSITY: normal
2323
#COREHOST_TRACE: 1
@@ -36,17 +36,17 @@ jobs:
3636

3737
# Steps represent a sequence of tasks that will be executed as part of the job
3838
steps:
39-
- name: Install .NET SDK v${{ env.DOTNET_VERSION }}
40-
uses: actions/setup-dotnet@v4
41-
with:
42-
dotnet-version: ${{ env.DOTNET_VERSION }}
43-
4439
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
4540
- name: Checkout Repository
4641
uses: actions/checkout@v4
4742
with:
4843
submodules: recursive
4944

45+
- name: Install .NET SDK
46+
uses: actions/setup-dotnet@v4
47+
with:
48+
global-json-file: global.json
49+
5050
# Restore Tools from Manifest list in the Repository
5151
- name: Restore dotnet tools
5252
run: dotnet tool restore
@@ -59,6 +59,9 @@ jobs:
5959
needs: [Xaml-Style-Check]
6060
runs-on: windows-2022
6161

62+
env:
63+
PROCDUMP_PATH: ${{ github.workspace }}
64+
6265
# See https://docs.github.com/actions/using-jobs/using-a-matrix-for-your-jobs
6366
strategy:
6467
fail-fast: false # prevent one matrix pipeline from being cancelled if one fails, we want them all to run to completion.
@@ -82,29 +85,27 @@ jobs:
8285
maximum-size: 32GB
8386
disk-root: "C:"
8487

85-
- name: Enable User-Mode Dumps collecting
86-
if: ${{ env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '' }}
87-
shell: powershell
88-
run: |
89-
New-Item '${{ github.workspace }}\CrashDumps' -Type Directory
90-
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -Name 'DumpFolder' -Type ExpandString -Value '${{ github.workspace }}\CrashDumps'
91-
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -Name 'DumpCount' -Type DWord -Value '10'
92-
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -Name 'DumpType' -Type DWord -Value '2'
88+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
89+
- name: Checkout Repository
90+
uses: actions/checkout@v4
91+
with:
92+
submodules: recursive
9393

94-
- name: Install .NET SDK v${{ env.DOTNET_VERSION }}
94+
- name: Install .NET SDK
9595
uses: actions/setup-dotnet@v4
9696
with:
97-
dotnet-version: ${{ env.DOTNET_VERSION }}
97+
global-json-file: global.json
9898

9999
- name: .NET Info (if diagnostics)
100100
if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }}
101101
run: dotnet --info
102102

103-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
104-
- name: Checkout Repository
105-
uses: actions/checkout@v4
106-
with:
107-
submodules: recursive
103+
- name: Install procdump
104+
if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }}
105+
shell: pwsh
106+
run: |
107+
Invoke-WebRequest -Uri https://download.sysinternals.com/files/Procdump.zip -OutFile Procdump.zip
108+
Expand-Archive -Path Procdump.zip -DestinationPath ${{ env.PROCDUMP_PATH }}
108109
109110
# Restore Tools from Manifest list in the Repository
110111
- name: Restore dotnet tools
@@ -157,10 +158,17 @@ jobs:
157158
id: test-generator
158159
run: vstest.console.exe ./tooling/CommunityToolkit.Tooling.SampleGen.Tests/bin/Release/net8.0/CommunityToolkit.Tooling.SampleGen.Tests.dll /logger:"trx;LogFileName=SourceGenerators.trx"
159160

161+
- name: Start Procdump monitoring for first-chance exceptions
162+
if: ${{ (matrix.multitarget == 'uwp' || matrix.multitarget == 'wasdk') && env.ENABLE_DIAGNOSTICS == 'true' }}
163+
shell: pwsh
164+
run: |
165+
$procdumpArgs = @("-accepteula", "-e", "1", "-w", "CommunityToolkit.Tests.${{ matrix.multitarget }}.exe", "-ma", "${{ env.PROCDUMP_PATH }}")
166+
Start-Process -FilePath "${{ env.PROCDUMP_PATH }}/procdump64.exe" -ArgumentList $procdumpArgs -NoNewWindow
167+
160168
- name: Run component tests against ${{ matrix.multitarget }}
161169
if: ${{ matrix.multitarget == 'uwp' || matrix.multitarget == 'wasdk' }}
162170
id: test-platform
163-
run: vstest.console.exe ./tooling/**/CommunityToolkit.Tests.${{ matrix.multitarget }}.build.appxrecipe /Framework:FrameworkUap10 /logger:"trx;LogFileName=${{ matrix.multitarget }}.trx" /Blame
171+
run: vstest.console.exe ./tooling/**/CommunityToolkit.Tests.${{ matrix.multitarget }}.build.appxrecipe /Framework:FrameworkUap10 /logger:"trx;LogFileName=${{ matrix.multitarget }}.trx" /Blame:"CollectDump;DumpType=Full;CollectHangDump;TestTimeout=30m;HangDumpType=Full" /Diag:"${{ github.workspace }}/vstest-diagnostic-log.txt"
164172

165173
- name: Create test reports
166174
run: |
@@ -178,7 +186,7 @@ jobs:
178186
uses: actions/upload-artifact@v4
179187
if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }}
180188
with:
181-
name: ilc-repro
189+
name: ilc-repro-${{ matrix.multitarget }}-winui${{ matrix.winui }}
182190
path: ./*.zip
183191

184192
# https://github.com/dorny/paths-filter#custom-processing-of-changed-files
@@ -187,14 +195,21 @@ jobs:
187195
if: always()
188196
working-directory: ${{ github.workspace }}
189197
run: |
190-
echo "DUMP_FILE=$(Get-ChildItem .\CrashDumps\*.dmp -ErrorAction SilentlyContinue)" >> $env:GITHUB_OUTPUT
198+
echo "DUMP_FILE=$(Get-ChildItem ${{ env.PROCDUMP_PATH }}/**/*.dmp -ErrorAction SilentlyContinue)" >> $env:GITHUB_OUTPUT
191199
192-
- name: Artifact - WER crash dumps
200+
- name: Artifact - Process Dumps
193201
uses: actions/upload-artifact@v4
194202
if: ${{ (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }}
195203
with:
196204
name: CrashDumps-${{ matrix.multitarget }}-winui${{ matrix.winui }}
197-
path: '${{ github.workspace }}/CrashDumps'
205+
path: ${{ env.PROCDUMP_PATH }}/**/*.dmp
206+
207+
- name: Artifact - vstest-diagnostic-log
208+
uses: actions/upload-artifact@v4
209+
if: always()
210+
with:
211+
name: 'vstest-diagnostic-log-${{ matrix.multitarget }}-winui${{ matrix.winui }}.txt'
212+
path: '${{ github.workspace }}/vstest-diagnostic-log.txt'
198213

199214
- name: Analyze Dump
200215
if: ${{ steps.detect-dump.outputs.DUMP_FILE != '' && (env.ENABLE_DIAGNOSTICS == 'true' || env.COREHOST_TRACE != '') && always() }}
@@ -214,21 +229,21 @@ jobs:
214229
VERSION_PROPERTY: ${{ github.ref == 'refs/heads/main' && format('build.{0}', github.run_number) || format('pull-{0}.{1}', github.event.number, github.run_number) }}
215230

216231
steps:
217-
- name: Install .NET SDK v${{ env.DOTNET_VERSION }}
232+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
233+
- name: Checkout Repository
234+
uses: actions/checkout@v4
235+
with:
236+
submodules: recursive
237+
238+
- name: Install .NET SDK
218239
uses: actions/setup-dotnet@v4
219240
with:
220-
dotnet-version: ${{ env.DOTNET_VERSION }}
241+
global-json-file: global.json
221242

222243
- name: .NET Info (if diagnostics)
223244
if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }}
224245
run: dotnet --info
225246

226-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
227-
- name: Checkout Repository
228-
uses: actions/checkout@v4
229-
with:
230-
submodules: recursive
231-
232247
# Semver regex: https://regex101.com/r/Ly7O1x/3/
233248
- name: Format Date/Time of Release Package Version
234249
if: ${{ env.IS_RELEASE == 'true' }}
@@ -325,7 +340,7 @@ jobs:
325340
winui: [2, 3]
326341

327342
steps:
328-
- name: Install .NET SDK v${{ env.DOTNET_VERSION }}
343+
- name: Install .NET SDK
329344
uses: actions/setup-dotnet@v4
330345
with:
331346
dotnet-version: ${{ env.DOTNET_VERSION }}
@@ -390,7 +405,7 @@ jobs:
390405
winui: [2, 3]
391406

392407
steps:
393-
- name: Install .NET SDK v${{ env.DOTNET_VERSION }}
408+
- name: Install .NET SDK
394409
uses: actions/setup-dotnet@v4
395410
with:
396411
dotnet-version: ${{ env.DOTNET_VERSION }}
@@ -413,21 +428,21 @@ jobs:
413428
runs-on: ubuntu-latest
414429

415430
steps:
416-
- name: Install .NET SDK v${{ env.DOTNET_VERSION }}
431+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
432+
- name: Checkout Repository
433+
uses: actions/checkout@v4
434+
with:
435+
submodules: recursive
436+
437+
- name: Install .NET SDK
417438
uses: actions/setup-dotnet@v4
418439
with:
419-
dotnet-version: ${{ env.DOTNET_VERSION }}
440+
global-json-file: global.json
420441

421442
- name: .NET Info (if diagnostics)
422443
if: ${{ env.ENABLE_DIAGNOSTICS == 'true' }}
423444
run: dotnet --info
424445

425-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
426-
- name: Checkout Repository
427-
uses: actions/checkout@v4
428-
with:
429-
submodules: recursive
430-
431446
# Restore Tools from Manifest list in the Repository
432447
- name: Restore dotnet tools
433448
run: dotnet tool restore
@@ -459,3 +474,4 @@ jobs:
459474
with:
460475
name: linux-logs
461476
path: ./**/*.*log
477+

components/Collections/samples/AdvancedCollectionViewSample.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ private void Setup()
4848
// right list
4949
AdvancedCollectionView acv = new(EmployeeCollection);
5050
acv.Filter = x => !int.TryParse(((Employee)x).Name, out _);
51-
acv.SortDescriptions.Add(new(nameof(Employee.Name), SortDirection.Ascending));
51+
acv.SortDescriptions.Add(new SortDescription<Employee>(nameof(Employee.Name), SortDirection.Ascending));
5252

5353
CollectionView = acv;
5454
}

components/Collections/src/AdvancedCollectionView/AdvancedCollectionView.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ namespace CommunityToolkit.WinUI.Collections;
1313
/// <summary>
1414
/// A collection view implementation that supports filtering, sorting and incremental loading
1515
/// </summary>
16-
#if NET8_0_OR_GREATER
17-
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Item sorting uses reflection to get property types and may not be AOT compatible.")]
18-
#endif
1916
public partial class AdvancedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer<object>
2017
{
2118
private readonly List<object> _view;
@@ -383,7 +380,7 @@ public Predicate<object> Filter
383380
int IComparer<object>.Compare(object x, object y)
384381
#pragma warning restore CA1033 // Interface methods should be callable by child types
385382
{
386-
if (!_sortProperties.Any())
383+
if (_sortProperties.Count == 0)
387384
{
388385
var listType = _source?.GetType();
389386
Type type;
@@ -401,7 +398,7 @@ int IComparer<object>.Compare(object x, object y)
401398
{
402399
if (!string.IsNullOrEmpty(sd.PropertyName))
403400
{
404-
_sortProperties[sd.PropertyName] = type.GetProperty(sd.PropertyName);
401+
_sortProperties[sd.PropertyName] = sd.GetProperty(type);
405402
}
406403
}
407404
}
@@ -419,8 +416,8 @@ int IComparer<object>.Compare(object x, object y)
419416
{
420417
var pi = _sortProperties[sd.PropertyName];
421418

422-
cx = pi.GetValue(x!);
423-
cy = pi.GetValue(y!);
419+
cx = pi.GetValue(x);
420+
cy = pi.GetValue(y);
424421
}
425422

426423
var cmp = sd.Comparer.Compare(cx, cy);

components/Collections/src/AdvancedCollectionView/SortDescription.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Collections;
6+
using System.Diagnostics.CodeAnalysis;
67

78
namespace CommunityToolkit.WinUI.Collections;
89

@@ -14,7 +15,7 @@ public class SortDescription
1415
/// <summary>
1516
/// Gets the name of property to sort on
1617
/// </summary>
17-
public string PropertyName { get; }
18+
public string? PropertyName { get; }
1819

1920
/// <summary>
2021
/// Gets the direction of sort
@@ -33,8 +34,10 @@ public class SortDescription
3334
/// <param name="direction">Direction of sort</param>
3435
/// <param name="comparer">Comparer to use. If null, will use default comparer</param>
3536
public SortDescription(SortDirection direction, IComparer? comparer = null)
36-
: this(null!, direction, comparer!)
3737
{
38+
PropertyName = null;
39+
Direction = direction;
40+
Comparer = comparer ?? ObjectComparer.Instance;
3841
}
3942

4043
/// <summary>
@@ -43,13 +46,23 @@ public SortDescription(SortDirection direction, IComparer? comparer = null)
4346
/// <param name="propertyName">Name of property to sort on</param>
4447
/// <param name="direction">Direction of sort</param>
4548
/// <param name="comparer">Comparer to use. If null, will use default comparer</param>
49+
#if NET8_0_OR_GREATER
50+
[RequiresUnreferencedCode("Item sorting with the property name uses reflection to get the property and is not trim-safe. Either use SortDescription<T> to preserve the required metadata, or use the other constructor without a property name.")]
51+
#endif
4652
public SortDescription(string propertyName, SortDirection direction, IComparer? comparer = null)
4753
{
4854
PropertyName = propertyName;
4955
Direction = direction;
5056
Comparer = comparer ?? ObjectComparer.Instance;
5157
}
5258

59+
#if NET8_0_OR_GREATER
60+
[UnconditionalSuppressMessage("Trimming", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.",
61+
Justification = "The path which does reflection is only triggered if the user uses the constructor with RequiresUnreferencedCode, which will inform them of the risk.")]
62+
#endif
63+
internal virtual PropertyInfo? GetProperty(Type type)
64+
=> PropertyName != null ? type.GetProperty(PropertyName) : null;
65+
5366
private class ObjectComparer : IComparer
5467
{
5568
public static readonly IComparer Instance = new ObjectComparer();
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections;
6+
using System.Diagnostics.CodeAnalysis;
7+
8+
namespace CommunityToolkit.WinUI.Collections;
9+
10+
/// <summary>
11+
/// A generic version of <see cref="SortDescription"/> which preserves the required metadata for reflection-based sorting.
12+
/// </summary>
13+
/// <typeparam name="T">The type to sort</typeparam>
14+
public sealed class SortDescription<
15+
#if NET8_0_OR_GREATER
16+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
17+
#endif
18+
T> : SortDescription
19+
{
20+
private readonly PropertyInfo _prop;
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="SortDescription{T}"/> class.
24+
/// </summary>
25+
/// <param name="propertyName">Name of property to sort on</param>
26+
/// <param name="direction">Direction of sort</param>
27+
/// <param name="comparer">Comparer to use. If null, will use default comparer</param>
28+
#if NET8_0_OR_GREATER
29+
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
30+
Justification = "This class preserves metadata and ensures at runtime that the received type is compatible.")]
31+
#endif
32+
public SortDescription(string propertyName, SortDirection direction, IComparer? comparer = null) : base(propertyName, direction, comparer)
33+
{
34+
_prop = typeof(T).GetProperty(propertyName) ?? throw new ArgumentException($"Could not find property {propertyName}");
35+
}
36+
37+
internal override PropertyInfo? GetProperty(Type type) =>
38+
(_prop.DeclaringType is not null && _prop.DeclaringType.IsAssignableFrom(type)) ? _prop : throw new ArgumentException("This instance of SortDescription is not compatible with the desired type");
39+
}

components/Converters/samples/DoubleToObjectConverterSample.xaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
<Page.Resources>
1212
<converters:DoubleToObjectConverter x:Key="DoubleToObjectConverter"
1313
FalseValue="{ThemeResource SystemFillColorSuccessBrush}"
14-
GreaterThan="7"
15-
LessThan="3"
14+
GreaterThan="3"
15+
LessThan="7"
1616
TrueValue="{ThemeResource SystemFillColorCriticalBrush}" />
1717
</Page.Resources>
1818

0 commit comments

Comments
 (0)