Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 0 additions & 14 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,20 +200,6 @@ git commit -m "Fix: Description of the change"
- `.github/instructions/android.instructions.md` - Android handler implementation
- `.github/instructions/xaml-unittests.instructions.md` - XAML unit test guidelines

### Opening PRs

All PRs are required to have this at the top of the description:

```
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!
```

Always put that at the top, without the block quotes. Without it, users will NOT be able to try the PR and your work will have been in vain!



## Custom Agents and Skills

Expand Down
15 changes: 2 additions & 13 deletions .github/skills/pr-finalize/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,10 @@ Examples:
## Description Requirements

PR description should:
1. Start with the required NOTE block (so users can test PR artifacts)
2. Include the base sections from `.github/PULL_REQUEST_TEMPLATE.md` ("Description of Change" and "Issues Fixed"). The skill adds additional structured fields (Root cause, Fix, Key insight, etc.) as recommended enhancements for better agent context.
3. Match the actual implementation
1. Include the base sections from `.github/PULL_REQUEST_TEMPLATE.md` ("Description of Change" and "Issues Fixed"). The skill adds additional structured fields (Root cause, Fix, Key insight, etc.) as recommended enhancements for better agent context.
2. Match the actual implementation

```markdown
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!

### Description of Change
[Must match actual implementation]

Expand Down Expand Up @@ -229,11 +223,6 @@ Example: "Before: Safe area applied by default (opt-out). After: Only views impl
Use structured template only when existing description is inadequate:

```markdown
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!

### Root Cause

[Why the bug occurred - be specific about the code path]
Expand Down
4 changes: 0 additions & 4 deletions .github/skills/pr-finalize/references/complete-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ This example shows a PR description optimized for future agent success.

## Description
```markdown
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you!

### Root Cause

In `MauiView.GetAdjustedSafeAreaInsets()` on iOS, views that don't implement `ISafeAreaView` or `ISafeAreaView2` (such as `ContentPresenter`, `Border`) were falling through to return `baseSafeArea`. This applied full device safe area insets to views that never opted into safe area handling, causing double-padding when used inside ControlTemplates.
Expand Down
2 changes: 2 additions & 0 deletions eng/pipelines/common/ui-tests-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ steps:
- task: PublishBuildArtifacts@1
condition: always()
displayName: publish artifacts
inputs:
artifactName: drop-$(System.StageName)-$(System.JobName)-$(System.JobAttempt)

# Enable Notification Center re-enabled only for catalyst
- ${{ if eq(parameters.platform, 'catalyst')}}:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#nullable disable
using System;
using System.Collections;
using System.Collections.Specialized;

Expand All @@ -9,6 +10,11 @@ internal static class TemplatedItemSourceFactory
internal static object Create(IEnumerable itemsSource, DataTemplate itemTemplate, BindableObject container,
double? itemHeight = null, double? itemWidth = null, Thickness? itemSpacing = null, IMauiContext mauiContext = null)
{
if (itemsSource is null)
{
return Array.Empty<object>();
}

switch (itemsSource)
{
case IList observable when itemsSource is INotifyCollectionChanged:
Expand Down
46 changes: 46 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue17864.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<controls:TestContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:controls="clr-namespace:Maui.Controls.Sample.Issues"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue17864">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<Button Clicked="Button_Clicked"
AutomationId="Button"
Text="Disable Grouping"/>

<Button Grid.Row="1"
Clicked="EnableGroupingOnlyButton_Clicked"
AutomationId="EnableGroupingOnlyButton"
Text="Enable Grouping Without Regrouping"/>

<CollectionView Grid.Row="2"
AutomationId="CollectionView"
ItemsSource="{Binding Items}"
IsGrouped="{Binding IsGrouped}">
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<Label Margin="2"
FontSize="Medium"
Text="{Binding ItemText}"
HorizontalOptions="Fill"
TextColor="LightBlue"/>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Margin="15,2"
Text="{Binding ItemText}"
HorizontalOptions="Fill"
TextColor="Gray"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</controls:TestContentPage>
122 changes: 122 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue17864.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 17864, "[Windows] CollectionView throws NRE when value of IsGrouped property is changed to false",
PlatformAffected.UWP)]
public partial class Issue17864 : TestContentPage
{
readonly Issue17864_ItemListViewModel _ItemListViewModel;
protected override void Init() { }

public Issue17864()
{
InitializeComponent();
_ItemListViewModel = new Issue17864_ItemListViewModel();
BindingContext = _ItemListViewModel;
}

private void Button_Clicked(object sender, EventArgs e)
{
_ItemListViewModel.IsGrouped = !_ItemListViewModel.IsGrouped;
}

private void EnableGroupingOnlyButton_Clicked(object sender, EventArgs e)
{
_ItemListViewModel.EnableGroupingWithoutRegrouping();
}
}

class Issue17864_GroupViewModel : ObservableCollection<Issue17864_ItemViewModel>, Issue17864_IItemViewModel
{

public Issue17864_GroupViewModel(int groupIndex)
{
ItemText = $"Group #{groupIndex}";
}

public string ItemText { get; }
}

interface Issue17864_IItemViewModel
{
string ItemText { get; }
}

class Issue17864_ItemListViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

ObservableCollection<Issue17864_IItemViewModel> items = new();

private bool isGrouped = true;


public Issue17864_ItemListViewModel()
{
Populate();
}

private void Populate()
{
items.Clear();
if (isGrouped)
{
int groupIndex = 0;
items.Add(GetGroup(groupIndex++, 2));
items.Add(GetGroup(groupIndex++, 1));
items.Add(GetGroup(groupIndex++, 3));
items.Add(GetGroup(groupIndex++, 2));
}
else
{
int itemIndex = 0;
items.Add(new Issue17864_ItemViewModel(itemIndex++));
items.Add(new Issue17864_ItemViewModel(itemIndex++));
items.Add(new Issue17864_ItemViewModel(itemIndex++));
}
}

private Issue17864_IItemViewModel GetGroup(int groupIndex, int itemCount)
{
var group = new Issue17864_GroupViewModel(groupIndex);
for (int i = 0; i < itemCount; i++)
{
group.Add(new Issue17864_ItemViewModel(i));
}
return group;
}

public ObservableCollection<Issue17864_IItemViewModel> Items => items;

public void EnableGroupingWithoutRegrouping()
{
isGrouped = true;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsGrouped)));
}

public bool IsGrouped
{
get => isGrouped;
set
{
isGrouped = value;
Populate();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsGrouped)));
}
}

}

class Issue17864_ItemViewModel : Issue17864_IItemViewModel
{

public Issue17864_ItemViewModel(int itemIndex)
{
ItemText = $"Item #{itemIndex}";
}

public string ItemText { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue17864 : _IssuesUITest
{
const string CollectionView = "CollectionView";
public Issue17864(TestDevice device) : base(device)
{
}

public override string Issue => "[Windows] CollectionView throws NRE when value of IsGrouped property is changed to false";

[Test]
[Category(UITestCategories.CollectionView)]
public void CollectionViewShouldNotCrashWhenIsGroupedChangesInBothDirections()
{
App.WaitForElement(CollectionView);

// true -> false
App.Tap("Button");
Copy link

Copilot AI Jan 27, 2025

Choose a reason for hiding this comment

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

Ensure that the AutomationId for 'Button' is unique and not reused, or WaitForElement will fail to find the correct element.

Copilot uses AI. Check for mistakes.
App.WaitForElement(CollectionView);

// false -> true while items remain flat
App.Tap("EnableGroupingOnlyButton");
App.WaitForElement(CollectionView);
}
}
}
Loading