Merge branch 'main' into merge-main-net9

# Conflicts:
#	eng/Versions.props
#	src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Windows.cs
This commit is contained in:
Rui Marinho 2024-09-17 11:41:31 +01:00
Родитель 270f6619e5 b2c1d25f7a
Коммит 7f1685291f
33 изменённых файлов: 512 добавлений и 20 удалений

4
.github/ISSUE_TEMPLATE/bug-report.yml поставляемый
Просмотреть файл

@ -42,6 +42,7 @@ body:
label: Version with bug
description: In what version do you see this issue? Run `dotnet workload list` to find your version.
options:
- 9.0.0-rc.1.24453.9
- 9.0.0-preview.7.24407.4
- 9.0.0-preview.6.24327.7
- 9.0.0-preview.5.24307.10
@ -49,6 +50,7 @@ body:
- 9.0.0-preview.3.10457
- 9.0.0-preview.2.10293
- 9.0.0-preview.1.9973
- 8.0.90 SR9
- 8.0.82 SR8.2
- 8.0.80 SR8
- 8.0.71 SR7.1
@ -123,12 +125,14 @@ body:
- 8.0.71 SR7.1
- 8.0.80 SR8
- 8.0.82 SR8.2
- 8.0.90 SR9
- 9.0.0-preview.1.9973
- 9.0.0-preview.2.10293
- 9.0.0-preview.3.10457
- 9.0.0-preview.4.10690
- 9.0.0-preview.5.24307.10
- 9.0.0-preview.6.24327.7
- 9.0.0-preview.7.24407.4
validations:
required: true
- type: dropdown

Просмотреть файл

@ -72,14 +72,20 @@ parameters:
- name: iosPool
type: object
default:
name: $(macosTestsVmPool)
vmImage: macOS-14
name: $(iosTestsVmPool)
vmImage: $(iosTestsVmImage)
demands:
- macOS.Name -equals Sonoma
- macOS.Architecture -equals x64
- name: catalystPool
type: object
default:
name: $(macosTestsVmPool)
vmImage: macOS-14
name: $(iosTestsVmPool)
vmImage: $(iosTestsVmImage)
demands:
- macOS.Name -equals Sonoma
- macOS.Architecture -equals x64
- name: windowsPool
type: object

Просмотреть файл

@ -88,7 +88,7 @@ parameters:
- name: macosPool
type: object
default:
name: $(macosTestsVmPool)
name: Azure Pipelines
vmImage: macOS-14
- name: androidCompatibilityPool

Просмотреть файл

@ -132,7 +132,6 @@ namespace Microsoft.Maui.Controls.Handlers.Compatibility
{
var child = GetChildAt(0);
child?.RemoveFromParent();
child?.Dispose();
}
Element?.Handler?.DisconnectHandler();

Просмотреть файл

@ -959,10 +959,8 @@ namespace Microsoft.Maui.Controls.Handlers.Compatibility
{
if (_prototype != null)
{
var element = _prototype.VirtualView;
element?.Handler?.DisconnectHandler();
//_prototype?.Dispose();
//_prototype = null;
_prototype?.DisconnectHandler();
_prototype = null;
}
}
}

Просмотреть файл

@ -345,7 +345,7 @@ namespace Microsoft.Maui.Controls.Platform.Compatibility
UITableViewCell[] GetMoreNavigationCells()
{
if (MoreNavigationController.TopViewController.View is UITableView uITableView)
if (MoreNavigationController.TopViewController.View is UITableView uITableView && uITableView.Window is not null)
return uITableView.VisibleCells;
return EmptyUITableViewCellArray;

Просмотреть файл

@ -38,7 +38,7 @@ namespace Microsoft.Maui.Controls.Handlers.Items
protected override void ConnectHandler(ListViewBase platformView)
{
ItemsView.Scrolled += CarouselScrolled;
ListViewBase.SizeChanged += OnListViewSizeChanged;
platformView.SizeChanged += OnListViewSizeChanged;
UpdateScrollBarVisibilityForLoop();
@ -50,8 +50,11 @@ namespace Microsoft.Maui.Controls.Handlers.Items
if (ItemsView != null)
ItemsView.Scrolled -= CarouselScrolled;
platformView.SizeChanged -= OnListViewSizeChanged;
_proxy.Unsubscribe();
if (platformView != null)
{
platformView.SizeChanged -= OnListViewSizeChanged;
_proxy.Unsubscribe();
}
if (_scrollViewer != null)
{

Просмотреть файл

@ -57,6 +57,7 @@ namespace Microsoft.Maui.Controls.Handlers.Items
protected override void DisconnectHandler(ListViewBase platformView)
{
VirtualView.ScrollToRequested -= ScrollToRequested;
CleanUpCollectionViewSource(platformView);
base.DisconnectHandler(platformView);
}
@ -154,6 +155,11 @@ namespace Microsoft.Maui.Controls.Handlers.Items
protected abstract ListViewBase SelectListViewBase();
protected virtual void CleanUpCollectionViewSource()
{
CleanUpCollectionViewSource(ListViewBase);
}
private void CleanUpCollectionViewSource(ListViewBase platformView)
{
if (CollectionViewSource is not null)
{
@ -174,7 +180,7 @@ namespace Microsoft.Maui.Controls.Handlers.Items
// Remove all children inside the ItemsSource
if (VirtualView is not null)
{
foreach (var item in ListViewBase.GetChildren<ItemContentControl>())
foreach (var item in platformView.GetChildren<ItemContentControl>())
{
var element = item.GetVisualElement();
VirtualView.RemoveLogicalChild(element);
@ -183,7 +189,7 @@ namespace Microsoft.Maui.Controls.Handlers.Items
if (VirtualView?.ItemsSource is null)
{
ListViewBase.ItemsSource = null;
platformView.ItemsSource = null;
return;
}
}

Просмотреть файл

@ -17,6 +17,7 @@ namespace Microsoft.Maui.Controls.Handlers.Items
protected override void DisconnectHandler(UIView platformView)
{
ItemsView.ScrollToRequested -= ScrollToRequested;
Controller?.DisposeItemsSource();
base.DisconnectHandler(platformView);
}

Просмотреть файл

@ -243,7 +243,8 @@ namespace Microsoft.Maui.Controls.Handlers.Items
return false;
}
if (layoutAttributesForRectElements[0].Frame.Top != CollectionView.Frame.Top + CollectionView.ContentInset.Bottom)
// We need to determine whether this 'if' statement is needed, as its relevance is currently uncertain.
if (layoutAttributesForRectElements[0].Frame.Top != CollectionView.Frame.Top)
{
return false;
}

Просмотреть файл

@ -329,6 +329,15 @@ namespace Microsoft.Maui.Controls.Handlers.Items
(ItemsView as IView)?.InvalidateMeasure();
}
internal void DisposeItemsSource()
{
_measurementCells?.Clear();
ItemsViewLayout?.ClearCellSizeCache();
ItemsSource?.Dispose();
ItemsSource = new EmptySource();
CollectionView.ReloadData();
}
public virtual void UpdateFlowDirection()
{
CollectionView.UpdateFlowDirection(ItemsView);

Просмотреть файл

@ -30,7 +30,11 @@ namespace Microsoft.Maui.Controls
public static readonly BindableProperty IsDestructiveProperty = BindableProperty.Create(nameof(IsDestructive), typeof(bool), typeof(MenuItem), false);
/// <summary>Bindable property for <see cref="IconImageSource"/>.</summary>
public static readonly BindableProperty IconImageSourceProperty = BindableProperty.Create(nameof(IconImageSource), typeof(ImageSource), typeof(MenuItem), default(ImageSource));
public static readonly BindableProperty IconImageSourceProperty = BindableProperty.Create(nameof(IconImageSource), typeof(ImageSource), typeof(MenuItem), default(ImageSource),
propertyChanged: (bindable, oldValue, newValue) => {
((MenuItem)bindable).AddRemoveLogicalChildren(oldValue, newValue);
}
);
/// <summary>Bindable property for <see cref="IsEnabled"/>.</summary>
public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(

Просмотреть файл

@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Handlers.Items;
@ -112,6 +113,45 @@ namespace Microsoft.Maui.DeviceTests
Assert.NotNull(handler.PlatformView);
});
}
#if !ANDROID //https://github.com/dotnet/maui/pull/24610
[Fact]
public async void DisconnectedCarouselViewDoesNotHookCollectionViewChanged()
{
SetupBuilder();
CollectionChangedObservableCollection<int> data = new CollectionChangedObservableCollection<int>()
{
1,
2,
};
var template = new DataTemplate(() =>
{
return new Grid()
{
new Label()
};
});
var carouselView = new CarouselView()
{
ItemTemplate = template,
ItemsSource = data
};
await CreateHandlerAndAddToWindow<CarouselViewHandler>(carouselView, async (handler) =>
{
await Task.Delay(100);
Assert.NotNull(handler.PlatformView);
Assert.False(data.IsCollectionChangedEventEmpty);
});
carouselView.Handler?.DisconnectHandler();
Assert.True(data.IsCollectionChangedEventEmpty);
}
#endif
}
internal class CustomDataTemplateSelectorSelector : DataTemplateSelector
@ -129,4 +169,17 @@ namespace Microsoft.Maui.DeviceTests
return Template2;
}
}
}
internal class CollectionChangedObservableCollection<T> : ObservableCollection<T>, INotifyCollectionChanged
{
NotifyCollectionChangedEventHandler collectionChanged;
event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
{
add { collectionChanged += value; base.CollectionChanged += value; }
remove { collectionChanged -= value; base.CollectionChanged -= value; }
}
public bool IsCollectionChangedEventEmpty => collectionChanged is null;
}
}

Просмотреть файл

@ -28,10 +28,65 @@ namespace Microsoft.Maui.DeviceTests
handlers.AddHandler<ListView, ListViewRenderer>();
handlers.AddHandler<VerticalStackLayout, LayoutHandler>();
handlers.AddHandler<Label, LabelHandler>();
handlers.AddHandler<Entry, EntryHandler>();
});
});
}
[Fact
#if ANDROID
(Skip = "https://github.com/dotnet/maui/issues/24701")
#endif
]
public async Task ChangingTemplateTypeDoesNotCrash()
{
SetupBuilder();
ObservableCollection<string> data1 = new ObservableCollection<string>()
{
"cat",
"dog",
};
ObservableCollection<string> data2 = new ObservableCollection<string>()
{
"dog",
"cat",
};
var template1 = new DataTemplate(() =>
{
return new ViewCell()
{
View = new Label()
};
});
var template2 = new DataTemplate(() =>
{
return new ViewCell()
{
View = new Entry()
};
});
var listView = new ListView()
{
HasUnevenRows = true,
ItemTemplate = new FunctionalDataTemplateSelector((item, container) =>
{
return item.ToString() == "cat" ? template1 : template2;
}),
IsGroupingEnabled = true,
ItemsSource = new ObservableCollection<ObservableCollection<string>>(){data1}
};
await CreateHandlerAndAddToWindow<LayoutHandler>(new VerticalStackLayout(){ listView }, async (handler) =>
{
listView.ItemsSource = new ObservableCollection<ObservableCollection<string>>(){data2};
await Task.Delay(5000);
});
}
[Fact]
public async Task RemovingFirstItemOfListViewDoesntCrash()
{
@ -346,5 +401,20 @@ namespace Microsoft.Maui.DeviceTests
Assert.Equal("6", cells[2].Text);
});
}
class FunctionalDataTemplateSelector : DataTemplateSelector
{
public Func<object, BindableObject, DataTemplate> Selector { get; }
public FunctionalDataTemplateSelector(Func<object, BindableObject, DataTemplate> selectTemplate)
{
Selector = selectTemplate;
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return Selector.Invoke(item, container);
}
}
}
}
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 9.5 KiB

Просмотреть файл

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue15196">
<StackLayout x:Name="stackLayout">
<Frame x:Name="frame" HeightRequest="200">
<Entry x:Name="entry" Text="This is entry inside the frame"/>
</Frame>
<Button Text="Remove the frame" AutomationId="RemoveButton" Clicked="OnButtonClicked"/>
</StackLayout>
</ContentPage>

Просмотреть файл

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 15196, "Nested Entry View In A Frame Causes Crash", PlatformAffected.Android)]
public partial class Issue15196 : ContentPage
{
public Issue15196()
{
InitializeComponent();
}
private void OnButtonClicked(object sender, EventArgs e)
{
if (stackLayout.Children.Contains(frame))
{
stackLayout.Children.Remove(frame);
}
frame?.Handler?.DisconnectHandler();
entry?.Handler?.DisconnectHandler();
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue21728"
xmlns:ns="clr-namespace:Maui.Controls.Sample.Issues">
<CollectionView x:Name="collectionview" AutomationId="collectionview" ItemsLayout="VerticalGrid, 2">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Name}" BackgroundColor="Red" HeightRequest="200" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.Footer>
<ContentView >
<ContentView.ControlTemplate>
<ControlTemplate>
<Label Text="CollectionView Footer"/>
</ControlTemplate>
</ContentView.ControlTemplate>
</ContentView>
</CollectionView.Footer>
</CollectionView>
</ContentPage>

Просмотреть файл

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Maui.Controls;
namespace Maui.Controls.Sample.Issues;
[Issue(IssueTracker.Github, 21728, "CollectionView item alignment issue when a single item is present with a footer", PlatformAffected.iOS)]
public partial class Issue21728 : ContentPage
{
public IList<TestItem> Items { get; set; }
public Issue21728()
{
InitializeComponent();
BindingContext = this;
Items = new List<TestItem>();
Items.Add(new TestItem() { Name = "Test Item 1" });
collectionview.ItemsSource = Items;
}
public class TestItem
{
public string Name { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<Shell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue22452"
xmlns:ns="clr-namespace:Maui.Controls.Sample.Issues"
Shell.FlyoutBehavior="Locked">
<FlyoutItem Title="FlyoutItem">
<Tab>
<ShellContent ContentTemplate="{DataTemplate ns:Issue22452Content}" />
</Tab>
</FlyoutItem>
</Shell>

Просмотреть файл

@ -0,0 +1,32 @@
namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 22452, "Fix error when running new template maui app on iOS", PlatformAffected.iOS)]
public partial class Issue22452 : Shell
{
public Issue22452()
{
InitializeComponent();
}
}
public class Issue22452Content : ContentPage
{
public Issue22452Content()
{
Content = new StackLayout
{
Children =
{
new Label
{
AutomationId="TabContent",
Text = "TabContent"
}
},
IgnoreSafeArea = false
};
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
#if !MACCATALYST
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
internal class Issue15196 : _IssuesUITest
{
public override string Issue => "Nested Entry View In A Frame Causes Crash";
public Issue15196(TestDevice testDevice) : base(testDevice) { }
[Test]
[Category(UITestCategories.Entry)]
public void NestedEntryViewInFrameShouldNotCrash()
{
App.WaitForElement("RemoveButton");
App.Click("RemoveButton");
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,26 @@
#if !MACCATALYST
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue21728 : _IssuesUITest
{
public override string Issue => "CollectionView item alignment issue when a single item is present with a footer";
public Issue21728(TestDevice device)
: base(device)
{ }
[Test]
[Category(UITestCategories.CollectionView)]
public void CollectionViewSingleItemAlignmentWithFooter()
{
App.WaitForElement("collectionview");
VerifyScreenshot();
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,21 @@
using System.Diagnostics;
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
namespace Microsoft.Maui.TestCases.Tests.Issues;
public class Issue22452 : _IssuesUITest
{
public Issue22452(TestDevice device) : base(device) { }
public override string Issue => "Fix error when running new template maui app on iOS";
[Test]
[Category(UITestCategories.Shell)]
public void NavigationBetweenFlyoutItems()
{
App.WaitForElement("TabContent");
VerifyScreenshot();
}
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 14 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui20508">
<ContentPage.ToolbarItems>
<ToolbarItem>
<ToolbarItem.IconImageSource>
<FileImageSource File="{Binding Icon}" />
</ToolbarItem.IconImageSource>
</ToolbarItem>
</ContentPage.ToolbarItems>
</ContentPage>

Просмотреть файл

@ -0,0 +1,42 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Controls.Core.UnitTests;
using Microsoft.Maui.Dispatching;
using Microsoft.Maui.UnitTests;
using NUnit.Framework;
namespace Microsoft.Maui.Controls.Xaml.UnitTests;
public partial class Maui20508
{
public Maui20508()
{
InitializeComponent();
}
public Maui20508(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
class Test
{
[SetUp]
public void Setup()
{
Application.SetCurrentApplication(new MockApplication());
DispatcherProvider.SetCurrent(new DispatcherProviderStub());
}
[TearDown] public void TearDown() => AppInfo.SetCurrent(null);
[Test]
public void ToolBarItemBinding([Values(false, true)] bool useCompiledXaml)
{
var page = new Maui20508(useCompiledXaml) {BindingContext = new {Icon = "boundIcon.png"}};
Assert.That(((FileImageSource)page.ToolbarItems[0].IconImageSource).File, Is.EqualTo("boundIcon.png"));
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui23201">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Search">
<ToolbarItem.IconImageSource>
<FontImageSource FontFamily="SegoeFluentIcons"
Glyph="&#xE721;"
Color="{AppThemeBinding Light={StaticResource Black},
Dark={StaticResource White}}" />
</ToolbarItem.IconImageSource>
</ToolbarItem>
<ToolbarItem Text="23195">
<ToolbarItem.IconImageSource>
<FontImageSource FontFamily="SegoeFluentIcons"
Glyph="&#xE721;"
Color="{AppThemeBinding Light=Black,
Dark=White}" />
</ToolbarItem.IconImageSource>
</ToolbarItem>
</ContentPage.ToolbarItems>
</ContentPage>

Просмотреть файл

@ -0,0 +1,55 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Controls.Core.UnitTests;
using Microsoft.Maui.Dispatching;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.UnitTests;
using NUnit.Framework;
namespace Microsoft.Maui.Controls.Xaml.UnitTests;
public partial class Maui23201
{
public Maui23201()
{
InitializeComponent();
}
public Maui23201(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
class Test
{
[SetUp]
public void Setup()
{
Application.SetCurrentApplication(new MockApplication());
DispatcherProvider.SetCurrent(new DispatcherProviderStub());
}
[TearDown] public void TearDown() => AppInfo.SetCurrent(null);
[Test]
public void ToolBarItemAppThemeBinding([Values(false, true)] bool useCompiledXaml)
{
Application.Current.Resources.Add("Black", Colors.DarkGray);
Application.Current.Resources.Add("White", Colors.LightGray);
Application.Current.UserAppTheme = AppTheme.Light;
var page = new Maui23201(useCompiledXaml);
Application.Current.MainPage = page;
Assert.That(((FontImageSource)(page.ToolbarItems[0].IconImageSource)).Color, Is.EqualTo(Colors.DarkGray));
Assert.That(((FontImageSource)(page.ToolbarItems[1].IconImageSource)).Color, Is.EqualTo(Colors.Black));
Application.Current.UserAppTheme = AppTheme.Dark;
Assert.That(((FontImageSource)(page.ToolbarItems[0].IconImageSource)).Color, Is.EqualTo(Colors.LightGray));
Assert.That(((FontImageSource)(page.ToolbarItems[1].IconImageSource)).Color, Is.EqualTo(Colors.White));
}
}
}