diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla23942.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla23942.xaml new file mode 100644 index 000000000000..aa4ba34b7b5d --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla23942.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla23942.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla23942.xaml.cs new file mode 100644 index 000000000000..f90ced9cbbf5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla23942.xaml.cs @@ -0,0 +1,97 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 23942, "Cannot bind properties in BindableObjects added to static resources in XAML", PlatformAffected.All)] + public partial class Bugzilla23942 : TestContentPage + { + [Preserve(AllMembers = true)] + public class TestViewModel : ViewModelBase + { + string _doesItWork; + public string DoesItWork + { + get + { + return _doesItWork; + } + set + { + _doesItWork = value; + OnPropertyChanged(); + } + } + } + + public Bugzilla23942() + { + InitializeComponent(); + } + + private void InitializeView() + { + TestViewModel vm = new TestViewModel() { DoesItWork = "initial binding works" }; + BindingContext = vm; + vm.DoesItWork = "success"; + } + + protected override void Init() + { + InitializeView(); + } + + protected override void OnAppearing() + { + base.OnAppearing(); + var lbl = this.FindByName("label"); + lbl.Text = lbl.Options.Text; + } + } + + [Preserve(AllMembers = true)] + public class Bugzilla23942Options : BindableObject + { + public static readonly BindableProperty TextProperty = + BindableProperty.Create(propertyName: nameof(Text), + returnType: typeof(string), + declaringType: typeof(Bugzilla23942Options), + defaultValue: default(string)); + + public string Text + { + get + { + return (string)GetValue(TextProperty); + } + set + { + SetValue(TextProperty, value); + } + } + } + + [Preserve(AllMembers = true)] + public class Bugzilla23942Label : Label + { + public static readonly BindableProperty OptionsProperty = + BindableProperty.Create(propertyName: nameof(Options), + returnType: typeof(Bugzilla23942Options), + declaringType: typeof(Bugzilla23942Label), + defaultValue: default(Bugzilla23942Options)); + + public Bugzilla23942Options Options + { + get + { + return (Bugzilla23942Options)GetValue(OptionsProperty); + } + set + { + SetValue(OptionsProperty, value); + } + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla25943.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla25943.cs new file mode 100644 index 000000000000..cfbc46ff2a0e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla25943.cs @@ -0,0 +1,82 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 25943, + "[Android] TapGestureRecognizer does not work with a nested StackLayout", PlatformAffected.Android)] + public class Bugzilla25943 : TestContentPage + { + Label _result; + int _taps; + const string InnerLayout = "innerlayout"; + const string OuterLayout = "outerlayout"; + const string Success = "Success"; + + protected override void Init() + { + StackLayout layout = GetNestedStackLayout(); + + var tapGestureRecognizer = new TapGestureRecognizer(); + tapGestureRecognizer.Tapped += (sender, e) => + { + _taps = _taps + 1; + if (_taps == 2) + { + _result.Text = Success; + } + }; + layout.GestureRecognizers.Add(tapGestureRecognizer); + + Content = layout; + } + + public StackLayout GetNestedStackLayout() + { + _result = new Label(); + +#pragma warning disable CS0618 // Type or member is obsolete + var innerLayout = new StackLayout + { + AutomationId = InnerLayout, + HeightRequest = 100, + Orientation = StackOrientation.Horizontal, + HorizontalOptions = LayoutOptions.Fill, + BackgroundColor = Colors.AntiqueWhite, + Children = + { + new Label + { + Text = "inner label", + FontSize = 20, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.CenterAndExpand + } + } + }; +#pragma warning restore CS0618 // Type or member is obsolete + + var outerLayout = new StackLayout + { + AutomationId = OuterLayout, + Orientation = StackOrientation.Vertical, + BackgroundColor = Colors.Brown, + Children = + { + _result, + innerLayout, + new Label + { + Text = "outer label", + FontSize = 20, + HorizontalOptions = LayoutOptions.Center, + } + } + }; + + return outerLayout; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29128.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29128.cs new file mode 100644 index 000000000000..c8b079d74163 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29128.cs @@ -0,0 +1,22 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 29128, "Slider background lays out wrong Android")] + public class Bugzilla29128 : TestContentPage + { + protected override void Init() + { + Content = new Slider + { + AutomationId = "SliderId", + BackgroundColor = Colors.Blue, + Maximum = 255, + Minimum = 0, + }; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29363.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29363.cs new file mode 100644 index 000000000000..a72a1c643c04 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29363.cs @@ -0,0 +1,46 @@ +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 29363, "PushModal followed immediate by PopModal crashes")] + public class Bugzilla29363 : NavigationPage + { + public Bugzilla29363() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { +#pragma warning disable CS0618 // Type or member is obsolete + var layout = new StackLayout() { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand }; +#pragma warning restore CS0618 // Type or member is obsolete + + Button modal = new Button + { + AutomationId = "ModalPushPopTest", + Text = "Modal Push Pop Test", + FontAttributes = FontAttributes.Bold, + FontSize = 25, + HorizontalOptions = LayoutOptions.Center + }; + modal.Clicked += async (object sender, EventArgs e) => + { + var page = new ContentPage() { BackgroundColor = Colors.Red }; + + await Navigation.PushModalAsync(page); + + await Navigation.PopModalAsync(true); + }; + + layout.Children.Add(modal); + Content = layout; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29453.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29453.cs new file mode 100644 index 000000000000..94026627d752 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla29453.cs @@ -0,0 +1,66 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 29453, "Navigation.PopAsync(false) in Entry.Completed handler => System.ArgumentException", PlatformAffected.Android)] + public class Bugzilla29453 : NavigationPage + { + public Bugzilla29453() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + var page1Layout = new StackLayout + { + Children = { + new Label { + AutomationId = "Page1", + HorizontalTextAlignment = TextAlignment.Center, + Text = "Page 1" + } + } + }; + + var page2Layout = new StackLayout + { + Children = { + new Label { + HorizontalTextAlignment = TextAlignment.Center, + Text = "Page 2" + } + } + }; + + var entry = new Entry { AutomationId = "entryText" }; + + entry.Completed += async (sender, args) => + { + await Navigation.PopAsync(false); + }; + + page2Layout.Children.Add(entry); + + var page2 = new ContentPage + { + Content = page2Layout + }; + + var button = new Button + { + Text = "Go to page 2", + AutomationId = "btnGotoPage2", + Command = new Command(async () => await Navigation.PushAsync(page2)) + }; + + page1Layout.Children.Add(button); + Content = page1Layout; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla30166.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla30166.cs new file mode 100644 index 000000000000..2a9969f15b0b --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla30166.cs @@ -0,0 +1,40 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 30166, "NavigationBar.BarBackgroundColor resets on Lollipop after popping modal page", PlatformAffected.Android)] + public class Bugzilla30166 : NavigationPage + { + public Bugzilla30166() : base(new MainPage()) + { + BarBackgroundColor = Colors.Red; + } + + public class MainPage : ContentPage + { + public MainPage() + { + Navigation.PushAsync(new ContentPage + { + Content = new Button + { + AutomationId = "PushModal", + Text = "Push Modal", + Command = new Command(async () => await Navigation.PushModalAsync(new ContentPage + { + Content = new Button + { + AutomationId = "Back", + Text = "Back", + Command = new Command(async () => await Navigation.PopModalAsync()), + }, + })), + }, + }); + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla30935.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla30935.cs new file mode 100644 index 000000000000..d05d33c5a341 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla30935.cs @@ -0,0 +1,32 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 30935, "NullReferenceException in ViewRenderer (Microsoft.Maui.Controls.Platform.Android)")] + public class Bugzilla30935 : TestContentPage + { + Entry _entry; + protected override void Init() + { + _entry = new Entry { AutomationId = "entry" }; + // Initialize ui here instead of ctor + Content = new StackLayout + { + Children = { new Label { + AutomationId = "IssuePageLabel", + Text = "See if I'm here" + },_entry + } + }; + } + + protected override void OnAppearing() + { + _entry.Focus(); + Content = null; + base.OnAppearing(); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31255.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31255.cs new file mode 100644 index 000000000000..933080b09594 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31255.cs @@ -0,0 +1,87 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 31255, "Flyout's page Icon cause memory leak after FlyoutPage is popped out by holding on page")] + public class Bugzilla31255 : NavigationPage + { + public Bugzilla31255() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + var stack = new StackLayout() { VerticalOptions = LayoutOptions.Center }; + + stack.Children.Add(new Label() + { + VerticalOptions = LayoutOptions.Center, + HorizontalTextAlignment = TextAlignment.Center, + Text = "Page 1" + }); + + Content = stack; + + } + + WeakReference _page2Tracker; + + protected override async void OnAppearing() + { + base.OnAppearing(); + + if (_page2Tracker == null) + { + var page2 = new Page2(); + + _page2Tracker = new WeakReference(page2, false); + + await Task.Delay(1000); + await Navigation.PushModalAsync(page2); + + StartTrackPage2(); + } + } + + async void StartTrackPage2() + { + while (true) + { + ((Label)((StackLayout)Content).Children[0]).Text = + string.Format("Page1. But Page2 IsAlive = {0}", _page2Tracker.IsAlive); + await Task.Delay(1000); + GarbageCollectionHelper.Collect(); + } + } + + [Preserve(AllMembers = true)] + public class Page2 : FlyoutPage + { + public Page2() + { + Flyout = new Page() + { + Title = "Flyout", + IconImageSource = "Icon.png" + }; + Detail = new Page() { Title = "Detail" }; + } + + protected override async void OnAppearing() + { + base.OnAppearing(); + + await Task.Delay(1000); + await Navigation.PopModalAsync(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31366.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31366.cs new file mode 100644 index 000000000000..287ffeb4aa49 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31366.cs @@ -0,0 +1,75 @@ +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 31366, "Pushing and then popping a page modally causes ArgumentOutOfRangeException", + PlatformAffected.All)] + public class Bugzilla31366 : NavigationPage + { + public Bugzilla31366() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + var page1 = new ContentPage() { Title = "Page1" }; + + var successLabel = new Label(); + var startPopOnAppearing = new Button() { AutomationId = "StartPopOnAppearingTest", Text = "Start PopOnAppearing Test" }; + var startModalStack = new Button() { AutomationId = "StartModalStackTest", Text = "Start ModalStack Test" }; + + page1.Content = new StackLayout() + { + Children = { startPopOnAppearing, startModalStack, successLabel } + }; + + var popOnAppearing = new ContentPage() + { + Title = "PopOnAppearing", + Content = new StackLayout() + }; + + popOnAppearing.Appearing += async (sender, args) => + { + await Task.Yield(); + await popOnAppearing.Navigation.PopModalAsync(); + }; + + startPopOnAppearing.Clicked += async (sender, args) => + { + successLabel.Text = string.Empty; + + await page1.Navigation.PushModalAsync(popOnAppearing); + + successLabel.Text = "If this is visible, the PopOnAppearing test has passed."; + }; + + startModalStack.Clicked += async (sender, args) => + { + successLabel.Text = string.Empty; + + var intermediatePage = new ContentPage() + { + Content = new StackLayout() + { + Children = { + new Label () { Text = "If this is visible, the modal stack test has passed." } + } + } + }; + + await intermediatePage.Navigation.PushModalAsync(popOnAppearing); + + await page1.Navigation.PushModalAsync(intermediatePage); + }; + + Navigation.PushAsync(page1); + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31395.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31395.cs new file mode 100644 index 000000000000..fb0eacc77a54 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31395.cs @@ -0,0 +1,45 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 31395, "Crash when switching MainPage and using a Custom Render")] + public class Bugzilla31395 : NavigationPage + { + public Bugzilla31395() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + Content = new CustomContentView + { // Replace with ContentView and everything works fine + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = { + new Button { + AutomationId = "SwitchMainPage", + Text = "Switch Main Page", + Command = new Command (() => SwitchMainPage ()) + } + } + } + }; + } + + void SwitchMainPage() + { + Application.Current.MainPage = new ContentPage { Content = new Label { Text = "Hello" } }; + } + + public class CustomContentView : ContentView + { + + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31688.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31688.cs new file mode 100644 index 000000000000..a9f51ca8facc --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla31688.cs @@ -0,0 +1,123 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 31688, "'Navigation.InsertPageBefore()' does not work for more than two pages, \"throws java.lang.IndexOutOfBoundsException: index=3 count=2", PlatformAffected.Android)] + public class Bugzilla31688 : NavigationPage // or TestFlyoutPage, etc ... + { + public Bugzilla31688() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + MyMainPage _page; + + public MainPage() + { + _page = new MyMainPage(); + Navigation.PushAsync(_page); + _page.LoadAsync(); + } + + public class MyMainPage : ContentPage + { + public MyMainPage() + { + Content = new Label { Text = "My Main Page" }; + } + + public async void LoadAsync() + { + ActivityIndicatorPage aip = new ActivityIndicatorPage(); + await Navigation.PushAsync(aip); + + var page1 = await Page1.CreateAsync(); + Navigation.InsertPageBefore(page1, aip); + + var page2 = await Page2.CreateAsync(); + Navigation.InsertPageBefore(page2, aip); + + var page3 = await Page3.CreateAsync(); + Navigation.InsertPageBefore(page3, aip); + + + //// try to remove last page (with AcitivityIndicator) and here it bombs with the error: "java.lang.IndexOutOfBoundsException: index=3 count=2" + await Navigation.PopAsync(); + } + } + + public class Page1 : ContentPage + { + private Page1() + { + Content = new Label { Text = "Page 1" }; + } + + public static async Task CreateAsync() + { + var page = new Page1(); + await Task.Delay(TimeSpan.FromMilliseconds(200)); // simulate loading of state from DB + return page; + } + } + + public class Page2 : ContentPage + { + private Page2() + { + Content = new Label { Text = "Page 2" }; + } + + public static async Task CreateAsync() + { + var page = new Page2(); + await Task.Delay(TimeSpan.FromMilliseconds(200)); // simulate loading of state from DB + return page; + } + } + + class Page3 : ContentPage + { + private Page3() + { + Content = new Label { AutomationId = "Page3", Text = "Page 3" }; + } + + public static async Task CreateAsync() + { + var page = new Page3(); + await Task.Delay(TimeSpan.FromMilliseconds(200)); // simulate loading of state from DB + return page; + } + } + + public class Page4 : ContentPage + { + private Page4() + { + Content = new Label { Text = "Page 4" }; + } + + public static async Task CreateAsync() + { + var page = new Page4(); + await Task.Delay(TimeSpan.FromMilliseconds(200)); // simulate loading of state from DB + return page; + } + } + + public class ActivityIndicatorPage : ContentPage + { + public ActivityIndicatorPage() + { + Content = new ActivityIndicator { IsRunning = true }; + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32206.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32206.cs new file mode 100644 index 000000000000..64a491dfdc15 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32206.cs @@ -0,0 +1,113 @@ +using System.Collections.Generic; +using System.Threading; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 32206, "ContextActions cause memory leak: Page is never destroyed", PlatformAffected.iOS)] + public class Bugzilla32206 : TestNavigationPage + { + protected override void Init() + { + PushAsync(new LandingPage32206()); + } + } + + [Preserve(AllMembers = true)] + public class LandingPage32206 : ContentPage + { + public static int Counter; + public Label Label; + + public LandingPage32206() + { + Label = new Label + { + Text = "Counter: " + Counter, + HorizontalTextAlignment = TextAlignment.Center, + VerticalTextAlignment = TextAlignment.Center + }; + + Content = new StackLayout + { + Orientation = StackOrientation.Vertical, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + Spacing = 15, + Children = + { + new Label + { + Text = "Click Push to show a ListView. When you hit the Back button, Counter will show the number of pages that have not been finalized yet." + + " If you click GC, the counter should be 0." + }, + Label, + new Button + { + Text = "GC", + AutomationId = "GC", + Command = new Command(o => + { + GarbageCollectionHelper.Collect(); + Label.Text = "Counter: " + Counter; + }) + }, + new Button + { + Text = "Push", + AutomationId = "Push", + Command = new Command(async o => + { + await Navigation.PushAsync(new ContentPage32206()); + }) + } + } + }; + } + + protected override void OnAppearing() + { + base.OnAppearing(); + + if (Label != null) + Label.Text = "Counter: " + Counter; + } + } + + [Preserve(AllMembers = true)] + public class ContentPage32206 : ContentPage + { + public ContentPage32206() + { + Interlocked.Increment(ref LandingPage32206.Counter); + System.Diagnostics.Debug.WriteLine("Page: " + LandingPage32206.Counter); + + Content = new ListView + { + ItemsSource = new List { "Apple", "Banana", "Cherry" }, + ItemTemplate = new DataTemplate(typeof(ViewCell32206)), + AutomationId = "ListView" + }; + } + + ~ContentPage32206() + { + Interlocked.Decrement(ref LandingPage32206.Counter); + System.Diagnostics.Debug.WriteLine("Page: " + LandingPage32206.Counter); + } + } + + [Preserve(AllMembers = true)] + public class ViewCell32206 : ViewCell + { + public ViewCell32206() + { + View = new Label(); + View.SetBinding(Label.TextProperty, "."); + ContextActions.Add(new MenuItem { Text = "Delete" }); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32615.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32615.cs new file mode 100644 index 000000000000..2ca6164f00a5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32615.cs @@ -0,0 +1,63 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 32615, "OnAppearing is not called on previous page when modal page is popped")] + public class Bugzilla32615 : NavigationPage + { + public Bugzilla32615() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + int _counter; + Label _textField; + + public MainPage() + { +#pragma warning disable CS0618 // Type or member is obsolete + var btnModal = new Button { AutomationId = "btnModal", Text = "open", HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand }; +#pragma warning restore CS0618 // Type or member is obsolete + btnModal.Clicked += async (sender, e) => await Navigation.PushModalAsync(new Bugzilla32615Page2()); + _textField = new Label { AutomationId = "lblCount" }; + var layout = new StackLayout(); + layout.Children.Add(btnModal); + layout.Children.Add(_textField); + // Initialize ui here instead of ctor + Content = layout; + } + + protected override void OnAppearing() + { + _textField.Text = _counter++.ToString(); + } + + class Bugzilla32615Page2 : ContentPage + { + public Bugzilla32615Page2() + { +#pragma warning disable CS0618 // Type or member is obsolete + var btnPop = new Button { AutomationId = "btnPop", Text = "pop", HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand }; +#pragma warning restore CS0618 // Type or member is obsolete + btnPop.Clicked += async (sender, e) => await Navigation.PopModalAsync(); + Content = btnPop; + } + + protected override void OnDisappearing() + { + System.Diagnostics.Debug.WriteLine("Disappearing Modal"); + base.OnDisappearing(); + } + + protected override void OnAppearing() + { + System.Diagnostics.Debug.WriteLine("Appearing Modal"); + base.OnAppearing(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32830.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32830.cs new file mode 100644 index 000000000000..6ab249318d4f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32830.cs @@ -0,0 +1,128 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + // Uses a custom renderer on Android to override SetupPageTransition. + // While these transitions are often desired, they can appear to cause the "flash" + // at the top and bottom of the screen that could be confused with the bug we're fixing. + public class NoFlashTestNavigationPage : TestNavigationPage + { + protected override void Init() + { + + } + } + + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 32830, "Hiding navigation bar causes layouts to shift during navigation", PlatformAffected.iOS)] + public class Bugzilla32830 : NoFlashTestNavigationPage + { + const string Button1 = "button1"; + const string Button2 = "button2"; + const string BottomLabel = "I am visible at the bottom of the page"; + + [Preserve(AllMembers = true)] + class Page1 : ContentPage + { + public Page1() + { + Title = "Page 1"; + BackgroundColor = Colors.Gray; + + var relativeLayout = new Microsoft.Maui.Controls.Compatibility.RelativeLayout { }; + + relativeLayout.Children.Add(new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = { + new Label { + HorizontalTextAlignment = TextAlignment.Center, + Text = "Page 1", + TextColor = Colors.White + }, + new Button { + Text = "Go to page 2", + Command = new Command(async () => await Navigation.PushAsync(new Page2())), + AutomationId = Button1, + TextColor = Colors.White + }, + new Button { + Text = "Toggle Nav Bar", + Command = new Command(() => NavigationPage.SetHasNavigationBar(this, !NavigationPage.GetHasNavigationBar(this))), + TextColor = Colors.White + } + } + }, yConstraint: Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(parent => { return parent.Y; })); + + relativeLayout.Children.Add(new Label + { + Text = BottomLabel, + TextColor = Colors.White + }, yConstraint: Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(parent => { return parent.Height - 30; })); + + Content = relativeLayout; + + NavigationPage.SetHasNavigationBar(this, false); + } + } + + [Preserve(AllMembers = true)] + class Page2 : ContentPage + { + public Page2() + { + Title = "Page 2"; + BackgroundColor = Colors.Gray; + var relativeLayout = new Microsoft.Maui.Controls.Compatibility.RelativeLayout { }; + relativeLayout.Children.Add(new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = { + new Label { + HorizontalTextAlignment = TextAlignment.Center, + Text = "Page 2", + TextColor = Colors.White + }, + new Button { + Text = "Go to tabs", + AutomationId = Button2, + Command = new Command(async () => await Navigation.PushAsync(new MyTabs())), + TextColor = Colors.White + }, + new Button { + Text = "Toggle Nav Bar", + Command = new Command(() => NavigationPage.SetHasNavigationBar(this, !NavigationPage.GetHasNavigationBar(this))), + TextColor = Colors.White + } + } + }, yConstraint: Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(parent => { return parent.Y; })); + + relativeLayout.Children.Add(new Label + { + Text = BottomLabel, + TextColor = Colors.White + }, yConstraint: Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(parent => { return parent.Height - 30; })); + + Content = relativeLayout; + } + } + + class MyTabs : TabbedPage + { + public MyTabs() + { + Children.Add(new NavigationPage(new Page1())); + Children.Add(new Page2()); + } + } + + protected override void Init() + { + Navigation.PushAsync(new Page1()); + + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32898.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32898.cs new file mode 100644 index 000000000000..e325e8b71b29 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla32898.cs @@ -0,0 +1,78 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 32898, "Memory leak when TabbedPage is popped out ")] + public class Bugzilla32898 : TestContentPage + { + WeakReference _page2Tracker; + WeakReference _tabTracker; + + Label _result; + const string Success = "Success"; + const string Fail = "Fail"; + const int Timeout = 20000; + + protected override void Init() + { + var stack = new StackLayout { VerticalOptions = LayoutOptions.Center }; + + _result = new Label + { + VerticalOptions = LayoutOptions.Center, + HorizontalTextAlignment = TextAlignment.Center, + Text = "Page 1" + }; + + stack.Children.Add(_result); + + Content = stack; + } + + protected override async void OnAppearing() + { + base.OnAppearing(); + + if (_page2Tracker == null) + { + var page2 = new TabbedPage { Children = { new ContentPage { Title = "tab" } } }; + page2.Appearing += async delegate + { + await Task.Delay(1000); + await page2.Navigation.PopModalAsync(); + }; + + _page2Tracker = new WeakReference(page2, false); + _tabTracker = new WeakReference(page2.Children[0], false); + + await Task.Delay(1000); + await Navigation.PushModalAsync(page2); + + StartTrackPage2(); + } + } + + async void StartTrackPage2() + { + var watch = new Stopwatch(); + watch.Start(); + + // We'll let this run until the references are dead or timeout has passed + while (_page2Tracker.IsAlive && _tabTracker.IsAlive && watch.ElapsedMilliseconds < Timeout) + { + await Task.Delay(1000); + GarbageCollectionHelper.Collect(); + } + + watch.Stop(); + + _result.Text = _page2Tracker.IsAlive || _tabTracker.IsAlive ? Fail : Success; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla34007.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla34007.cs new file mode 100644 index 000000000000..c4d105ab16d7 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla34007.cs @@ -0,0 +1,68 @@ +using System; +using System.Xml.Linq; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 34007, "Z order drawing of children views are different on Android, iOS, Win", PlatformAffected.Android | PlatformAffected.iOS)] + public class Bugzilla34007 : TestContentPage + { + protected override void Init() + { + var grid = new Grid(); + + var button0 = new Button + { + AutomationId = "Button0", + Text = "Button 0", + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill + }; + + var button1 = new Button + { + AutomationId = "Button1", + Text = "Button 1", + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill + }; + + var lastButtonTappedLabel = new Label(); + + Action reorder = () => + { + // Get the last item in the grid + var item = grid.Children[1]; + + // Remove it + grid.Children.RemoveAt(1); + + // And put it back as the 0th item + grid.Children.Insert(0, item); + }; + + button0.Clicked += (sender, args) => + { + lastButtonTappedLabel.Text = "Button 0 was tapped last"; + }; + + button1.Clicked += (sender, args) => + { + lastButtonTappedLabel.Text = "Button 1 was tapped last"; + + reorder(); + }; + + grid.Add(button0, 0, 0); + grid.Add(button1, 0, 0); + + Content = new StackLayout + { + Children = { grid, lastButtonTappedLabel } + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla34061.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla34061.cs new file mode 100644 index 000000000000..b734337e5ec1 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla34061.cs @@ -0,0 +1,64 @@ +using System; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 34061, "RelativeLayout - First child added after page display does not appear")] + public class Bugzilla34061 : TestContentPage + { + Microsoft.Maui.Controls.Compatibility.RelativeLayout _layout; + + protected override void Init() + { + _layout = new Microsoft.Maui.Controls.Compatibility.RelativeLayout(); + var label = new Label { Text = "Some content goes here", HorizontalOptions = LayoutOptions.Center }; + + var addButton = new Button { Text = "Add Popover", AutomationId = "btnAdd" }; + addButton.Clicked += (s, ea) => AddPopover(); + + var stack = new StackLayout + { + Orientation = StackOrientation.Vertical, + Children = { + label, + addButton + }, + }; + + _layout.Children.Add(stack, + Microsoft.Maui.Controls.Compatibility.Constraint.Constant(0), + Microsoft.Maui.Controls.Compatibility.Constraint.Constant(0), + Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(p => p.Width), + Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(p => p.Height)); + + Content = _layout; + } + + void AddPopover() + { + var newView = new Button + { + BackgroundColor = Color.FromRgba(64, 64, 64, 64), + Text = "Remove Me", + AutomationId = "btnRemoveMe" + }; + newView.Clicked += (s, ea) => RemovePopover(newView); + + _layout.Children.Add( + newView, + Microsoft.Maui.Controls.Compatibility.Constraint.Constant(0), + Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(p => p.Height / 2), + Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(p => p.Width), + Microsoft.Maui.Controls.Compatibility.Constraint.RelativeToParent(p => p.Height / 2)); + } + + void RemovePopover(View view) + { + _layout.Children.Remove(view); + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35472.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35472.cs new file mode 100644 index 000000000000..947df8682df7 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35472.cs @@ -0,0 +1,86 @@ +using System; +using System.Diagnostics; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 35472, "PopAsync during ScrollToAsync throws NullReferenceException")] + public class Bugzilla35472 : NavigationPage + { + public Bugzilla35472() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + // Set up the scroll viewer page + var scrollToButton = new Button() { AutomationId = "NowPushButton", Text = "Now push this button" }; + + var stackLayout = new StackLayout(); + + stackLayout.Children.Add(scrollToButton); + + for (int n = 0; n < 100; n++) + { + stackLayout.Children.Add(new Label() { Text = n.ToString() }); + } + + var scrollView = new ScrollView() + { + Content = stackLayout + }; + + var pageWithScrollView = new ContentPage() + { + Content = scrollView + }; + + // Set up the start page + var goButton = new Button() + { + AutomationId = "PushButton", + Text = "Push this button" + }; + + var successLabel = new Label() { Text = "The test has passed", IsVisible = false }; + + var startPage = new ContentPage() + { + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = { + goButton, + successLabel + } + } + }; + + Navigation.PushAsync(startPage); + + goButton.Clicked += (sender, args) => Navigation.PushAsync(pageWithScrollView); + + scrollToButton.Clicked += async (sender, args) => + { + try + { +#pragma warning disable 4014 + // Deliberately not awaited so we can simulate a user navigating back before the scroll is finished + scrollView.ScrollToAsync(0, 1500, true); +#pragma warning restore 4014 + await Navigation.PopAsync(); + successLabel.IsVisible = true; + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + }; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35477.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35477.cs new file mode 100644 index 000000000000..47ba0575455e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35477.cs @@ -0,0 +1,35 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 35477, "Tapped event does not fire when added to Frame in Android AppCompat", + PlatformAffected.Android)] + public class Bugzilla35477 : TestContentPage + { + protected override void Init() + { + var instructions = new Label + { + Text = "Tap the frame below. The label with the text 'No taps yet' should change its text to 'Frame was tapped'." + }; + var frame = new Frame() { }; + var frameLabel = new Label() { AutomationId = "TapHere", Text = "Tap here" }; + + frame.Content = new StackLayout() { Children = { frameLabel } }; + + var label = new Label { Text = "No taps yet" }; + + var rec = new TapGestureRecognizer { NumberOfTapsRequired = 1 }; + rec.Tapped += (s, e) => { label.Text = "Frame was tapped"; }; + frame.GestureRecognizers.Add(rec); + + Content = new StackLayout + { + Children = { instructions, frame, label } + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35733.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35733.cs new file mode 100644 index 000000000000..da837b24cfe2 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35733.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 35733, "iOS WebView crashes when loading an URL with encoded parameters", PlatformAffected.iOS)] + public class Bugzilla35733 : TestContentPage // or TestFlyoutPage, etc ... + { + protected override void Init() + { + var thisDoesNotWorkButton = new Button + { + Text = "This will crash", + AutomationId = "btnGo" + + }; + thisDoesNotWorkButton.Clicked += async (object sender, EventArgs e) => await ShowLocation("KÅRA"); + + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = { + thisDoesNotWorkButton + } + }; + } + + async Task ShowLocation(string locationString) + { + var stringUri = $"https://raw.githubusercontent.com/xamarin/Xamarin.Forms/main/README.md?l=en&px_location={Uri.EscapeDataString(locationString)}"; + + var uri = new Uri(stringUri); + var webPage = new ContentPage + { + Title = "WebViewTest", + Content = new WebView + { + Source = uri + } + }; + await Navigation.PushAsync(webPage); + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35736.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35736.cs new file mode 100644 index 000000000000..57c9d9f3aaf6 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla35736.cs @@ -0,0 +1,39 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 35736, "[iOS] Editor does not update Text value from autocorrect when losing focus", PlatformAffected.iOS)] + public class Bugzilla35736 : TestContentPage + { + protected override void Init() + { + var editor = new Editor + { + AutomationId = "Bugzilla35736Editor" + }; + var label = new Label + { + AutomationId = "Bugzilla35736Label", + Text = "" + }; + + Content = new StackLayout + { + Children = + { + editor, + label, + new Button + { + AutomationId = "Bugzilla35736Button", + Text = "Click to set label text", + Command = new Command(() => { label.Text = editor.Text; }) + } + } + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36009.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36009.cs new file mode 100644 index 000000000000..282c745073e1 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36009.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 36009, "Children of Layouts with data bound IsVisible are not displayed")] + public class Bugzilla36009 : TestContentPage // or TestFlyoutPage, etc ... + { + [Preserve(AllMembers = true)] + public class SampleViewModel : ViewModelBase + { + public bool IsContentVisible + { + get { return GetProperty(); } + set { SetProperty(value); } + } + } + + protected override void Init() + { + var boxview = new BoxView { BackgroundColor = Colors.Aqua, AutomationId = "Victory" }; + + var contentView = new ContentView + { + Content = boxview + }; + + contentView.SetBinding(IsVisibleProperty, "IsContentVisible"); + + var layout = new AbsoluteLayout + { + Children = { contentView } + }; + + Content = layout; + + var vm = new SampleViewModel(); + + BindingContext = vm; + + vm.IsContentVisible = true; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36559.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36559.cs new file mode 100644 index 000000000000..9ff2d76845ea --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36559.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 36559, "[WP] Navigating to a ContentPage with a Grid inside a TableView affects Entry heights")] + public class Bugzilla36559 : TestContentPage + { + protected override void Init() + { + var label = new Label { Text = "Label" }; + var entry = new Entry { AutomationId = "entry" }; + var grid = new Grid(); + + grid.Add(label, 0, 0); + grid.Add(entry, 1, 0); + var tableView = new TableView + { + Root = new TableRoot + { + new TableSection + { + new ViewCell + { + View = grid + } + } + } + }; + + Content = new StackLayout + { + Children = { tableView } + }; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36703.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36703.cs new file mode 100644 index 000000000000..c7a0e545ac14 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36703.cs @@ -0,0 +1,54 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 36703, + "TapGestureRecognizer inside initially disable Image will never fire Tapped event", PlatformAffected.All)] + public class Bugzilla36703 : TestContentPage + { + const string TestImage = "testimage"; + const string Success = "Success"; + const string Toggle = "toggle"; + const string Testing = "Testing..."; + + protected override void Init() + { + var image = new Image { Source = "coffee.png", IsEnabled = false, AutomationId = TestImage }; + var button = new Button { Text = $"Toggle IsEnabled (now {image.IsEnabled})", AutomationId = Toggle }; + var resultLabel = new Label { Text = "Testing..." }; + var instructions = new Label + { + Text = $"Tap the image. The '{Testing}' label should remain unchanged. " + + $"Tap the 'Toggle IsEnabled' button. Now tap the image again." + + $" The {Testing} Label should change its text to {Success}." + }; + + button.Clicked += (sender, args) => + { + image.IsEnabled = !image.IsEnabled; + button.Text = $"Toggle IsEnabled (now {image.IsEnabled})"; + }; + + Content = new StackLayout + { + Padding = new Thickness(0, 20, 0, 0), + Children = + { + instructions, resultLabel, + image, button + } + }; + + var tapGestureRecognizer = new TapGestureRecognizer(); + tapGestureRecognizer.Tapped += delegate + { + resultLabel.Text = Success; + }; + + image.GestureRecognizers.Add(tapGestureRecognizer); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36780.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36780.cs new file mode 100644 index 000000000000..ef12ab56ba88 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36780.cs @@ -0,0 +1,62 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 36780, "[iOS] Multiple TapGestureRecognizers on an Object Are Not Fired", PlatformAffected.iOS)] + public class Bugzilla36780 : TestContentPage + { + const string Gesture1Success = "Gesture1Success"; + const string Gesture2Success = "Gesture2Success"; + const string Gesture3Success = "Gesture3Success"; + const string Waiting = "Waiting"; + const string TestImage = "TestImage"; + + protected override void Init() + { + var gesture1Label = new Label { FontSize = 18, Text = Waiting }; + var gesture2Label = new Label { FontSize = 18, Text = Waiting }; + var gesture3Label = new Label { FontSize = 18, Text = Waiting }; + + var testImage = new Image { Source = "coffee.png", AutomationId = TestImage, HeightRequest = 75 }; + + testImage.GestureRecognizers.Add(new TapGestureRecognizer + { + Command = new Command(() => + { + gesture1Label.Text = Gesture1Success; + }) + }); + + testImage.GestureRecognizers.Add(new TapGestureRecognizer + { + Command = new Command(() => + { + gesture2Label.Text = Gesture2Success; + }) + }); + + testImage.GestureRecognizers.Add(new TapGestureRecognizer + { + Command = new Command(() => + { + gesture3Label.Text = Gesture3Success; + }) + }); + + Content = new StackLayout + { + Padding = new Thickness(0, 20, 0, 0), + Children = + { + gesture1Label, + gesture2Label, + gesture3Label, + testImage + } + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36788.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36788.cs new file mode 100644 index 000000000000..7951defdaab1 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36788.cs @@ -0,0 +1,120 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 36788, "Truncation Issues with Relative Layouts")] + public class Bugzilla36788 : TestContentPage // or TestFlyoutPage, etc ... + { + Label _resultLabel; + Label _testLabel; + View _container; + + protected override void Init() + { + // Initialize ui here instead of ctor + var stackLayout = new StackLayout + { + Spacing = 8 + }; + + var longString = "Very long text in single line to be truncated at tail. Adding extra text to make sure it gets truncated. And even more extra text because otherwise the test might fail if we're in, say, landscape orientation rather than portrait."; + + var contentView = new ContentView + { + Padding = 16, + BackgroundColor = Colors.Gray, + Content = new Label + { + BackgroundColor = Colors.Aqua, + Text = longString, + LineBreakMode = LineBreakMode.TailTruncation + } + }; + + stackLayout.Children.Add(contentView); + + contentView = new ContentView + { + Padding = 16, + BackgroundColor = Colors.Gray, + Content = new Microsoft.Maui.Controls.Compatibility.RelativeLayout + { + BackgroundColor = Colors.Navy, + Children = { + {new Label { + BackgroundColor = Colors.Blue, + Text = longString, + LineBreakMode = LineBreakMode.TailTruncation + }, Microsoft.Maui.Controls.Compatibility.Constraint.Constant (0)}, + {new Label { + BackgroundColor = Colors.Fuchsia, + Text = longString, + LineBreakMode = LineBreakMode.TailTruncation + }, Microsoft.Maui.Controls.Compatibility.Constraint.Constant (0), Microsoft.Maui.Controls.Compatibility.Constraint.Constant (40)}, + {new Label { + BackgroundColor = Colors.Fuchsia, + Text = longString, + LineBreakMode = LineBreakMode.TailTruncation + }, Microsoft.Maui.Controls.Compatibility.Constraint.Constant (10), Microsoft.Maui.Controls.Compatibility.Constraint.Constant (80)}, + } + } + }; + + stackLayout.Children.Add(contentView); + + contentView = new ContentView + { + Padding = 16, + BackgroundColor = Colors.Gray, + IsClippedToBounds = true, + Content = _container = new Microsoft.Maui.Controls.Compatibility.RelativeLayout + { + IsClippedToBounds = true, + BackgroundColor = Colors.Navy, + Children = { + {_testLabel = new Label { + BackgroundColor = Colors.Blue, + Text = longString, + LineBreakMode = LineBreakMode.TailTruncation + }, Microsoft.Maui.Controls.Compatibility.Constraint.Constant (0)}, + {new Label { + BackgroundColor = Colors.Fuchsia, + Text = longString, + LineBreakMode = LineBreakMode.TailTruncation + }, Microsoft.Maui.Controls.Compatibility.Constraint.Constant (0), Microsoft.Maui.Controls.Compatibility.Constraint.Constant (40)}, + {new Label { + BackgroundColor = Colors.Fuchsia, + Text = longString, + LineBreakMode = LineBreakMode.TailTruncation + }, Microsoft.Maui.Controls.Compatibility.Constraint.Constant (10), Microsoft.Maui.Controls.Compatibility.Constraint.Constant (80)}, + } + } + }; + + stackLayout.Children.Add(contentView); + + _resultLabel = new Label(); + stackLayout.Children.Add(_resultLabel); + + Content = stackLayout; + } + + protected override async void OnAppearing() + { + base.OnAppearing(); + await Task.Delay(200); + + double fuzzFactor = 15; // labels sometimes overflow slightly, thanks hinting + + if (Math.Abs(_testLabel.Width - _container.Width) < fuzzFactor) + _resultLabel.Text = "Passed"; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36802.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36802.cs new file mode 100644 index 000000000000..981c004bc663 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla36802.cs @@ -0,0 +1,78 @@ +using System.Collections.ObjectModel; +using System.Linq; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 36802, "[iOS] AccessoryView Partially Hidden When Using RecycleElement and GroupShortName", PlatformAffected.iOS)] + public class Bugzilla36802 : TestContentPage + { + const string Instructions = "On iOS, all the list items below should have an AccessoryView visible. If any are not visible or are covered by the section index list then this test has failed."; + ObservableCollection grouped { get; set; } + ListView lstView; + + public class AccessoryViewCell : ViewCell + { + public AccessoryViewCell() + { + var label = new Label(); + label.SetBinding(Label.TextProperty, "."); + View = label; + } + } + + public class GroupedItem : ObservableCollection + { + public string LongName { get; set; } + public string ShortName { get; set; } + } + + protected override void Init() + { + var label = new Label { Text = Instructions, AutomationId = "TestReady" }; + grouped = new ObservableCollection(); + lstView = new ListView(ListViewCachingStrategy.RecycleElement) + { + IsGroupingEnabled = true, + ItemTemplate = new DataTemplate(typeof(AccessoryViewCell)), + ItemsSource = grouped, + GroupDisplayBinding = new Binding("LongName"), + GroupShortNameBinding = new Binding("ShortName") + }; + + var grp1 = new GroupedItem() { LongName = "Group 1", ShortName = "1" }; + var grp2 = new GroupedItem() { LongName = "Group 2", ShortName = "2" }; + + for (int i = 1; i < 4; i++) + { + grp1.Add($"Item #{i}"); + grp2.Add($"Item #{i}"); + } + + grouped.Add(grp1); + grouped.Add(grp2); + + Content = new StackLayout + { + Children = { + label, + lstView + } + }; + } + +#if (UITEST && __IOS__) + [Test] + [Category(UITestCategories.ManualReview)] + [Compatibility.UITests.FailsOnMauiIOS] + public void Bugzilla36802Test() + { + RunningApp.WaitForElement("TestReady"); + RunningApp.Screenshot("AccessoryView partially hidden test"); + } +#endif + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla37625.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla37625.cs new file mode 100644 index 000000000000..4f753bae6ee7 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla37625.cs @@ -0,0 +1,26 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 37625, "App crashes when quickly adding/removing Image views (Windows UWP)")] + public class Bugzilla37625 : TestContentPage + { + protected override async void Init() + { + int retry = 5; + while (retry-- >= 0) + { + var imageUri = new Uri("https://raw.githubusercontent.com/xamarin/Xamarin.Forms/main/Microsoft.Maui.Controls.ControlGallery.Android/Assets/WebImages/XamarinLogo.png"); + Content = new Image() { Source = new UriImageSource() { Uri = imageUri }, BackgroundColor = Colors.Black, AutomationId = "success" }; + + await Task.Delay(50); + } + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla38723.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla38723.cs new file mode 100644 index 000000000000..81e41cfef904 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla38723.cs @@ -0,0 +1,52 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 38723, "Update Content in Picker's SelectedIndexChanged event causes NullReferenceException", PlatformAffected.All)] + public class Bugzilla38723 : TestContentPage + { + protected override void Init() + { + var label = new Label + { + Text = "NoSelected" + }; + + var picker = new Picker + { + Title = "Options", + ItemsSource = new[] { "option1", "option2", "option3" } + }; + + picker.SelectedIndexChanged += (sender, args) => + { + label.Text = "Selected"; + Content = label; + }; + + var button = new Button + { + AutomationId = "SELECT", + Text = "SELECT" + }; + + button.Clicked += (sender, args) => + { + picker.SelectedIndex = 0; + }; + + Content = new StackLayout + { + Children = + { + label, + picker, + button + } + }; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla38989.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla38989.cs new file mode 100644 index 000000000000..69979675e3e2 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla38989.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 38989, "[Android] NullReferenceException when using a custom ViewCellRenderer ", + PlatformAffected.Android)] + public class Bugzilla38989 : TestContentPage + { + const string Success = "If you can see this, the test passed."; + + protected override void Init() + { + var successLabel = new Label { Text = Success }; + + var lv = new ListView(); + var items = new List { "data", "does not", "matter" }; + + lv.ItemTemplate = new DataTemplate(typeof(_38989CustomViewCell)); + + lv.ItemsSource = items; + + Content = new StackLayout { Children = { successLabel, lv } }; + } + + [Preserve(AllMembers = true)] + public class _38989CustomViewCell : ViewCell + { + public _38989CustomViewCell() + { + var label = new Label(); + label.SetBinding(Label.TextProperty, "."); + + View = label; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39489.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39489.cs new file mode 100644 index 000000000000..e698aba8750c --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39489.cs @@ -0,0 +1,79 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Maps; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 39489, "Memory leak when using NavigationPage with Maps", PlatformAffected.Android | PlatformAffected.iOS)] + public class Bugzilla39489 : TestNavigationPage + { + protected override void Init() + { + PushAsync(new Bz39489Content()); + } + } + + public class Bz39489Map : Microsoft.Maui.Controls.Maps.Map + { + static int s_count; + + public Bz39489Map() + { + Interlocked.Increment(ref s_count); + Debug.WriteLine($"++++++++ Bz39489Map : Constructor, count is {s_count}"); + } + + ~Bz39489Map() + { + Interlocked.Decrement(ref s_count); + Debug.WriteLine($"-------- Bz39489Map: Destructor, count is {s_count}"); + } + } + + [Preserve(AllMembers = true)] + public class Bz39489Content : ContentPage + { + static int s_count; + + public Bz39489Content() + { + Interlocked.Increment(ref s_count); + Debug.WriteLine($">>>>> Bz39489Content Bz39489Content 54: Constructor, count is {s_count}"); + + var button = new Button { AutomationId = "NewPage", Text = "New Page" }; + + var gcbutton = new Button { AutomationId = "GC", Text = "GC" }; + + var map = new Bz39489Map(); + + button.Clicked += Button_Clicked; + gcbutton.Clicked += GCbutton_Clicked; + + Content = new StackLayout { Children = { button, gcbutton, map } }; + } + + void GCbutton_Clicked(object sender, EventArgs e) + { + System.Diagnostics.Debug.WriteLine(">>>>>>>> Running Garbage Collection"); + GarbageCollectionHelper.Collect(); + System.Diagnostics.Debug.WriteLine($">>>>>>>> GC.GetTotalMemory = {GC.GetTotalMemory(true):n0}"); + } + + void Button_Clicked(object sender, EventArgs e) + { + Navigation.PushAsync(new Bz39489Content()); + } + + ~Bz39489Content() + { + Interlocked.Decrement(ref s_count); + Debug.WriteLine($">>>>> Bz39489Content ~Bz39489Content 82: Destructor, count is {s_count}"); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39636.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39636.xaml new file mode 100644 index 000000000000..6616c2612368 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39636.xaml @@ -0,0 +1,41 @@ + + + + + + + + + + + + 80 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39636.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39636.xaml.cs new file mode 100644 index 000000000000..90f1bfe3a8ed --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39636.xaml.cs @@ -0,0 +1,21 @@ +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.Xaml; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 39636, "Cannot use XamlC with OnPlatform in resources, it throws System.InvalidCastException", PlatformAffected.All)] + [XamlCompilation(XamlCompilationOptions.Compile)] + public partial class Bugzilla39636 : TestContentPage + { + public Bugzilla39636() + { + InitializeComponent(); + } + + protected override void Init() + { + + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39668.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39668.cs new file mode 100644 index 000000000000..428d5527c9c5 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39668.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 39668, "Overriding ListView.CreateDefault Does Not Work on Windows", PlatformAffected.WinRT)] + public class Bugzilla39668 : TestContentPage + { + [Preserve(AllMembers = true)] + public class CustomListView : ListView + { + protected override Cell CreateDefault(object item) + { + var cell = new ViewCell(); + + cell.View = new StackLayout + { + BackgroundColor = Colors.Green, + Children = { + new Label { Text = "Success" } + } + }; + + return cell; + } + } + + protected override void Init() + { + CustomListView lv = new CustomListView() + { + ItemsSource = Enumerable.Range(0, 10) + }; + Content = new StackLayout { Children = { new Label { Text = "If the ListView does not have green Cells, this test has failed." }, lv } }; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39702.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39702.cs new file mode 100644 index 000000000000..97cda4c82b56 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39702.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 39702, "Cannot enter text when Entry is focus()'d from an editor completed event")] + public class Bugzilla39702 : TestContentPage + { + const string TheEntry = "TheEntry"; + const string Success = "Success"; + + protected override async void Init() + { + Title = "focus test"; + var editor = new Editor(); + var entry = new Entry { AutomationId = TheEntry }; + var result = new Label(); + + var instructions = new Label + { + Text = "Wait 4 seconds; the Entry (third control from the top) should be focused, and the keyboard" + + " should be visible. Typing on the keyboard should enter text into the Entry." + + " If the typing does not enter text into the Entry, this test has failed." + }; + + editor.Unfocused += (sender, e) => entry.Focus(); + entry.TextChanged += (sender, args) => result.Text = args.NewTextValue; + + Content = new StackLayout + { + Children = + { + instructions, + editor, + entry, + result + } + }; + + await Task.Delay(2000); + editor.Focus(); + await Task.Delay(1000); + editor.Unfocus(); + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39821.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39821.cs new file mode 100644 index 000000000000..7c492603c80c --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla39821.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 39821, "ViewExtension.TranslateTo cannot be invoked on Main thread")] + public class Bugzilla39821 : TestContentPage + { + protected override void Init() + { + var box = new BoxView { BackgroundColor = Colors.Blue, WidthRequest = 50, HeightRequest = 50, HorizontalOptions = LayoutOptions.Center }; + + var instructions = new Label { Text = "Click the 'Animate' button to run animation on the box. If the animations complete without crashing, this test has passed." }; + + var success = new Label { Text = "Success", IsVisible = false }; + + var button = new Button() { AutomationId = "Animate", Text = "Animate" }; + + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Fill, + HorizontalOptions = LayoutOptions.Fill, + Children = + { + instructions, + success, + button, + new AbsoluteLayout + { + Children = { box }, + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill + } + } + }; + + button.Clicked += async (sender, args) => + { + // Run a bunch of animations from the thread pool + await Task.WhenAll( + Task.Run(async () => await Translate(box)), + Task.Run(async () => await CheckTranslateRunning(box)), + Task.Run(async () => await AnimateScale(box)), + Task.Run(async () => await Rotate(box)), + Task.Run(async () => await Animate(box)), + Task.Run(async () => await Kinetic(box)), + Task.Run(async () => await Cancel(box)) + ); + + success.IsVisible = true; + }; + } + +#pragma warning disable 1998 // considered for removal + async Task CheckTranslateRunning(BoxView box) +#pragma warning restore 1998 + { + Debug.WriteLine(box.AnimationIsRunning("TranslateTo") ? "Translate is running" : "Translate is not running"); + } + + static async Task Translate(BoxView box) + { + var currentX = box.X; + var currentY = box.Y; + + await box.TranslateTo(currentX, currentY + 100); + await box.TranslateTo(currentX, currentY); + } + + static async Task AnimateScale(BoxView box) + { + await box.ScaleTo(2); + await box.ScaleTo(0.5); + } + + static async Task Rotate(BoxView box) + { + await box.RelRotateTo(360); + } + +#pragma warning disable 1998 // considered for removal + async Task Cancel(BoxView box) +#pragma warning restore 1998 + { + box.AbortAnimation("animate"); + box.AbortAnimation("kinetic"); + } + +#pragma warning disable 1998 // considered for removal + async Task Animate(BoxView box) +#pragma warning restore 1998 + { + box.Animate("animate", d => d, d => { }, 100, 1); + } + +#pragma warning disable 1998 // considered for removal + async Task Kinetic(BoxView box) +#pragma warning restore 1998 + { + var resultList = new List>(); + + box.AnimateKinetic("kinetic", (distance, velocity) => + { + resultList.Add(new Tuple(distance, velocity)); + return true; + }, 100, 1); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla40005.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla40005.cs new file mode 100644 index 000000000000..393961f8c900 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla40005.cs @@ -0,0 +1,136 @@ +using System.Diagnostics; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 40005, "Navigation Bar back button does not show when using InsertPageBefore")] + public class Bugzilla40005 : NavigationPage + { + public Bugzilla40005() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public const string GoToPage2 = "Go to Page 2"; + public const string PageOneLabel = "Page 1"; + public const string PageTwoLabel = "Page 2"; + public const string InsertedPageLabel = "Inserted page"; + public const string TestInstructions = "Click " + GoToPage2 + " and you should still see a back bar button"; + + public MainPage() + { + Application.Current.MainPage = new NavigationPage(new Page1()); + } + + public class Page1 : ContentPage + { + bool pageInserted; + + public Page1() + { + var btn = new Button() + { + AutomationId = GoToPage2, + Text = GoToPage2 + }; + btn.Clicked += async (sender, e) => + { + await Navigation.PushAsync(new Page2()); + }; + + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = + { + new Label + { + AutomationId = PageOneLabel, + HorizontalTextAlignment = TextAlignment.Center, + Text = PageOneLabel + }, + btn, + new Label + { + AutomationId = TestInstructions, + HorizontalTextAlignment = TextAlignment.Center, + Text = TestInstructions + } + } + }; + } + + protected override void OnAppearing() + { + base.OnAppearing(); + if (!pageInserted) + { + Navigation.InsertPageBefore(new InsertedPage(), this); + pageInserted = true; + } + } + + protected override bool OnBackButtonPressed() + { + Debug.WriteLine($"Hardware BackButton Pressed on {PageOneLabel}"); + return base.OnBackButtonPressed(); + } + } + + public class InsertedPage : ContentPage + { + public InsertedPage() + { + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = + { + new Label + { + HorizontalTextAlignment = TextAlignment.Center, + Text = InsertedPageLabel + } + } + }; + } + + protected override bool OnBackButtonPressed() + { + Debug.WriteLine($"Hardware BackButton Pressed on {InsertedPageLabel}"); + return base.OnBackButtonPressed(); + } + } + + public class Page2 : ContentPage + { + public Page2() + { + Content = new StackLayout + { + VerticalOptions = LayoutOptions.Center, + Children = + { + new Label + { + AutomationId = PageTwoLabel, + HorizontalTextAlignment = TextAlignment.Center, + Text = PageTwoLabel + } + } + }; + } + + protected override bool OnBackButtonPressed() + { + Debug.WriteLine($"Hardware BackButton Pressed on {PageTwoLabel}"); + return base.OnBackButtonPressed(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41205.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41205.cs new file mode 100644 index 000000000000..08f77a92087e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41205.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 41205, "UWP CreateDefault passes string instead of object")] + public class Bugzilla41205 : TestContentPage + { + const string _success = "Pass"; + + [Preserve(AllMembers = true)] + public class ViewModel + { + public string Text { get { return _success; } } + } + + [Preserve(AllMembers = true)] + public class CustomListView : ListView + { + protected override Cell CreateDefault(object item) + { + if (item is ViewModel) + { + var newTextCell = new TextCell(); + newTextCell.SetBinding(TextCell.TextProperty, nameof(ViewModel.Text)); + return newTextCell; + } + return base.CreateDefault("Fail"); + } + } + + protected override void Init() + { + var listView = new CustomListView + { + ItemsSource = new[] + { + new ViewModel(), + new ViewModel(), + } + }; + + Content = listView; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41600.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41600.cs new file mode 100644 index 000000000000..5239597ae377 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41600.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 41600, "[Android] Invalid item param value for ScrollTo throws an error", PlatformAffected.Android)] + public class Bugzilla41600 : TestContentPage + { + const string _btnScrollToNonExistentItem = "btnScrollToNonExistentItem"; + const string _btnScrollToExistentItem = "btnScrollToExistentItem"; + const string _firstListItem = "0"; + const string _middleListItem = "15"; + + protected override void Init() + { + var items = new List(); + for (var i = 0; i <= 30; i++) + items.Add(i.ToString()); + + var listView = new ListView + { + ItemsSource = items + }; + Content = new StackLayout + { + Children = + { + listView, + new Button + { + AutomationId = _btnScrollToNonExistentItem, + Text = "Click for ScrollTo (should do nothing)", + Command = new Command(() => + { + listView.ScrollTo("Hello", ScrollToPosition.Start, true); + }) + }, + new Button + { + AutomationId = _btnScrollToExistentItem, + Text = "Click for ScrollTo (should go to 15)", + Command = new Command(() => + { + listView.ScrollTo(_middleListItem, ScrollToPosition.Start, false); + }) + } + } + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41619.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41619.cs new file mode 100644 index 000000000000..78b7d31d70b2 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41619.cs @@ -0,0 +1,60 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 41619, "[WinRT/UWP] Slider binding works incorrectly", PlatformAffected.WinRT)] + public class Bugzilla41619 : TestContentPage + { + const double _success = 6; + protected override void Init() + { + var vm = new Bugzilla41619ViewModel(); + BindingContext = vm; + var label = new Label(); + label.SetBinding(Label.TextProperty, "SliderValue"); + var slider = new Slider + { + Maximum = 10, + Minimum = 1, + }; + slider.SetBinding(Slider.ValueProperty, "SliderValue", BindingMode.TwoWay); + Content = new StackLayout + { + Children = + { + label, + slider, + new Label { Text = $"The initial slider value above should be {_success}." } + } + }; + } + + [Preserve(AllMembers = true)] + class Bugzilla41619ViewModel : INotifyPropertyChanged + { + private double _sliderValue = _success; + + public double SliderValue + { + get { return _sliderValue; } + set + { + _sliderValue = value; + OnPropertyChanged(); + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41842.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41842.cs new file mode 100644 index 000000000000..0bb387af1a17 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla41842.cs @@ -0,0 +1,20 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 41842, "Set FlyoutPage.Detail = New Page() twice will crash the application when set FlyoutLayoutBehavior = FlyoutLayoutBehavior.Split", PlatformAffected.WinRT)] + public class Bugzilla41842 : TestFlyoutPage + { + protected override void Init() + { + FlyoutLayoutBehavior = FlyoutLayoutBehavior.Split; + + Flyout = new Page() { Title = "Flyout" }; + + Detail = new NavigationPage(new Page()); + Detail = new NavigationPage(new ContentPage { Content = new Label { AutomationId = "Success", Text = "Success" } }); + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla42277.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla42277.cs new file mode 100644 index 000000000000..67a6f413e49e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla42277.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 42277, "DataTemplate System.InvalidCastException crash in 2.3.1-pre1")] + public class Bugzilla42277 : TestContentPage + { + const string Success1 = "Success1"; + const string Success2 = "Success2"; + const string Success3 = "GroupedSuccess3"; + const string Success4 = "GroupedSuccess4"; + const string Success5 = "GroupedSuccess5"; + const string Success6 = "GroupedSuccess6"; + + class MyDataTemplateSelector : DataTemplateSelector + { + DataTemplate _1Template; + DataTemplate _2Template; + + DataTemplate _3Template; + DataTemplate _4Template; + DataTemplate _5Template; + DataTemplate _6Template; + + public MyDataTemplateSelector() + { + _1Template = new DataTemplate(() => + { + return new TextCell { AutomationId = Success1, Text = Success1 }; + }); + + _2Template = new DataTemplate(() => + { + return new TextCell { AutomationId = Success2, Text = Success2 }; + }); + + _3Template = new DataTemplate(() => + { + return new TextCell { AutomationId = Success3, Text = Success3 }; + }); + + _4Template = new DataTemplate(() => + { + return new TextCell { AutomationId = Success4, Text = Success4 }; + }); + + _5Template = new DataTemplate(() => + { + return new TextCell { AutomationId = Success5, Text = Success5 }; + }); + + _6Template = new DataTemplate(() => + { + return new TextCell { AutomationId = Success6, Text = Success6 }; + }); + } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + int number = (int)item; + switch (number) + { + default: + case 0: + return _1Template; + case 1: + return _2Template; + case 2: + return _3Template; + case 3: + return _4Template; + case 4: + return _5Template; + case 5: + return _6Template; + } + } + } + + protected override void Init() + { + //test non-grouped DTS + ListView listView = new ListView(ListViewCachingStrategy.RecycleElement) + { + ItemsSource = Enumerable.Range(0, 2), + ItemTemplate = new MyDataTemplateSelector() + }; + + //test grouped DTS + ListView groupedListView = new ListView(ListViewCachingStrategy.RecycleElement) + { + ItemsSource = new List> { Enumerable.Range(2, 2).ToList(), Enumerable.Range(4, 2).ToList() }, + IsGroupingEnabled = true, + ItemTemplate = new MyDataTemplateSelector() + }; + + Content = new StackLayout { Children = { listView, groupedListView } }; + + //test collection changed + listView.ItemsSource = Enumerable.Range(0, 2); + groupedListView.ItemsSource = new List> { Enumerable.Range(2, 2).ToList(), Enumerable.Range(4, 2).ToList() }; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla42956.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla42956.cs new file mode 100644 index 000000000000..8942d3e24e8d --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla42956.cs @@ -0,0 +1,129 @@ +using System; +using System.Linq; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 42956, "ListView with DataTemplateSelector can have only 17 Templates, even with CachingStrategy=RetainElement", PlatformAffected.Android)] + public class Bugzilla42956 : TestContentPage + { + const string Success = "Success"; + + class MyDataTemplateSelector : DataTemplateSelector + { + readonly DataTemplate one; + readonly DataTemplate two; + readonly DataTemplate three; + readonly DataTemplate four; + readonly DataTemplate five; + readonly DataTemplate six; + readonly DataTemplate seven; + readonly DataTemplate eight; + readonly DataTemplate nine; + readonly DataTemplate ten; + readonly DataTemplate eleven; + readonly DataTemplate twelve; + readonly DataTemplate thirteen; + readonly DataTemplate fourteen; + readonly DataTemplate fifteen; + readonly DataTemplate sixteen; + readonly DataTemplate seventeen; + readonly DataTemplate eighteen; + readonly DataTemplate nineteen; + readonly DataTemplate twenty; + + public MyDataTemplateSelector() + { + one = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the one!" } }); + two = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the two!" } }); + three = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the three!" } }); + four = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the four!" } }); + five = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the five!" } }); + six = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the six!" } }); + seven = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the seven!" } }); + eight = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the eight!" } }); + nine = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the nine!" } }); + ten = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the ten!" } }); + eleven = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the eleven!" } }); + twelve = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the twelve!" } }); + thirteen = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the thirteen!" } }); + fourteen = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the fourteen!" } }); + fifteen = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the fifteen!" } }); + sixteen = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the sixteen!" } }); + seventeen = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the seventeen!" } }); + eighteen = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the eighteen!" } }); + nineteen = new DataTemplate(() => new ViewCell { View = new Label { Text = "I am the nineteen! Is this how I should be databinding? Whatev." } }); + twenty = new DataTemplate(() => new ViewCell { View = new Label { AutomationId = Success, Text = Success } }); + } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + var val = (int)item; + + switch (val) + { + case 1: + return one; + case 2: + return two; + case 3: + return three; + case 4: + return four; + case 5: + return five; + case 6: + return six; + case 7: + return seven; //not six + case 8: + return eight; + case 9: + return nine; + case 10: + return ten; + case 11: + return eleven; + case 12: + return twelve; + case 13: + return thirteen; + case 14: + return fourteen; + case 15: + return fifteen; + case 16: + return sixteen; + case 17: + return seventeen; + case 18: + return eighteen; + case 19: + default: + return nineteen; + case 75: + return twenty; + } + } + } + + protected override void Init() + { + var dts = new MyDataTemplateSelector(); + var listView = new ListView + { + ItemsSource = Enumerable.Range(0, 100), + ItemTemplate = dts + }; + + var layout = new StackLayout { Children = { listView } }; + + Content = layout; + + listView.ScrollTo(75, ScrollToPosition.MakeVisible, true); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla43519.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla43519.cs new file mode 100644 index 000000000000..43795946c336 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla43519.cs @@ -0,0 +1,72 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 43519, "[UWP] FlyoutPage ArgumentException when nested in a TabbedPage and returning from modal page" + , PlatformAffected.UWP)] + public class Bugzilla43519 : TestTabbedPage + { + const string Pop = "PopModal"; + + const string Push = "PushModal"; + + const string Page2 = "Page 2"; + + protected override void Init() + { + var modalPage = new ContentPage + { + Title = "ModalPage", + Content = new StackLayout + { + Children = + { + new Button + { + Command = new Command(() => Navigation.PopModalAsync()), + Text = "Pop modal page -- should not crash on UWP", + AutomationId = Pop + } + } + } + }; + + var mdp = new FlyoutPage + { + Title = "Page 1", + Flyout = new ContentPage + { + Title = "Flyout", + Content = new StackLayout() + }, + Detail = new ContentPage + { + Title = "Detail", + Content = new StackLayout() + } + }; + + Children.Add(mdp); + Children.Add(new ContentPage + { + AutomationId = Page2, + Title = Page2, + Content = new StackLayout + { + Children = + { + new Button + { + Command = new Command(() => Navigation.PushModalAsync(modalPage)), + Text = "Click to display modal", + AutomationId = Push + } + } + } + }); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44096.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44096.cs new file mode 100644 index 000000000000..42ddb50afca9 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44096.cs @@ -0,0 +1,140 @@ +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 44096, "Grid, StackLayout, and ContentView still participate in hit testing on " + + "Android after IsEnabled is set to false", PlatformAffected.Android)] + public class Bugzilla44096 : TestContentPage + { + bool _flag; + const string Child = "Child"; + const string Original = "Original"; + const string ToggleColor = "color"; + const string ToggleIsEnabled = "disabled"; + + const string StackLayout = "stackLayout"; + const string ContentView = "contentView"; + const string Grid = "grid"; + const string RelativeLayout = "relativeLayout"; + + protected override void Init() + { + var result = new Label + { + Text = Original + }; + + var grid = new Grid + { + IsEnabled = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = Grid + }; + AddTapGesture(result, grid); + + var contentView = new ContentView + { + IsEnabled = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = ContentView + }; + AddTapGesture(result, contentView); + + var stackLayout = new StackLayout + { + IsEnabled = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = StackLayout + }; + AddTapGesture(result, stackLayout); + + var relativeLayout = new Microsoft.Maui.Controls.Compatibility.RelativeLayout + { + IsEnabled = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = RelativeLayout + }; + AddTapGesture(result, relativeLayout); + + var color = new Button + { + Text = "Toggle colors", + Command = new Command(() => + { + if (!_flag) + { + grid.BackgroundColor = Colors.Red; + contentView.BackgroundColor = Colors.Blue; + stackLayout.BackgroundColor = Colors.Yellow; + relativeLayout.BackgroundColor = Colors.Green; + } + else + { + grid.BackgroundColor = null; + contentView.BackgroundColor = null; + stackLayout.BackgroundColor = null; + relativeLayout.BackgroundColor = null; + } + + _flag = !_flag; + }), + AutomationId = ToggleColor + }; + + var disabled = new Button + { + Text = "Toggle IsEnabled", + Command = new Command(() => + { + grid.IsEnabled = false; + contentView.IsEnabled = false; + stackLayout.IsEnabled = false; + relativeLayout.IsEnabled = false; + + result.Text = Original; + }), + AutomationId = ToggleIsEnabled + }; + + var parent = new StackLayout + { + Spacing = 10, + Orientation = StackOrientation.Vertical, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + Children = + { + color, + disabled, + result, + grid, + contentView, + stackLayout, + relativeLayout + } + }; + + Content = parent; + } + + void AddTapGesture(Label result, View view) + { + var tapGestureRecognizer = new TapGestureRecognizer + { + Command = new Command(() => + { + result.Text = Child; + }) + }; + view.GestureRecognizers.Add(tapGestureRecognizer); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44176.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44176.cs new file mode 100644 index 000000000000..bd23cde8bdba --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44176.cs @@ -0,0 +1,113 @@ +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 44176, "InputTransparent fails if BackgroundColor not explicitly set on Android", PlatformAffected.Android)] + public class Bugzilla44176 : TestContentPage + { + bool _flag; + + protected override void Init() + { + var result = new Label(); + + var grid = new Grid + { + InputTransparent = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = "grid" + }; + AddTapGesture(result, grid); + + var contentView = new ContentView + { + InputTransparent = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = "contentView" + }; + AddTapGesture(result, contentView); + + var stackLayout = new StackLayout + { + InputTransparent = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = "stackLayout" + }; + AddTapGesture(result, stackLayout); + + var color = new Button + { + Text = "Toggle colors", + Command = new Command(() => + { + if (!_flag) + { + grid.BackgroundColor = Colors.Red; + contentView.BackgroundColor = Colors.Blue; + stackLayout.BackgroundColor = Colors.Yellow; + } + else + { + grid.BackgroundColor = null; + contentView.BackgroundColor = null; + stackLayout.BackgroundColor = null; + } + + _flag = !_flag; + }), + AutomationId = "color" + }; + + var nonTransparent = new Button + { + Text = "Non-transparent", + Command = new Command(() => + { + grid.InputTransparent = false; + contentView.InputTransparent = false; + stackLayout.InputTransparent = false; + }), + AutomationId = "nontransparent" + }; + + var parent = new StackLayout + { + Spacing = 10, + Orientation = StackOrientation.Vertical, + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + Children = + { + color, + nonTransparent, + result, + grid, + contentView, + stackLayout + } + }; + AddTapGesture(result, parent, true); + + Content = parent; + } + + void AddTapGesture(Label result, View view, bool isParent = false) + { + var tapGestureRecognizer = new TapGestureRecognizer + { + Command = new Command(() => + { + result.Text = !isParent ? "Child" : "Parent"; + }) + }; + view.GestureRecognizers.Add(tapGestureRecognizer); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44476.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44476.cs new file mode 100644 index 000000000000..f05f0b0de9ff --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla44476.cs @@ -0,0 +1,60 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 44476, "[Android] Unwanted margin at top of details page when nested in a NavigationPage")] + public class Bugzilla44476 : NavigationPage + { + public Bugzilla44476() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + BackgroundColor = Colors.Maroon; +#pragma warning disable CS0618 // Type or member is obsolete + Navigation.PushAsync(new FlyoutPage + { + Title = "Bugzilla Issue 44476", + Flyout = new ContentPage + { + Title = "Flyout", + Content = new StackLayout + { + Children = + { + new Label { Text = "Flyout" } + } + } + }, + Detail = new ContentPage + { + Title = "Detail", + Content = new StackLayout + { + VerticalOptions = LayoutOptions.FillAndExpand, + Children = + { + new Label { Text = "Detail Page" }, + new StackLayout + { + VerticalOptions = LayoutOptions.EndAndExpand, + Children = + { + new Label { Text = "This should be visible." } + } + } + } + } + }, + }); +#pragma warning restore CS0618 // Type or member is obsolete + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla45702.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla45702.cs new file mode 100644 index 000000000000..5ab1d084590f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla45702.cs @@ -0,0 +1,49 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 45702, "Disabling back press on modal page causes app to crash", PlatformAffected.Android)] + public class Bugzilla45702 : NavigationPage + { + public Bugzilla45702() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + Navigation.PushAsync(new NavigationPage(new FlyoutPage() { Flyout = new ContentPage() { Title = "Flyout" }, Detail = new DetailPage45702() })); + +#pragma warning disable CS0618 // Type or member is obsolete + MessagingCenter.Subscribe(this, "switch", SwitchControl); +#pragma warning restore CS0618 // Type or member is obsolete + } + + void SwitchControl(object sender) + { + Application.Current.MainPage = new NavigationPage(new ContentPage { Content = new Label { Text = "Success" } }); + } + + [Preserve(AllMembers = true)] + class DetailPage45702 : ContentPage + { + public DetailPage45702() + { + var button = new Button { AutomationId = "ClickMe", Text = "Click me" }; + button.Clicked += Button_Clicked; + Content = button; + } + + void Button_Clicked(object sender, System.EventArgs e) + { +#pragma warning disable CS0618 // Type or member is obsolete + MessagingCenter.Send(this, "switch"); +#pragma warning restore CS0618 // Type or member is obsolete + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla45722.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla45722.cs new file mode 100644 index 000000000000..2eee843b9b9d --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla45722.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 45722, "Memory leak in Xamarin Forms ListView", PlatformAffected.UWP)] + public class Bugzilla45722 : TestContentPage + { + const string Success = "Success"; + const string Running = "Running..."; + const string Update = "Update List"; + const string Collect = "GC"; + + const int ItemCount = 10; + + Label _currentLabelCount; + Label _statusLabel; + + protected override void Init() + { + _currentLabelCount = new Label(); + _statusLabel = new Label { Text = Running }; + +#pragma warning disable CS0618 // Type or member is obsolete + MessagingCenter.Subscribe<_45722Label>(this, _45722Label.CountMessage, sender => + { +#pragma warning disable CS0612 // Type or member is obsolete + Device.BeginInvokeOnMainThread(() => + { + _currentLabelCount.Text = _45722Label.Count.ToString(); + _statusLabel.Text = _45722Label.Count - ItemCount <= 0 ? Success : Running; + }); +#pragma warning restore CS0612 // Type or member is obsolete + }); +#pragma warning restore CS0618 // Type or member is obsolete + + var lv = new ListView(ListViewCachingStrategy.RetainElement); + + var items = new ObservableCollection<_45722Model>(); + + foreach (var item in CreateItems()) + { + items.Add(item); + } + + var dt = new DataTemplate(() => + { + var layout = new Grid(); + + var label = new _45722Label(); + label.SetBinding(Label.TextProperty, new Binding("Text")); + + var bt = new Button { Text = "Go" }; + bt.SetBinding(Button.CommandProperty, new Binding("Command")); + + var en = new Entry { Text = "entry" }; + + layout.Children.Add(bt); + layout.Children.Add(en); + layout.Children.Add(label); + + Grid.SetRow(bt, 1); + Grid.SetRow(en, 2); + + return new ViewCell { View = layout }; + }); + + lv.ItemsSource = items; + lv.ItemTemplate = dt; + + var button = new Button { AutomationId = Update, Text = Update }; + button.Clicked += (sender, args) => + { + items.Clear(); + foreach (var item in CreateItems()) + { + items.Add(item); + } + }; + + var collect = new Button() { AutomationId = Collect, Text = Collect }; + collect.Clicked += (sender, args) => + { + GarbageCollectionHelper.Collect(); + }; + + Title = "Bugzilla 45722"; + Content = new StackLayout + { + Padding = new Thickness(0, 20, 0, 0), + Children = { _currentLabelCount, _statusLabel, button, collect, lv } + }; + } + + [Preserve(AllMembers = true)] + public class _45722Model : INotifyPropertyChanged + { + string _text; + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged1([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public _45722Model(string text) + { + _text = text; + Command = new Command(() => Debug.WriteLine($">>>>> _45722Model Command Running")); + } + + public string Text + { + get { return _text; } + set + { + _text = value; + OnPropertyChanged1(); + } + } + + public Command Command { get; } + } + + static IEnumerable<_45722Model> CreateItems() + { + var r = new Random(DateTime.Now.Millisecond); + for (int n = 0; n < ItemCount; n++) + { + yield return new _45722Model(r.NextDouble().ToString(CultureInfo.InvariantCulture)); + } + } + + protected override void OnDisappearing() + { +#pragma warning disable CS0618 // Type or member is obsolete + MessagingCenter.Unsubscribe<_45722Label>(this, _45722Label.CountMessage); +#pragma warning restore CS0618 // Type or member is obsolete + base.OnDisappearing(); + } + } + + [Preserve(AllMembers = true)] + public class _45722Label : Label + { + public static int Count; + public const string CountMessage = "45722Count"; + + public _45722Label() + { + Interlocked.Increment(ref Count); +#pragma warning disable CS0618 // Type or member is obsolete + MessagingCenter.Send(this, CountMessage); +#pragma warning restore CS0618 // Type or member is obsolete + } + + ~_45722Label() + { + Interlocked.Decrement(ref Count); +#pragma warning disable CS0618 // Type or member is obsolete + MessagingCenter.Send(this, CountMessage); +#pragma warning restore CS0618 // Type or member is obsolete + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla46458.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla46458.cs new file mode 100644 index 000000000000..d64c01c816f0 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla46458.cs @@ -0,0 +1,90 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 46458, "Grid.IsEnabled property is not working", PlatformAffected.Android)] + public class Bugzilla46458 : TestContentPage + { + protected override void Init() + { + var parentGrid = new Grid + { + BackgroundColor = Colors.Yellow + }; + parentGrid.RowDefinitions.Add(new RowDefinition()); + parentGrid.RowDefinitions.Add(new RowDefinition()); + + var grid = new Grid + { + IsEnabled = false, + BackgroundColor = Colors.Red + }; + + grid.RowDefinitions.Add(new RowDefinition()); + grid.RowDefinitions.Add(new RowDefinition()); + grid.RowDefinitions.Add(new RowDefinition()); + + var label = new Label + { + HorizontalOptions = LayoutOptions.Center, + Text = "Success" + }; + Grid.SetRow(label, 0); + grid.Children.Add(label); + + var entry = new Entry + { + HorizontalOptions = LayoutOptions.Center, + HeightRequest = 50, + WidthRequest = 250, + Placeholder = "Placeholder", + AutomationId = "entry" + }; + Grid.SetRow(entry, 1); + entry.Focused += (sender, args) => { label.Text = "Fail"; }; + grid.Children.Add(entry); + + var button = new Button + { + WidthRequest = 250, + HeightRequest = 50, + BackgroundColor = Colors.Black, + TextColor = Colors.White, + Text = "Click", + HorizontalOptions = LayoutOptions.Center, + Command = new Command(() => { label.Text = "Fail"; }), + AutomationId = "button" + }; + Grid.SetRow(button, 2); + grid.Children.Add(button); + + parentGrid.Children.Add(grid); + Grid.SetRow(grid, 1); + + var button1 = new Button + { + WidthRequest = 250, + HeightRequest = 50, + BackgroundColor = Colors.Black, + TextColor = Colors.White, + Text = "Test transparency", + HorizontalOptions = LayoutOptions.Center, + AutomationId = "button1" + }; + button1.Command = new Command((sender) => + { + grid.IsEnabled = true; + grid.InputTransparent = true; + button1.Text = "Clicked"; + }); + Grid.SetRow(button1, 0); + parentGrid.Children.Add(button1); + + Content = parentGrid; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla51238.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla51238.cs new file mode 100644 index 000000000000..97e50d75206d --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla51238.cs @@ -0,0 +1,54 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 51238, + "Transparent Grid causes Java.Lang.IllegalStateException: Unable to create layer for Platform_DefaultRenderer", + PlatformAffected.Android)] + public class Bugzilla51238 : TestContentPage + { + protected override void Init() + { + var grid = new Grid(); + grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star }); + grid.RowDefinitions.Add(new RowDefinition { Height = 50 }); + + var transparentLayer = new Grid(); + transparentLayer.IsVisible = false; + transparentLayer.BackgroundColor = Colors.Lime; + transparentLayer.Opacity = 0.5; + + var label = new Label + { + Text = "Foo", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center + }; + + Grid.SetRow(label, 0); + Grid.SetRow(transparentLayer, 0); + + var button = new Button + { + AutomationId = "TapMe", + Text = "Tap Me!", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center + }; + + Grid.SetRow(button, 1); + + button.Clicked += (sender, args) => { transparentLayer.IsVisible = !transparentLayer.IsVisible; }; + + grid.Children.Add(label); + grid.Children.Add(transparentLayer); + grid.Children.Add(button); + + Content = grid; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla51503.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla51503.cs new file mode 100644 index 000000000000..2a77d891bd0a --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla51503.cs @@ -0,0 +1,64 @@ +using System; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 51503, "NullReferenceException on VisualElement Finalize", PlatformAffected.All)] + public class Bugzilla51503 : NavigationPage + { + public Bugzilla51503() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + Navigation.PushAsync(new _51503RootPage()); + } + + [Preserve(AllMembers = true)] + class _51503RootPage : ContentPage + { + public _51503RootPage() + { + Button button = new Button + { + AutomationId = "Button", + Text = "Open" + }; + + button.Clicked += Button_Clicked; + + Content = button; + } + + async void Button_Clicked(object sender, EventArgs e) + { + GarbageCollectionHelper.Collect(); + + await Navigation.PushAsync(new ChildPage()); + } + } + + [Preserve(AllMembers = true)] + class ChildPage : ContentPage + { + public ChildPage() + { + Content = new Label + { + AutomationId = "VisualElement", + Text = "Navigate 3 times to this page", + Triggers = + { + new EventTrigger() + } + }; + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla52533.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla52533.cs new file mode 100644 index 000000000000..05c1741bba2e --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla52533.cs @@ -0,0 +1,46 @@ +using System.Linq; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 52533, "System.ArgumentException: NaN is not a valid value for width", PlatformAffected.iOS)] + public class Bugzilla52533 : TestContentPage + { + const string LabelId = "label"; + + protected override void Init() + { + Content = new ListView { ItemTemplate = new DataTemplate(typeof(GridViewCell)), ItemsSource = Enumerable.Range(0, 10) }; + } + + [Preserve(AllMembers = true)] + class GridViewCell : ViewCell + { + + public GridViewCell() + { + var grid = new Grid + { + // Multiple rows + RowDefinitions = { + new RowDefinition { Height = new GridLength(20, GridUnitType.Absolute) }, + new RowDefinition { Height = new GridLength(150, GridUnitType.Absolute) } + }, + // Dynamic width + ColumnDefinitions = { + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) } + } + }; + + // Infinitely wide + Label + var horStack = new StackLayout { Orientation = StackOrientation.Horizontal, Children = { new Label { Text = "If this does not crash, this test has passed.", AutomationId = LabelId } } }; + grid.Add(horStack, 0, 0); + + View = grid; + } + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53179.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53179.cs new file mode 100644 index 000000000000..971a444e6b1f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53179.cs @@ -0,0 +1,71 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 53179, + "PopAsync crashing after RemovePage when support packages are updated to 25.1.1", PlatformAffected.Android)] + public class Bugzilla53179 : NavigationPage + { + public Bugzilla53179() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + Navigation.PushAsync(new TestPage(1)); + } + + class TestPage : ContentPage + { + Button nextBtn, rmBtn, popBtn; + + public TestPage(int index) + { + nextBtn = new Button { AutomationId = "Next Page", Text = "Next Page" }; + rmBtn = new Button { AutomationId = "Remove previous pages", Text = "Remove previous pages" }; + popBtn = new Button { AutomationId = "Back", Text = "Back" }; + + nextBtn.Clicked += async (sender, e) => await Navigation.PushAsync(new TestPage(index + 1)); + rmBtn.Clicked += (sender, e) => + { + var stackSize = Navigation.NavigationStack.Count; + Navigation.RemovePage(Navigation.NavigationStack[stackSize - 2]); + + stackSize = Navigation.NavigationStack.Count; + Navigation.RemovePage(Navigation.NavigationStack[stackSize - 2]); + + popBtn.IsVisible = true; + rmBtn.IsVisible = false; + }; + popBtn.Clicked += async (sender, e) => await Navigation.PopAsync(); + + switch (index) + { + case 4: + nextBtn.IsVisible = false; + popBtn.IsVisible = false; + break; + default: + rmBtn.IsVisible = false; + popBtn.IsVisible = false; + break; + } + + Content = new StackLayout + { + Children = { + new Label { Text = $"This is page {index}"}, + nextBtn, + rmBtn, + popBtn + } + }; + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53445.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53445.cs new file mode 100644 index 000000000000..d40e88e425db --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53445.cs @@ -0,0 +1,78 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 53445, "Setting Grid.IsEnabled to false does not disable child controls", PlatformAffected.All)] + public class Bugzilla53445 : TestContentPage + { + protected override void Init() + { + var layout = new StackLayout { VerticalOptions = LayoutOptions.Fill, Spacing = 20 }; + + var status = new Label { AutomationId = "Success", Text = "Success" }; + + var instructions = new Label { Text = "Disable all of the layouts by clicking the Toggle button. Then click the buttons inside each layout. If the status changes from Success to Fail, this test has failed." }; + + var grid = new Grid + { + BackgroundColor = Colors.Blue, + IsEnabled = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = "grid" + }; + + var gridButton = new Button { AutomationId = "gridbutton", Text = "Test", WidthRequest = 50 }; + grid.Children.Add(gridButton); + gridButton.Clicked += (sender, args) => status.Text = "Fail"; + + var contentView = new ContentView + { + BackgroundColor = Colors.Green, + IsEnabled = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = "contentView" + }; + + var contentViewButton = new Button { AutomationId = "contentviewbutton", Text = "Test", WidthRequest = 50 }; + contentView.Content = contentViewButton; + contentViewButton.Clicked += (sender, args) => status.Text = "Fail"; + + var stackLayout = new StackLayout + { + BackgroundColor = Colors.Orange, + IsEnabled = true, + WidthRequest = 250, + HeightRequest = 50, + AutomationId = "stackLayout" + }; + + var stackLayoutButton = new Button { AutomationId = "stacklayoutbutton", Text = "Test", WidthRequest = 50 }; + stackLayout.Children.Add(stackLayoutButton); + stackLayoutButton.Clicked += (sender, args) => status.Text = "Fail"; + + var toggleButton = new Button { AutomationId = "toggle", Text = $"Toggle IsEnabled (currently {grid.IsEnabled})" }; + toggleButton.Clicked += (sender, args) => + { + grid.IsEnabled = !grid.IsEnabled; + contentView.IsEnabled = !contentView.IsEnabled; + stackLayout.IsEnabled = !stackLayout.IsEnabled; + toggleButton.Text = $"Toggle IsEnabled (currently {grid.IsEnabled})"; + }; + + layout.Children.Add(instructions); + layout.Children.Add(status); + layout.Children.Add(toggleButton); + layout.Children.Add(grid); + layout.Children.Add(contentView); + layout.Children.Add(stackLayout); + + Content = layout; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53834.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53834.cs new file mode 100644 index 000000000000..bdcf6782887f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla53834.cs @@ -0,0 +1,81 @@ +using System.Collections.ObjectModel; +using System.Linq; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 53834, "incorrect row heights on ios when using groupheadertemplate in Xamarin.Forms 2.3.4.214-pre5", PlatformAffected.iOS)] + public class Bugzilla53834 : TestContentPage + { + const string Instructions = ""; + ObservableCollection grouped { get; set; } + ListView lstView; + + class MyViewCell : ViewCell + { + public MyViewCell() + { + var label = new Label { HeightRequest = 66, VerticalOptions = LayoutOptions.Start }; + label.SetBinding(Label.TextProperty, "."); + View = new StackLayout { Padding = 10, Children = { label } }; + } + } + + class MyHeaderViewCell : ViewCell + { + public MyHeaderViewCell() + { + Height = 25; + var label = new Label { VerticalOptions = LayoutOptions.Center }; + label.SetBinding(Label.TextProperty, nameof(GroupedItem.LongName)); + View = label; + } + } + + class GroupedItem : ObservableCollection + { + public string LongName { get; set; } + public string ShortName { get; set; } + } + + protected override void Init() + { + var label = new Label { Text = Instructions, }; + grouped = new ObservableCollection(); + lstView = new ListView() + { + IsGroupingEnabled = true, + HasUnevenRows = true, + ItemTemplate = new DataTemplate(typeof(MyViewCell)), + GroupHeaderTemplate = new DataTemplate(typeof(MyHeaderViewCell)), + ItemsSource = grouped, + AutomationId = "TestReady" + }; + + var grp1 = new GroupedItem() { LongName = "Group 1", ShortName = "1" }; + var grp2 = new GroupedItem() { LongName = "Group 2", ShortName = "2" }; + + for (int i = 1; i < 4; i++) + { + grp1.Add($"I am a short text #{i}"); + grp1.Add($"I am a long text that should cause the line to wrap, and I should not be cut off or overlapping in any way. #{i}"); + grp2.Add($"I am a short text #{i}"); + grp2.Add($"I am a long text that should cause the line to wrap, and I should not be cut off or overlapping in any way. #{i}"); + } + + grouped.Add(grp1); + grouped.Add(grp2); + + Content = new StackLayout + { + Children = { + label, + lstView + } + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55365.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55365.cs new file mode 100644 index 000000000000..37f151030149 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55365.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 55365, "~VisualElement crashes with System.Runtime.InteropServices.COMException", PlatformAffected.UWP)] + public class Bugzilla55365 : TestContentPage + { + readonly StackLayout _itemsPanel = new StackLayout(); + readonly DataTemplate _itemTemplate = new DataTemplate(CreateBoxView); + readonly StackLayout _layout = new StackLayout(); + + protected override void Init() + { + var viewModel = new ObservableCollection<_55365Item> + { + new _55365Item { Subject = 65 } + }; + + viewModel.CollectionChanged += OnCollectionChanged; + + _itemsPanel.BindingContext = viewModel; + + foreach (_55365Item item in viewModel) + { + _itemTemplate.SetValue(BindingContextProperty, item); + var view = (View)_itemTemplate.CreateContent(); + _itemsPanel.Children.Add(view); + } + + var clearButton = new Button { AutomationId = "Clear", Text = "Clear", Command = new Command(o => viewModel.Clear()) }; + _layout.Children.Add(clearButton); + + var collectButton = new Button + { + AutomationId = "Garbage", + Text = "Garbage", + Command = new Command(o => + { + GarbageCollectionHelper.Collect(); + _layout.Children.Add(new Label { Text = "Success" }); + }) + }; + _layout.Children.Add(collectButton); + _layout.Children.Add(_itemsPanel); + + Content = _layout; + } + + static object CreateBoxView() + { + var boxView1 = new BoxView { HeightRequest = 100, Color = new Color(0.55f, 0.23f, 0.147f) }; + var setter1 = new Setter { Property = BoxView.ColorProperty, Value = "#FF2879DD" }; + var trigger1 = new DataTrigger(typeof(BoxView)) { Binding = new Binding("Subject"), Value = 65 }; + trigger1.Setters.Add(setter1); + boxView1.Triggers.Add(trigger1); + return boxView1; + } + + void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.Action == NotifyCollectionChangedAction.Reset) + { + // reset the list + _itemsPanel.Children.Clear(); + } + } + + [Preserve(AllMembers = true)] + public class _55365Item + { + public int Subject { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55745.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55745.cs new file mode 100644 index 000000000000..404cf5438b2c --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55745.cs @@ -0,0 +1,154 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 55745, "[iOS] NRE in ListView with HasUnevenRows=true after changing content and rebinding", PlatformAffected.iOS)] + public class Bugzilla55745 : TestContentPage + { + const string ButtonId = "button"; + ViewModel vm; + + protected override void Init() + { + vm = new ViewModel(); + BindingContext = vm; + + var listView = new ListView + { + HasUnevenRows = true, + ItemTemplate = new DataTemplate(() => + { + var label1 = new Label(); + label1.SetBinding(Label.TextProperty, nameof(DataViewModel.TextOne)); + var label2 = new Label(); + label2.SetBinding(Label.TextProperty, nameof(DataViewModel.TextTwo)); + return new ViewCell { View = new StackLayout { Children = { label1, label2 } } }; + }) + }; + + listView.SetBinding(ListView.ItemsSourceProperty, nameof(vm.MyCollection)); + + var button = new Button { Text = "Tap me twice. The app should not crash.", AutomationId = ButtonId }; + button.Clicked += Button_Clicked; + + Content = new StackLayout { Children = { button, listView } }; + } + + void Button_Clicked(object sender, System.EventArgs e) + { + vm.ToggleContent(); + } + + [Preserve(AllMembers = true)] + class DataViewModel : INotifyPropertyChanged + { + string mTextOne; + + string mTextTwo; + + public event PropertyChangedEventHandler PropertyChanged; + + public string TextOne + { + get { return mTextOne; } + set + { + mTextOne = value; + OnPropertyChanged(nameof(TextOne)); + } + } + + public string TextTwo + { + get { return mTextTwo; } + set + { + mTextTwo = value; + OnPropertyChanged(nameof(TextTwo)); + } + } + + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + + [Preserve(AllMembers = true)] + class ViewModel : INotifyPropertyChanged + { + public List myList = new List() + { + new DataViewModel() { TextOne = "Super", TextTwo = "Juuu"}, + new DataViewModel() { TextOne = "Michael", TextTwo = "Maier"}, + new DataViewModel() { TextOne = "House", TextTwo = "Cat"}, + new DataViewModel() { TextOne = "Flower", TextTwo = "Rock"}, + new DataViewModel() { TextOne = "Job", TextTwo = "Dog"}, + new DataViewModel() { TextOne = "Super", TextTwo = "Juuu"}, + new DataViewModel() { TextOne = "Michael", TextTwo = "Maier"}, + new DataViewModel() { TextOne = "House", TextTwo = "Cat"}, + new DataViewModel() { TextOne = "Flower", TextTwo = "Rock"}, + new DataViewModel() { TextOne = "Job", TextTwo = "Dog"} + }; + + ObservableCollection mMyCollection; + + DataViewModel mSelectedData; + + public ViewModel() + { + MyCollection = new ObservableCollection(myList); + } + + public event PropertyChangedEventHandler PropertyChanged; + + public ObservableCollection MyCollection + { + get + { + return mMyCollection; + } + set + { + mMyCollection = value; + OnPropertyChanged(nameof(MyCollection)); + } + } + + public DataViewModel SelectedData + { + get { return mSelectedData; } + set + { + mSelectedData = value; + OnPropertyChanged(nameof(SelectedData)); + } + } + + public void ToggleContent() + { + if (MyCollection.Count < 3) + { + MyCollection.Clear(); + MyCollection = new ObservableCollection(myList); + } + else + { + MyCollection.Clear(); + MyCollection.Add(myList[2]); + } + } + + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55912.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55912.cs new file mode 100644 index 000000000000..cdc2411a39ea --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla55912.cs @@ -0,0 +1,75 @@ +using System; +using System.Diagnostics; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 55912, "Tap event not always propagated to containing Grid/StackLayout", + PlatformAffected.Android)] + public class Bugzilla55912 : TestContentPage + { + const string Success = "Success"; + const string GridLabelId = "GridLabel"; + const string StackLabelId = "StackLabel"; + + protected override void Init() + { + var layout = new Grid(); + + layout.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star }); + layout.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star }); + layout.RowDefinitions.Add(new RowDefinition { Height = GridLength.Star }); + + var testGrid = new Grid { BackgroundColor = Colors.Red, AutomationId = "testgrid" }; + var gridLabel = new Label + { + AutomationId = GridLabelId, + Text = "This is a Grid with a TapGesture", + FontSize = 24, + BackgroundColor = Colors.Green + }; + Grid.SetRow(testGrid, 1); + testGrid.Children.Add(gridLabel); + + var testStack = new StackLayout { BackgroundColor = null, AutomationId = "teststack" }; + var stackLabel = new Label + { + AutomationId = StackLabelId, + Text = "This StackLayout also has a TapGesture", + FontSize = 24, + BackgroundColor = Colors.Green + }; + Grid.SetRow(testStack, 2); + testStack.Children.Add(stackLabel); + + layout.Children.Add(testGrid); + layout.Children.Add(testStack); + + Content = layout; + + testGrid.GestureRecognizers.Add(new TapGestureRecognizer + { + NumberOfTapsRequired = 1, + Command = new Command(() => + { + Debug.WriteLine($"***** TestGrid Tapped: {DateTime.Now} *****"); + layout.Children.Add(new Label { AutomationId = Success, Text = Success }); + }) + }); + + testStack.GestureRecognizers.Add(new TapGestureRecognizer + { + NumberOfTapsRequired = 1, + Command = new Command(() => + { + Debug.WriteLine($"***** TestStack Tapped: {DateTime.Now} *****"); + layout.Children.Add(new Label { AutomationId = Success, Text = Success }); + }) + }); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56298.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56298.cs new file mode 100644 index 000000000000..2c9f623ed67a --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56298.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.ObjectModel; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Controls.PlatformConfiguration; +using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific; +using Microsoft.Maui.Graphics; +using ListView = Microsoft.Maui.Controls.ListView; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 56298, "Changing ListViews HasUnevenRows at runtime on iOS has no effect", PlatformAffected.iOS)] + public class Bugzilla56298 : TestContentPage // or TestFlyoutPage, etc ... + { + ListView list; + Button button; + StackLayout layoutRoot; + + ObservableCollection groups; + public static int Count = 0; + + protected override void Init() + { + On().SetUseSafeArea(true); + list = new ListView(); + + var template = new DataTemplate(typeof(UnevenViewCell)); + //template.SetBinding(TextCell.TextProperty, "FullName"); + //template.SetBinding(TextCell.DetailProperty, "Address"); + list.ItemTemplate = template; + + groups = new ObservableCollection(); + list.ItemsSource = groups; + list.GroupDisplayBinding = new Binding(nameof(Group.Key)); + list.GroupShortNameBinding = new Binding(nameof(Group.Key)); + list.IsGroupingEnabled = true; + + button = new Button { Text = "Add new data", AutomationId = "btnAdd" }; + button.Clicked += Button_Clicked; + + var button1 = new Button { Text = "Toggle Uneven rows", AutomationId = "btnToggle" }; + button1.Clicked += Button_Clicked1; + + + layoutRoot = new StackLayout(); + layoutRoot.Children.Add(list); + layoutRoot.Children.Add(button); + layoutRoot.Children.Add(button1); + + this.Content = layoutRoot; + } + + void Button_Clicked(object sender, EventArgs e) + { + + var group = new Group() + { + Key = "A" + }; + for (int i = 0; i < 59; i++) + { + group.Add(new Person1 + { + FullName = "Andrew", + Address = "404 Somewhere" + }); + } + + groups.Add(group); + } + + private void Button_Clicked1(object sender, EventArgs e) + { + list.HasUnevenRows = !list.HasUnevenRows; + } + + [Preserve(AllMembers = true)] + class UnevenViewCell : ViewCell + { + public UnevenViewCell() + { + + var label = new Label(); + label.SetBinding(Label.TextProperty, "FullName"); + Height = Bugzilla56298.Count % 2 == 0 ? 50 : 100; + View = label; + View.BackgroundColor = Bugzilla56298.Count % 2 == 0 ? Colors.Pink : Colors.LightYellow; + Bugzilla56298.Count++; + } + } + + [Preserve(AllMembers = true)] + class Person1 + { + public string FullName { get; set; } + public string Address { get; set; } + } + + class Group : ObservableCollection + { + public string Key { get; set; } + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56771.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56771.cs new file mode 100644 index 000000000000..d969b55009ac --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56771.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 56771, "Multi-item add in INotifyCollectionChanged causes a NSInternalInconsistencyException in bindings on iOS", PlatformAffected.iOS)] + public class Bugzilla56771 : TestContentPage + { + const string Success = "Success"; + const string BtnAdd = "btnAdd"; + OptimizedCollection data = new OptimizedCollection(); + int i = 4; + + private void InitializeData() + { + + data.Add("Item 1"); + data.Add("Item 2"); + data.Add("Item 3"); + data.Add("Item 4"); + BindingContext = data; + } + + protected override void Init() + { + data.CollectionChanged += (_, e) => + { + var log = $"<{DateTime.Now.ToString("T")}> {e.Action} action fired."; + System.Diagnostics.Debug.WriteLine(log); + }; + var label = new Label { Text = "Click the Add 2 button." }; + var button = new Button + { + Text = "Add 2", + AutomationId = BtnAdd, + Command = new Command(() => + { + try + { + data.AddRange($"Item {++i}", $"Item {++i}"); + } + catch (ArgumentException) + { + label.Text = Success; + } + }) + }; + var button1 = new Button + { + Text = "Remove 2", + Command = new Command(() => + { + if (data.Count > 1) + { + data.RemoveRangeAt(0, 2); + } + }) + }; + var button2 = new Button + { + Text = "Clear", + Command = new Command(() => + { + data.RemoveRangeAt(0, data.Count); + }) + }; + var listView = new ListView { }; + listView.SetBinding(ListView.ItemsSourceProperty, "."); + + Content = new StackLayout + { + Children = { label, button, button1, button2, listView } + }; + + InitializeData(); + } + + [Preserve(AllMembers = true)] + public class OptimizedCollection : ObservableCollection + { + public OptimizedCollection() + { + } + + protected override void ClearItems() + { + base.ClearItems(); + } + + public void AddRange(params T[] items) + { + InsertRangeAt(this.Count, items); + } + + public void InsertRangeAt(int startIndex, params T[] items) + { + int idx = this.Count; + foreach (var item in items) + { + base.Items.Insert(startIndex++, item); + } + if (idx < Count) + { + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, changedItems: items.ToList(), startingIndex: startIndex)); + OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); + OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); + } + } + + public void RemoveRangeAt(int startIndex, int count) + { + if (count > 0) + { + List removedItems = new List(count); + for (int i = 0; i < count; i++) + { + removedItems.Add(base.Items[startIndex]); + base.Items.RemoveAt(startIndex); + } + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, changedItems: removedItems, startingIndex: startIndex++)); + OnPropertyChanged(new PropertyChangedEventArgs(nameof(Count))); + OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56896.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56896.cs new file mode 100644 index 000000000000..98faf30f2c1b --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla56896.cs @@ -0,0 +1,210 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 56896, "ListViews for lists with many elements regressed in performance on iOS", PlatformAffected.iOS)] + public class Bugzilla56896 : TestContentPage + { + const string Instructions = "The number in blue is the number of constructor calls. The number in purple is the initial load time in milliseconds."; + const string InstructionsId = "InstructionsId"; + const string ConstructorCountId = "constructorCount"; + const string TimeId = "time"; + + [Preserve(AllMembers = true)] + class MyViewModel : INotifyPropertyChanged + { + int _constructorCallCount; + + public int ConstructorCallCount + { + get { return _constructorCallCount; } + set + { + _constructorCallCount = value; + OnPropertyChanged(); + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + + [Preserve(AllMembers = true)] + class Fizz : ViewCell + { + readonly MyViewModel _vm; + + Label myLabel; + public Fizz(MyViewModel vm) + { + _vm = vm; + + vm.ConstructorCallCount++; + + Height = 30; + + myLabel = new Label { Text = "fizz" }; + View = myLabel; + } + ~Fizz() + { + _vm.ConstructorCallCount--; + } + } + + [Preserve(AllMembers = true)] + class Buzz : ViewCell + { + readonly MyViewModel _vm; + + Label myLabel; + public Buzz(MyViewModel vm) + { + _vm = vm; + + vm.ConstructorCallCount++; + + Height = 50; + + myLabel = new Label { Text = "buzz" }; + View = myLabel; + } + ~Buzz() + { + _vm.ConstructorCallCount--; + } + } + + [Preserve(AllMembers = true)] + class Fizzbuzz : ViewCell + { + readonly MyViewModel _vm; + + Label myLabel; + public Fizzbuzz(MyViewModel vm) + { + _vm = vm; + + vm.ConstructorCallCount++; + + Height = 150; + + myLabel = new Label { Text = "fizzbuzz" }; + View = myLabel; + } + ~Fizzbuzz() + { + _vm.ConstructorCallCount--; + } + } + + [Preserve(AllMembers = true)] + class Number : ViewCell + { + readonly MyViewModel _vm; + + Label myLabel; + public Number(MyViewModel vm) + { + _vm = vm; + + vm.ConstructorCallCount++; + + Height = 44; + + myLabel = new Label(); + myLabel.SetBinding(Label.TextProperty, "."); + View = myLabel; + } + ~Number() + { + _vm.ConstructorCallCount--; + } + } + + class MyDataTemplateSelector : DataTemplateSelector + { + DataTemplate _fizzbuzz; + DataTemplate _fizz; + DataTemplate _buzz; + DataTemplate _number; + + public MyDataTemplateSelector(MyViewModel vm) + { + _fizzbuzz = new DataTemplate(() => new Fizzbuzz(vm)); + _fizz = new DataTemplate(() => new Fizz(vm)); + _buzz = new DataTemplate(() => new Buzz(vm)); + _number = new DataTemplate(() => new Number(vm)); + } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + int number = (int)item; + + if (number % 15 == 0) + return _fizzbuzz; + else if (number % 5 == 0) + return _buzz; + else if (number % 3 == 0) + return _fizz; + else + return _number; + } + } + + + Label _timeLabel = new Label { TextColor = Colors.Purple, AutomationId = TimeId }; + Stopwatch _timer = new Stopwatch(); + ListView _listView; + protected override void Init() + { + _timer.Start(); + var vm = new MyViewModel(); + + BindingContext = vm; + + var label = new Label { TextColor = Colors.Blue, AutomationId = ConstructorCountId }; + label.SetBinding(Label.TextProperty, nameof(vm.ConstructorCallCount)); + + _listView = new ListView(ListViewCachingStrategy.RecycleElement) + { + HasUnevenRows = true, + // Set the RowHeight to enable optimal performance and minimal constructor calls. + // It will still use the specified Cell heights on final measure. + // Note, however, that doing this negates the fix for Bugzilla 43313, so if user expects + // to add items to the bottom of this list and scroll smoothly, user should omit the RowHeight + // and rely solely on the Cell heights. This will cause each row to be constructed at least once, + // but it will allow the ListView to estimate the height properly for smooth scrolling. + // Also note that performance will degrade if the first cell does not have a specified height or + // if most of the cells do not have a specified height. It is recommended to specify a height on all + // or none of the cells when possible. + RowHeight = 50, + ItemsSource = Enumerable.Range(1, 5001), + ItemTemplate = new MyDataTemplateSelector(vm) + }; + Content = new StackLayout { Children = { new Label { Text = Instructions, AutomationId = InstructionsId }, label, _timeLabel, _listView } }; + } + + protected override void OnAppearing() + { + base.OnAppearing(); + + _timer.Stop(); + _timeLabel.Text = _timer.ElapsedMilliseconds.ToString(); + _timer.Reset(); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57114.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57114.cs new file mode 100644 index 000000000000..2bcac0749735 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57114.cs @@ -0,0 +1,94 @@ +using System; +using System.Diagnostics; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 57114, "Forms gestures are not supported on UIViews that have native gestures", PlatformAffected.iOS)] + public class Bugzilla57114 : TestContentPage + { + public static string _57114NativeGestureFiredMessage = "_57114NativeGestureFiredMessage"; + + Label _results; + bool _nativeGestureFired; + bool _formsGestureFired; + + const string Testing = "Testing..."; + const string Success = "Success"; + const string ViewAutomationId = "_57114View"; + + protected override void Init() + { + var instructions = new Label + { + Text = $"Tap the Aqua View below. If the label below changes from '{Testing}' to '{Success}', the test has passed." + }; + + _results = new Label { Text = Testing }; + + var view = new _57114View + { + AutomationId = ViewAutomationId, + HeightRequest = 200, + WidthRequest = 200, + BackgroundColor = Colors.Aqua, + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill + }; + + var tap = new TapGestureRecognizer + { + Command = new Command(() => + { + _formsGestureFired = true; + UpdateResults(); + }) + }; + +#pragma warning disable CS0618 // Type or member is obsolete + MessagingCenter.Subscribe(this, _57114NativeGestureFiredMessage, NativeGestureFired); +#pragma warning restore CS0618 // Type or member is obsolete + + view.GestureRecognizers.Add(tap); + + var layout = new StackLayout() + { + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + Children = + { + instructions, _results, view + } + }; + + Content = layout; + } + + void NativeGestureFired(object obj) + { + _nativeGestureFired = true; + UpdateResults(); + } + + void UpdateResults() + { + if (_nativeGestureFired && _formsGestureFired) + { + _results.Text = Success; + } + else + { + _results.Text = Testing; + } + } + + [Preserve(AllMembers = true)] + public class _57114View : View + { + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57674.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57674.cs new file mode 100644 index 000000000000..936679530c32 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57674.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 57674, "ListView not honoring INotifyCollectionChanged", PlatformAffected.UWP)] + public class Bugzilla57674 : TestContentPage + { + MyCollection _myCollection; + protected override void Init() + { + // Initialize ui here instead of ctor + _myCollection = new MyCollection(); + + var stackLayout = new StackLayout(); + var button = new Button + { + AutomationId = "IssueButton", + Text = "Add new element to ListView" + }; + button.Clicked += (object sender, EventArgs e) => _myCollection.AddNewItem(); + + stackLayout.Children.Add(button); + + stackLayout.Children.Add(new ListView + { + AutomationId = "IssueListView", + ItemsSource = _myCollection + }); + + Content = stackLayout; + } + } + + public class MyCollection : IEnumerable, INotifyCollectionChanged + { + readonly List _internalList = new List(); + public MyCollection() + { + } + + public IEnumerable GetItems() + { + foreach (var item in _internalList) + { + yield return item; + } + } + + public IEnumerator GetEnumerator() + { + return GetItems().GetEnumerator(); + } + + public void AddNewItem() + { + int index = _internalList.Count; + string item = Guid.NewGuid().ToString(); + _internalList.Add(item); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); + } + + public event NotifyCollectionChangedEventHandler CollectionChanged; + + protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + CollectionChanged?.Invoke(this, e); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57758.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57758.cs new file mode 100644 index 000000000000..e698ffe5a020 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57758.cs @@ -0,0 +1,37 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 57758, "ObjectDisposedException for Microsoft.Maui.Controls.Platform.Android.FastRenderers.ImageRenderer", PlatformAffected.Android)] + public class Bugzilla57758 : TestContentPage + { + const string ImageId = "TestImageId"; + + protected override void Init() + { + var testImage = new Image { Source = "coffee.png", AutomationId = ImageId }; + + var layout = new StackLayout + { + Padding = new Thickness(0, 20, 0, 0), + Children = + { + testImage + } + }; + + var tapGesture = new TapGestureRecognizer + { + NumberOfTapsRequired = 1, + Command = new Command(() => layout.Children.Remove(testImage)) + }; + + testImage.GestureRecognizers.Add(tapGesture); + + Content = layout; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57910.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57910.cs new file mode 100644 index 000000000000..3d1303435d1f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla57910.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 57910, "ObjectDisposedException in Microsoft.Maui.Controls.Platform.Android.Renderers.ProgressBarRenderer", PlatformAffected.Android)] + public class Bugzilla57910 : NavigationPage + { + const string ButtonId = "btnPush"; + const string Button2Id = "btnPop"; + const string Instructions = "Tap Push. Then quickly tap Pop on the subsequent screen. Do this several times. If there is no crash, then this test has passed."; + const string Instructions2 = "Tap Pop. Then quickly tap Push on the subsequent screen. Do this several times. If there is no crash, then this test has passed."; + + public Bugzilla57910() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + Navigation.PushAsync(new HomePage()); + } + + [Preserve(AllMembers = true)] + class HomePage : ContentPage + { + public HomePage() + { + Button button = new Button { Text = "Push", AutomationId = ButtonId }; + + button.Clicked += Button_Clicked; + + Content = new StackLayout { Children = { new Label { Text = Instructions }, button } }; + } + + async void Button_Clicked(object sender, EventArgs e) + { + await Navigation.PushAsync(new ListPage()); + GarbageCollectionHelper.Collect(); + } + } + + [Preserve(AllMembers = true)] + class ListItemView : ViewCell + { + public ListItemView() + { + ProgressBar progressBar = new ProgressBar { IsVisible = false }; + progressBar.SetBinding(ProgressBar.ProgressProperty, nameof(ListItemViewModel.DownloadProgressPercentage)); + + // Need a trigger to set a property on a VisualElement. Not actually specific to ProgressBar. + DataTrigger newDataTrigger = new DataTrigger(typeof(ProgressBar)) { Binding = new Binding(nameof(ListItemViewModel.State)), Value = ListItemViewModel.InstallableState.Downloading }; + newDataTrigger.Setters.Add(new Setter { Property = ProgressBar.IsVisibleProperty, Value = true }); + progressBar.Triggers.Add(newDataTrigger); + + View = new ContentView { Content = new StackLayout { Children = { progressBar } } }; + } + } + + [Preserve(AllMembers = true)] + class ListHeaderView : ContentView + { + public ListHeaderView() + { + Label newLabel = new Label(); + newLabel.SetBinding(Label.TextProperty, nameof(ListPageViewModel.Header)); + Content = newLabel; + } + } + + [Preserve(AllMembers = true)] + class ListFooterView : ContentView + { + public ListFooterView() + { + Label newLabel = new Label(); + newLabel.SetBinding(Label.TextProperty, nameof(ListPageViewModel.Footer)); + + var stack = new StackLayout { Children = { newLabel } }; + Content = stack; + } + } + + [Preserve(AllMembers = true)] + class ListPageViewModel : INotifyPropertyChanged + { + ObservableCollection _items; + string _footer; + string _header; + + int _counter; + public ListPageViewModel() + { + _header = "Header!"; + _footer = "Footer!"; + _counter = 0; + _items = new ObservableCollection(Enumerable.Range(0, 100).Select(c => new ListItemViewModel())); + + // Need an asynchronous action that happens sometime between creation of the Element and Pop of the containing page +#pragma warning disable CS0612 // Type or member is obsolete +#pragma warning disable CS0618 // Type or member is obsolete + Device.StartTimer(TimeSpan.FromMilliseconds((100)), () => + { + Header = $"Header! {_counter++}"; + Footer = $"Footer! {_counter++}"; + + return true; + }); +#pragma warning restore CS0618 // Type or member is obsolete +#pragma warning restore CS0612 // Type or member is obsolete + } + + public event PropertyChangedEventHandler PropertyChanged; + + public ObservableCollection Items + { + get { return _items; } + set + { + _items = value; + OnPropertyChanged(nameof(Items)); + } + } + + public string Header + { + get { return _header; } + set + { + _header = value; + OnPropertyChanged(nameof(Header)); + } + } + + public string Footer + { + get { return _footer; } + set + { + _footer = value; + OnPropertyChanged(nameof(Footer)); + } + } + + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + + [Preserve(AllMembers = true)] + class ListItemViewModel : INotifyPropertyChanged + { + double _downloadProgressPercentage; + + InstallableState _state; + + public ListItemViewModel() + { + DownloadProgressPercentage = 0d; + State = InstallableState.Downloading; + + // Need an asynchronous action that happens sometime between creation of the Element and Pop of the containing page +#pragma warning disable CS0612 // Type or member is obsolete +#pragma warning disable CS0618 // Type or member is obsolete + Device.StartTimer(TimeSpan.FromMilliseconds((1000)), () => + { + DownloadProgressPercentage += 0.05d; + if (DownloadProgressPercentage > 0.99d) + { + State = InstallableState.Local; + } + + return DownloadProgressPercentage != 1.0d; + }); +#pragma warning restore CS0618 // Type or member is obsolete +#pragma warning restore CS0612 // Type or member is obsolete + } + + public event PropertyChangedEventHandler PropertyChanged; + + public enum InstallableState + { + Local, + Downloading + } + + public double DownloadProgressPercentage + { + get { return _downloadProgressPercentage; } + set + { + _downloadProgressPercentage = value; + OnPropertyChanged(nameof(DownloadProgressPercentage)); + } + } + + public InstallableState State + { + get { return _state; } + set + { + _state = value; + OnPropertyChanged(nameof(State)); + } + } + + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + + [Preserve(AllMembers = true)] + class ListPage : ContentPage + { + public ListPage() + { + ListView listView = new ListView(ListViewCachingStrategy.RecycleElement) + { + RowHeight = 70, + ItemTemplate = new DataTemplate(typeof(ListItemView)), + HeaderTemplate = new DataTemplate(typeof(ListHeaderView)), + FooterTemplate = new DataTemplate(typeof(ListFooterView)), + }; + + listView.SetBinding(ListView.ItemsSourceProperty, nameof(ListPageViewModel.Items)); + listView.SetBinding(ListView.HeaderProperty, "."); + listView.SetBinding(ListView.FooterProperty, "."); + + Button newButton = new Button { Text = "Pop", AutomationId = Button2Id }; + newButton.Clicked += NewButton_Clicked; + Content = new StackLayout { Children = { new Label { Text = Instructions2 }, newButton, listView } }; + + BindingContext = new ListPageViewModel(); + } + + void NewButton_Clicked(object sender, EventArgs e) + { + Navigation.PopAsync(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla58645.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla58645.cs new file mode 100644 index 000000000000..84ca77eff282 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla58645.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.ObjectModel; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 58645, "[iOS] NRE Thrown When ListView Items Are Replaced By Items With a Different Template", PlatformAffected.iOS)] + public class Bugzilla58645 : TestContentPage + { + const string ButtonId = "button"; + ObservableCollection Items { get; set; } + + protected override void Init() + { + Items = new ObservableCollection { "Item 1A", "Item 2A", "Item 3A" }; + + var myListView = new ListView + { + HasUnevenRows = true, + ItemsSource = Items, + ItemTemplate = new LayoutTemplateSelector + { + LayoutA = new DataTemplate(typeof(LayoutA)), + LayoutB = new DataTemplate(typeof(LayoutB)) + } + }; + + var switchBtn = new Button + { + Text = "Switch Items", + AutomationId = ButtonId, + Command = new Command(() => + { + Items.Clear(); + Items.Add("Item 1B"); + }) + }; + + Content = new StackLayout + { + Children = + { + new Label { Text = "Tap the 'Switch Items' button. If the app does not crash, this test has passed." }, + switchBtn, + myListView + } + }; + } + + [Preserve(AllMembers = true)] + public class LayoutA : ViewCell + { + public LayoutA() + { + var layout = new Grid + { + Padding = new Thickness(14), + ColumnDefinitions = + { + new ColumnDefinition { Width = GridLength.Auto }, + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) } + }, + RowDefinitions = + { + new RowDefinition { Height = GridLength.Auto } + } + }; + + var mainLabel = new Label(); + mainLabel.SetBinding(Label.TextProperty, "."); + + var sw = new Switch(); + layout.Add(mainLabel, 0, 0); + layout.Add(sw, 2, 0); + View = layout; + } + } + + [Preserve(AllMembers = true)] + public class LayoutB : ViewCell + { + public LayoutB() + { + var layout = new Grid + { + Padding = new Thickness(14), + ColumnDefinitions = + { + new ColumnDefinition { Width = GridLength.Auto }, + new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) } + }, + RowDefinitions = + { + new RowDefinition { Height = GridLength.Auto } + } + }; + + var mainLabel = new Label(); + mainLabel.SetBinding(Label.TextProperty, "."); + + var secondLabel = new Label + { + Text = "B" + }; + + layout.Add(mainLabel, 0, 0); + layout.Add(secondLabel, 2, 0); + View = layout; + } + } + + [Preserve(AllMembers = true)] + public class LayoutTemplateSelector : DataTemplateSelector + { + public DataTemplate LayoutA { get; set; } + public DataTemplate LayoutB { get; set; } + + protected override DataTemplate OnSelectTemplate(object item, BindableObject container) + { + if (item == null) + return LayoutA; + + var text = (string)item; + return text.Contains("A", StringComparison.OrdinalIgnoreCase) ? LayoutA : LayoutB; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59097.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59097.cs new file mode 100644 index 000000000000..8ec06a0c50f9 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59097.cs @@ -0,0 +1,42 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 59097, "[Android] Calling PopAsync via TapGestureRecognizer causes an application crash", PlatformAffected.Android)] + public class Bugzilla59097 : NavigationPage + { + public Bugzilla59097() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + Navigation.PushAsync(new ContentPage { Content = new Label { Text = "previous page " } }); + Navigation.PushAsync(new ToPopPage()); + } + + public class ToPopPage : ContentPage + { + public ToPopPage() + { + var boxView = new BoxView { WidthRequest = 100, HeightRequest = 100, Color = Colors.Red, AutomationId = "boxView" }; + var tapGesture = new TapGestureRecognizer { NumberOfTapsRequired = 1, Command = new Command(PopPageBack) }; + boxView.GestureRecognizers.Add(tapGesture); + var layout = new StackLayout(); + layout.Children.Add(boxView); + Content = layout; + } + + async void PopPageBack(object obj) + { + await Navigation.PopAsync(true); + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59172.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59172.cs new file mode 100644 index 000000000000..2ab6ea2336d3 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59172.cs @@ -0,0 +1,83 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, + 59172, "[iOS] Popped page does not appear on top of current navigation stack, please file a bug.", + PlatformAffected.iOS)] + public class Bugzilla59172 : NavigationPage + { + public Bugzilla59172() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + var firstPage = new TestPage(); + Navigation.PushAsync(firstPage); + } + + [Preserve(AllMembers = true)] + public class TestPage : ContentPage + { + TestPage parent; + Label navigationErrorLabel = new Label(); + + public TestPage(TestPage parentPage = null) + { + this.parent = parentPage; + + var layout = new StackLayout(); + + var forwardButton = new Button { Text = "Forward", AutomationId = "GoForward" }; + layout.Children.Add(forwardButton); + forwardButton.Clicked += Forward_OnClicked; + + if (parentPage != null) + { + var backButton = new Button { Text = "Back (Delayed)", AutomationId = "GoBackDelayed" }; + layout.Children.Add(backButton); + backButton.Clicked += (a, b) => BackButtonPress(false); + + var backButtonSafe = new Button { Text = "Back (Delayed; Safe)", AutomationId = "GoBackDelayedSafe" }; + layout.Children.Add(backButtonSafe); + backButtonSafe.Clicked += (a, b) => BackButtonPress(true); + } + + layout.Children.Add(navigationErrorLabel); + + Content = layout; + } + + void Forward_OnClicked(object sender, EventArgs e) + { + Navigation.PushAsync(new TestPage(this)); + } + + async void BackButtonPress(bool safe) + { + try + { + // Assume some workload that delays the back navigation + await Task.Delay(2500); + + await Navigation.PopAsync(); + } + catch (Exception ex) + { + if (!safe) + { throw; } + + parent.navigationErrorLabel.Text = ex.Message; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59896.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59896.cs new file mode 100644 index 000000000000..53c0a62d7afa --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59896.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 59896, "v2.4.0: Adding inserting section to ListView causes crash IF first section is empty", PlatformAffected.iOS)] + public class Bugzilla59896 : TestContentPage + { + const string btnAdd = "btnAdd"; + int _newGroupIndex = 0; + + protected override void Init() + { + var group1 = new Group("group A"); + var group2 = new Group("group C") + { + "item 1", "item 2" + }; + var source = new ObservableCollection + { + group1, group2 + }; + + var button = new Button + { + Text = "Add Group between A & C", + AutomationId = btnAdd + }; + + button.Clicked += (sender, e) => + { + var group = new Group("New Group " + _newGroupIndex) + { + "new Group["+_newGroupIndex+" ].A", "new Group["+_newGroupIndex+" ].B", + }; + _newGroupIndex++; + source.Insert(1, group); + }; + + Content = new StackLayout + { + Children = + { + new Label { Text = "Clicking the Add Group between A & C button should NOT cause an ArgumentException." }, + button, + new ListView + { + ItemsSource = source, + GroupDisplayBinding = new Binding("Title"), + IsGroupingEnabled = true + } + } + }; + + } + + [Preserve(AllMembers = true)] + public class Group : List + { + public string Title + { + get; + set; + } + + public Group() { } + + public Group(string title) + { + Title = title; + } + } + + [Preserve(AllMembers = true)] + public class GroupHeaderView + { + public GroupHeaderView() + { + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59925.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59925.cs new file mode 100644 index 000000000000..f70c1a091208 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla59925.cs @@ -0,0 +1,53 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Bugzilla, 59925, "Font size does not change vertical height of Entry on iOS", PlatformAffected.Default)] + public class Bugzilla59925 : TestContentPage // or TestFlyoutPage, etc ... + { + const int Delta = 1; + Entry _entry; + + private void ChangeFontSize(int delta) + { + _entry.FontSize += delta; + } + + protected override void Init() + { + _entry = new Entry + { + Text = "Hello World!" + }; + + var buttonBigger = new Button + { + AutomationId = "Bigger", + Text = "Bigger", + }; + buttonBigger.Clicked += (x, o) => ChangeFontSize(Delta); + + var buttonSmaller = new Button + { + AutomationId = "Smaller", + Text = "Smaller" + }; + buttonSmaller.Clicked += (x, o) => ChangeFontSize(-Delta); + + var stack = new StackLayout + { + Children = { + buttonBigger, + buttonSmaller, + _entry + } + }; + + // Initialize ui here instead of ctor + Content = stack; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla60123.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla60123.cs new file mode 100644 index 000000000000..8c91e86ca55d --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla60123.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Bugzilla, 60123, "Rui's issue", PlatformAffected.Default)] + public class Bugzilla60123 : TestContentPage // or TestFlyoutPage, etc ... + { + protected override void Init() + { + // Initialize ui here instead of ctor + var items = new List(); + for (int i = 0; i < 100; i++) + { + items.Add(i.ToString()); + } + + var listView = new ListView(ListViewCachingStrategy.RecycleElement) + { + BackgroundColor = Colors.Yellow, + AutomationId = "ListView" + }; + + listView.ItemsSource = items; + + Content = listView; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/CarouselViewUpdateCurrentItem.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/CarouselViewUpdateCurrentItem.xaml.cs index 335098a313c6..fde60220fa63 100644 --- a/src/Controls/tests/TestCases.HostApp/Issues/CarouselViewUpdateCurrentItem.xaml.cs +++ b/src/Controls/tests/TestCases.HostApp/Issues/CarouselViewUpdateCurrentItem.xaml.cs @@ -11,7 +11,7 @@ namespace Maui.Controls.Sample.Issues { // Issue9827 (src\ControlGallery\src\Issues.Shared\Issue9827.cs [XamlCompilation(XamlCompilationOptions.Compile)] - [Issue(IssueTracker.Github, 9827, "CarouselView doesn't update the CurrentItem on Swipe under strange condition", PlatformAffected.Android)] + [Issue(IssueTracker.Github, 9827, "CarouselView does not update the CurrentItem on Swipe under strange condition", PlatformAffected.Android)] public partial class CarouselViewUpdateCurrentItem : ContentPage { public CarouselViewUpdateCurrentItem() diff --git a/src/Controls/tests/TestCases.HostApp/Issues/GitHub1567.cs b/src/Controls/tests/TestCases.HostApp/Issues/GitHub1567.cs new file mode 100644 index 000000000000..fcbf15dac675 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/GitHub1567.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.ObjectModel; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 1567, "NRE using TapGestureRecognizer on cell with HasUnevenRows", PlatformAffected.iOS, issueTestNumber: 1)] + public class GitHub1567 : TestContentPage // or TestFlyoutPage, etc ... + { + ICommand SomeCommand; + ObservableCollection LocalList { get; set; } = new ObservableCollection(); + + protected override async void Init() + { + // Initialize ui here instead of ctor + var btn = new Button + { + AutomationId = "btnFillData", + Text = "FILL DATA", + Command = new Command(async () => { await FillData(); }) + }; + var lst = new ListView(ListViewCachingStrategy.RecycleElement) + { + Header = btn, + HasUnevenRows = true, + RowHeight = -1, + SeparatorVisibility = SeparatorVisibility.None, + ItemsSource = LocalList, + ItemTemplate = new DataTemplate(typeof(CustomCell)) + }; + + Content = lst; + this.BindingContext = this; + SomeCommand = new Command(SomeCommandAction); + await FillData(); + } + + [Preserve(AllMembers = true)] + class CustomCell : ViewCell + { + public CustomCell() + { + var lbl = new Label { FontSize = 14 }; + lbl.SetBinding(Label.TextProperty, "Value1"); + var grd = new Grid(); +#pragma warning disable CS0618 // Type or member is obsolete + var boxView = new BoxView + { + BackgroundColor = Colors.Transparent, + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.FillAndExpand + }; +#pragma warning restore CS0618 // Type or member is obsolete + var gesture = new TapGestureRecognizer(); + gesture.SetBinding(TapGestureRecognizer.CommandProperty, "SomeCommand"); + boxView.GestureRecognizers.Add(gesture); + grd.Children.Add(lbl); + grd.Children.Add(boxView); + View = grd; + } + } + + void SomeCommandAction(object obj) + { + } + + async Task FillData() + { + await Task.Factory.StartNew(async () => + { + await Task.Delay(100); + LocalList.Clear(); + for (int i = 0; i < 100; i++) + { + LocalList.Add(new LocalIem() + { + Value1 = DateTime.UtcNow.Ticks.ToString(), + }); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } + + [Preserve(AllMembers = true)] + class LocalIem + { + public string Value1 { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/GitHub1648.cs b/src/Controls/tests/TestCases.HostApp/Issues/GitHub1648.cs new file mode 100644 index 000000000000..f842b2bf166f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/GitHub1648.cs @@ -0,0 +1,57 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 1648, "FlyoutPage throws ArgumentOutOfRangeException", PlatformAffected.UWP)] + public class GitHub1648 : NavigationPage + { + public GitHub1648() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + Navigation.PushAsync(new FlyoutPage + { + Flyout = new NavigationPage(new ContentPage()) + { + Title = "Flyout" + }, + Detail = new ContentPage(), + }); + } + + protected override void OnAppearing() + { + base.OnAppearing(); + Navigation.PushModalAsync(new SimplePage()); + } + + class SimplePage : ContentPage + { + public SimplePage() + { + Content = new StackLayout() + { + Children = { + new Label { + AutomationId = "Success", + Text = "Success" + }, + new Button + { + AutomationId = "Reload", + Text = "Reload", + Command = new Command(() => Navigation.PopModalAsync()) + } + } + }; + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Github1625.cs b/src/Controls/tests/TestCases.HostApp/Issues/Github1625.cs new file mode 100644 index 000000000000..0f734d024e83 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Github1625.cs @@ -0,0 +1,49 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 1625, "Slider value is not changed for the first position change", PlatformAffected.Android)] + public class Github1625 : TestContentPage + { + protected override void Init() + { + var slider = new Slider(); + slider.Maximum = 10; + slider.Minimum = 1; + slider.Value = 5; + + var valueLabel = new Label() { AutomationId = "LabelValue" }; + var stack = new StackLayout { Orientation = StackOrientation.Vertical, Spacing = 15 }; + + valueLabel.SetBinding(Label.TextProperty, new Binding("Value", source: slider)); + stack.Children.Add(valueLabel); + stack.Children.Add(slider); + + var button = new Button + { + Text = "Set to 7", + AutomationId = "SetTo7", + Command = new Command(() => slider.Value = 7) + }; + + stack.Children.Add(button); + + var label = new Label + { + Text = "On start, slider value should show 5 even though SeekBar is 4.996. Sliding back and forth should update the label and the tracker. Tapping on a slider position should do the same. Tapping on the button should show 7 even though SeekBar is 6.994." + }; + stack.Children.Add(label); + + var labelAccessibility = new Label + { + Text = "Turn on a screen reader and use the volume buttons to modify the slider value. Ensure that the slider value on the label updates correctly." + }; + stack.Children.Add(labelAccessibility); + + Content = stack; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Github6384.cs b/src/Controls/tests/TestCases.HostApp/Issues/Github6384.cs new file mode 100644 index 000000000000..ce832af19de0 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Github6384.cs @@ -0,0 +1,66 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 6384, "content page in tabbed page not showing inside shell tab", PlatformAffected.iOS | PlatformAffected.Android)] + public class Github6384 : TestShell + { + protected override void Init() + { + var tabOneButton = new Button + { + AutomationId = "NavigationButton", + Text = "Push me!" + }; + + tabOneButton.Clicked += TabOneButton_Clicked; + + var tabOnePage = new ContentPage { Content = tabOneButton }; + + var tabTwoPage = new ContentPage { Content = new Label { Text = "Go to TabOne" } }; + var tabOne = new Tab { Title = "TabOne" }; + var tabTwo = new Tab { Title = "TabTwo" }; + tabOne.Items.Add(tabOnePage); + tabTwo.Items.Add(tabTwoPage); + + Items.Add( + new TabBar + { + Items = { tabOne, tabTwo } + } + ); + } + + private void TabOneButton_Clicked(object sender, System.EventArgs e) + { + var subTabPageOne = new ContentPage + { + Content = new Label + { + Text = "SubPage One", + AutomationId = "SubTabLabel1", + VerticalTextAlignment = TextAlignment.Center, + } + }; + var subTabPageTwo = new ContentPage + { + Content = new Label + { + Text = "SubPage Two", + AutomationId = "SubTabLabel2", + VerticalTextAlignment = TextAlignment.Center, + } + }; + + var tabbedPage = new TabbedPage { Title = "TabbedPage" }; + tabbedPage.Children.Add(subTabPageOne); + tabbedPage.Children.Add(subTabPageTwo); + Shell.SetTabBarIsVisible(tabbedPage, false); + this.Navigation.PushAsync(tabbedPage); + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/GridExtension.cs b/src/Controls/tests/TestCases.HostApp/Issues/GridExtension.cs new file mode 100644 index 000000000000..e9d4bb863b9d --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/GridExtension.cs @@ -0,0 +1,38 @@ +using System; +using Microsoft.Maui.Controls; + +namespace Maui.Controls.Sample.Issues +{ + public static class GridExtension + { + public static void AddChild(this Grid grid, View view, int column, int row, int columnspan = 1, int rowspan = 1) + { + if (row < 0) + { + throw new ArgumentOutOfRangeException("row"); + } + if (column < 0) + { + throw new ArgumentOutOfRangeException("column"); + } + if (rowspan <= 0) + { + throw new ArgumentOutOfRangeException("rowspan"); + } + if (columnspan <= 0) + { + throw new ArgumentOutOfRangeException("columnspan"); + } + if (view == null) + { + throw new ArgumentNullException("view"); + } + + Grid.SetRow(view, row); + Grid.SetRowSpan(view, rowspan); + Grid.SetColumn(view, column); + Grid.SetColumnSpan(view, columnspan); + grid.Children.Add(view); + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs new file mode 100644 index 000000000000..822965147cda --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 10222, "[CollectionView] ObjectDisposedException if the page is closed during scrolling", PlatformAffected.iOS)] + public class Issue10222 : NavigationPage + { + public Issue10222() : base(new MainPage()) + { + } + + public class MainPage : ContentPage + { + public MainPage() + { + // Initialize ui here instead of ctor + Navigation.PushAsync(new ContentPage + { + Content = new Button + { + AutomationId = "goTo", + Text = "Go", + Command = new Command(async () => await Navigation.PushAsync(new CarouselViewTestPage())) + } + }); + } + + class CarouselViewTestPage : ContentPage + { + CollectionView cv; + public CarouselViewTestPage() + { + cv = new CollectionView + { + AutomationId = "collectionView", + Margin = new Thickness(0, 40), + ItemTemplate = new DataTemplate(() => + { + var label = new Label + { + HorizontalTextAlignment = TextAlignment.Center, + Margin = new Thickness(0, 100) + }; + label.SetBinding(Label.TextProperty, new Binding(".")); + return label; + }) + }; + Content = cv; + InitCV(); + } + + async void InitCV() + { + var items = new List(); + for (int i = 0; i < 10; i++) + { + items.Add($"items{i}"); + } + + cv.ItemsSource = items; + + //give the cv time to draw the items + await Task.Delay(1000); + + cv.ScrollTo(items.Count - 1); + + //give the cv time to scroll + var rand = new Random(); + await Task.Delay(rand.Next(10, 200)); + + await Navigation.PopAsync(false); + + } + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue10454.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue10454.cs new file mode 100644 index 000000000000..6970138b5c4a --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue10454.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.ObjectModel; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 10454, "CollectionView ChildAdded", PlatformAffected.All)] + public class Issue10454 : TestContentPage + { + const string Success = "Success"; + + protected override void Init() + { + Title = "Issue 10454"; + + BindingContext = new Issue10454ViewModel(); + + var layout = new StackLayout(); + + var collectionView = new CollectionView(); + collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Items"); + + collectionView.ItemTemplate = new DataTemplate(() => + { + var template = new DataTemplate(); + var content = new Grid + { + BackgroundColor = Colors.LightGray + }; + var label = new Label(); + label.SetBinding(Label.TextProperty, "."); + content.Children.Add(label); + + return content; + }); + + var labelInfo = new Label + { + FontSize = 18 + }; + + var successLabel = new Label(); + + layout.Children.Add(labelInfo); + layout.Children.Add(successLabel); + layout.Children.Add(collectionView); + + Content = layout; + + collectionView.ChildAdded += (sender, args) => + { + labelInfo.Text = $"ChildAdded {args.Element}"; + Console.WriteLine(labelInfo.Text); + + successLabel.Text = Success; + }; + + collectionView.ChildRemoved += (sender, args) => + { + labelInfo.Text = $"ChildRemoved {args.Element}"; + Console.WriteLine(labelInfo.Text); + }; + } + } + + [Preserve(AllMembers = true)] + public class Issue10454ViewModel : BindableObject + { + public Issue10454ViewModel() + { + LoadItems(); + } + + public ObservableCollection Items { get; set; } + + void LoadItems() + { + Items = new ObservableCollection(); + + for (int i = 0; i < 100; i++) + { + Items.Add($"Item {i + 1}"); + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue10563.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue10563.cs new file mode 100644 index 000000000000..68fc5ffee7df --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue10563.cs @@ -0,0 +1,137 @@ +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 10563, "[Bug] SwipeView Open methods does not work for RightItems", PlatformAffected.Android | PlatformAffected.iOS)] + public class Issue10563 : TestContentPage + { + const string OpenLeftId = "OpenLeftId"; + const string OpenRightId = "OpenRightId"; + const string OpenTopId = "OpenTopId"; + const string OpenBottomId = "OpenBottomId"; + const string CloseId = "CloseId"; + + public Issue10563() + { + + } + + protected override void Init() + { + Title = "Issue 10563"; + + var swipeLayout = new StackLayout + { + Margin = new Thickness(12) + }; + + var openLeftButton = new Button + { + AutomationId = OpenLeftId, + Text = "Open Left SwipeItem" + }; + + var openRightButton = new Button + { + AutomationId = OpenRightId, + Text = "Open Right SwipeItem" + }; + + var openTopButton = new Button + { + AutomationId = OpenTopId, + Text = "Open Top SwipeItem" + }; + + var openBottomButton = new Button + { + AutomationId = OpenBottomId, + Text = "Open Bottom SwipeItem" + }; + + var closeButton = new Button + { + AutomationId = CloseId, + Text = "Close SwipeView" + }; + + swipeLayout.Children.Add(openLeftButton); + swipeLayout.Children.Add(openRightButton); + swipeLayout.Children.Add(openTopButton); + swipeLayout.Children.Add(openBottomButton); + swipeLayout.Children.Add(closeButton); + + var swipeItem = new SwipeItem + { + BackgroundColor = Colors.Red, + IconImageSource = "calculator.png", + Text = "Issue 10563" + }; + + swipeItem.Invoked += (sender, e) => { DisplayAlert("SwipeView", "SwipeItem Invoked", "Ok"); }; + + var swipeItems = new SwipeItems { swipeItem }; + + swipeItems.Mode = SwipeMode.Reveal; + + var swipeContent = new Grid + { + BackgroundColor = Colors.Gray + }; + + var swipeLabel = new Label + { + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + Text = "Swipe to any direction" + }; + + swipeContent.Children.Add(swipeLabel); + + var swipeView = new SwipeView + { + HeightRequest = 60, + WidthRequest = 300, + LeftItems = swipeItems, + RightItems = swipeItems, + TopItems = swipeItems, + BottomItems = swipeItems, + Content = swipeContent, + Margin = new Thickness(0, 48) + }; + + swipeLayout.Children.Add(swipeView); + + Content = swipeLayout; + + openLeftButton.Clicked += (sender, e) => + { + swipeView.Open(OpenSwipeItem.LeftItems); + }; + + openRightButton.Clicked += (sender, e) => + { + swipeView.Open(OpenSwipeItem.RightItems); + }; + + openTopButton.Clicked += (sender, e) => + { + swipeView.Open(OpenSwipeItem.TopItems); + }; + + openBottomButton.Clicked += (sender, e) => + { + swipeView.Open(OpenSwipeItem.BottomItems); + }; + + closeButton.Clicked += (sender, e) => + { + swipeView.Close(); + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue10744.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue10744.cs new file mode 100644 index 000000000000..01fdbe1cff2b --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue10744.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 10744, "[Android] WebView.Eval crashes on Android with long string", + PlatformAffected.Android)] + public class Issue10744 : TestContentPage + { + Label _navigatedLabel; + WebView _webView; + + protected override void Init() + { + _navigatedLabel = new Label() + { + AutomationId = "navigatedLabel" + }; + + _webView = new WebView() + { + Source = "https://dotnet.microsoft.com/apps/xamarin", + Cookies = new System.Net.CookieContainer(), + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + HeightRequest = 600 + }; + + _webView.Navigating += (_, __) => + { + }; + + _webView.Navigated += (_, __) => + { + if (_navigatedLabel.Text == "Navigated") + return; + + _webView.Eval($"javascript:{String.Join(":", Enumerable.Range(0, 900000).ToArray())}"); + _navigatedLabel.Text = "Navigated"; + }; + + Content = new StackLayout() + { + Children = + { + new Label(){ Text = "If App hasn't crashed after navigating to the web page then this test has passed"}, + _navigatedLabel, + _webView + } + }; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11132.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue11132.cs new file mode 100644 index 000000000000..c383e8aa3ef1 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11132.cs @@ -0,0 +1,51 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 11132, "[Bug] [iOS] UpdateClip throws NullReferenceException when the Name of the Mask of the Layer is null", PlatformAffected.iOS)] + public class Issue11132 : TestContentPage + { + const string InstructionsId = "instructions"; + + public Issue11132() + { + + } + + protected override void Init() + { + Title = "Issue 11132"; + + var layout = new StackLayout(); + + var instructions = new Label + { + AutomationId = InstructionsId, + Padding = 12, + BackgroundColor = Colors.Black, + TextColor = Colors.White, + Text = "If the test works without exceptions (an orange rectangle is rendered), the test has passed." + }; + + var issue11132Control = new Issue11132Control + { + HeightRequest = 100 + }; + + layout.Children.Add(instructions); + layout.Children.Add(issue11132Control); + + Content = layout; + } + } + + [Preserve(AllMembers = true)] + public class Issue11132Control : View + { + + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11209.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue11209.xaml new file mode 100644 index 000000000000..e3dfb1e1e20f --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11209.xaml @@ -0,0 +1,58 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11209.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue11209.xaml.cs new file mode 100644 index 000000000000..e2e66af4438d --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11209.xaml.cs @@ -0,0 +1,71 @@ +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)] + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 11209, "[Bug] [iOS][SwipeView] Swipe view not handling tap gesture events until swiped", PlatformAffected.Android)] + public class Issue11209NavigationPage : NavigationPage + { + public Issue11209NavigationPage() : base(new Issue11209()) + { + } + } + + public partial class Issue11209 : TestContentPage + { + const string SwipeViewContent = "SwipeViewContent"; + const string Success = "Success"; + + public Issue11209() + { + InitializeComponent(); + } + + public List Items => new List { "short", "long word", "Extra long word", "word up" }; + + protected override void Init() + { + + } + + void SwipeItem_Invoked(object sender, EventArgs e) + { + Console.WriteLine("Hey i was invoked"); + } + + async void TapGestureRecognizer_Tapped(object sender, EventArgs e) + { + await Navigation.PushAsync(new Issue11209SecondPage()); + } + + [Preserve(AllMembers = true)] + public class Issue11209SecondPage : ContentPage + { + public Issue11209SecondPage() + { + Title = "Issue 11209"; + + var layout = new StackLayout(); + + var instructions = new Label + { + AutomationId = Success, + Padding = 12, + BackgroundColor = Colors.Black, + TextColor = Colors.White, + Text = "If navigated tapping an item from the CollectionView, the test has passed." + }; + + layout.Children.Add(instructions); + + Content = layout; + } + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11311.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue11311.cs new file mode 100644 index 000000000000..89ef83293fc6 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11311.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Windows.Input; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.None, 11311, "[Regression] CollectionView NSRangeException", PlatformAffected.iOS)] + public class Issue11311 : TestTabbedPage + { + const string Success = "Success"; + + protected override void Init() + { + Children.Add(FirstPage()); + Children.Add(CollectionViewPage()); + } + + ContentPage FirstPage() + { + var firstPage = new ContentPage + { + Title = "The first page", + Content = new Label { Text = Success } + }; + + firstPage.Appearing += (sender, args) => + { + if (firstPage.Parent is TabbedPage tabbedPage + && tabbedPage.Children[1] is ContentPage collectionViewPage + && collectionViewPage.Content is RefreshView refreshView) + { + refreshView.IsRefreshing = true; + } + }; + + return firstPage; + } + + ContentPage CollectionViewPage() + { + BindingContext = new _11311ViewModel(); + + var collectionView = new CollectionView + { + Footer = new BoxView { BackgroundColor = Colors.Red, HeightRequest = 53 } + }; + + collectionView.SetBinding(ItemsView.ItemsSourceProperty, nameof(_11311ViewModel.ScoreCollectionList)); + var refreshView = new RefreshView + { + Content = collectionView + }; + + + refreshView.SetBinding(RefreshView.CommandProperty, nameof(_11311ViewModel.PopulateCollectionCommand)); + refreshView.SetBinding(RefreshView.IsRefreshingProperty, nameof(_11311ViewModel.IsRefreshing)); + + var page = new ContentPage + { + Title = "CollectionView Page", + Content = refreshView + }; + + return page; + } + + class _11311ViewModel : INotifyPropertyChanged + { + bool _isRefreshing; + IEnumerable _scoreCollectionList; + + public _11311ViewModel() + { + PopulateCollectionCommand = new Command(ExecuteRefreshCommand); + _scoreCollectionList = Enumerable.Empty(); + } + + public event PropertyChangedEventHandler PropertyChanged; + + public ICommand PopulateCollectionCommand { get; } + + public IEnumerable ScoreCollectionList + { + get => _scoreCollectionList; + set + { + _scoreCollectionList = value; + OnPropertyChanged(); + } + } + + public bool IsRefreshing + { + get => _isRefreshing; + set + { + if (IsRefreshing != value) + { + _isRefreshing = value; + OnPropertyChanged(); + } + } + } + + void ExecuteRefreshCommand() + { + ScoreCollectionList = Enumerable.Range(0, 100); + IsRefreshing = false; + } + + void OnPropertyChanged([CallerMemberName] string propertyName = "") => + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11333.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue11333.xaml new file mode 100644 index 000000000000..4d7920ad9bfa --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11333.xaml @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11333.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue11333.xaml.cs new file mode 100644 index 000000000000..8cb6a20b4ef9 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11333.xaml.cs @@ -0,0 +1,42 @@ +using System; +using System.Diagnostics; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 11333, + "[Bug] SwipeView does not work on Android if child has TapGestureRecognizer", + PlatformAffected.Android)] + public partial class Issue11333 : TestContentPage + { + const string SwipeViewId = "SwipeViewId"; + + public Issue11333() + { + InitializeComponent(); + } + + protected override void Init() + { + } + + void OnTapGestureRecognizerOnTapped(object sender, EventArgs e) + { + Debug.WriteLine("Tapped"); + } + + void OnSwipeViewSwipeEnded(object sender, SwipeEndedEventArgs e) + { + ResultLabel.Text = e.IsOpen ? "Open" : "Close"; + } + } + + [Preserve(AllMembers = true)] + public class Issue11333Model + { + public string Title { get; set; } + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue1146.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue1146.cs new file mode 100644 index 000000000000..27805acbf3c7 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue1146.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.CustomAttributes; +using Microsoft.Maui.Controls.Internals; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 1146, "Disabled Switch in Button Gallery not rendering on all devices", PlatformAffected.Android)] + public class Issue1146 : TestContentPage + { + protected override void Init() + { + Content = new ScrollView + { + Content = new StackLayout + { + Padding = new Size(20, 20), + Children = { + new StackLayout { + Orientation = StackOrientation.Horizontal, + Children= { + new Switch() { IsEnabled = false , AutomationId="switch"}, + }, + }, + } + } + }; + } + } +} diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11769.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue11769.cs new file mode 100644 index 000000000000..7823536fbcad --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11769.cs @@ -0,0 +1,91 @@ +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.Internals; + +namespace Maui.Controls.Sample.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 11769, "[Bug] Shell throws exception when delay adding Shell Content", issueTestNumber: 2)] + public class Issue11769_DelayedShellContent : TestShell + { + protected override void Init() + { + Items.Add(new FlyoutItem() + { + Items = + { + new Tab() + } + }); + +#pragma warning disable CS0612 // Type or member is obsolete +#pragma warning disable CS0618 // Type or member is obsolete + Device.InvokeOnMainThreadAsync(() => + { + var shellContent = new ShellContent() + { + Content = new ContentPage() + { + Content = new Label() { Text = "Success" } + } + }; + + Items[0].Items[0].Items.Add(shellContent); + }); +#pragma warning restore CS0618 // Type or member is obsolete +#pragma warning restore CS0612 // Type or member is obsolete + } + } + + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 11769, "[Bug] Shell throws exception when delay adding Shell Section", issueTestNumber: 1)] + public class Issue11769_DelayedShellSection : TestShell + { + protected override void Init() + { + Items.Add(new FlyoutItem()); +#pragma warning disable CS0612 // Type or member is obsolete +#pragma warning disable CS0618 // Type or member is obsolete + Device.InvokeOnMainThreadAsync(() => + { + var tab = new Tab() + { + Items = + { + new ShellContent() + { + Content = new ContentPage() + { + Content = new Label() { Text = "Success" } + } + } + } + }; + + Items[0].Items.Add(tab); + }); +#pragma warning restore CS0618 // Type or member is obsolete +#pragma warning restore CS0612 // Type or member is obsolete + } + } + + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 11769, "[Bug] Shell throws exception when delay adding Shell Item", issueTestNumber: 0)] + public class Issue11769_DelayedShellItem : TestShell + { + protected override void Init() + { +#pragma warning disable CS0612 // Type or member is obsolete +#pragma warning disable CS0618 // Type or member is obsolete + Device.InvokeOnMainThreadAsync(() => + { + var page = AddBottomTab("Flyout Item"); + page.Content = new Label() + { + Text = "Success" + }; + }); +#pragma warning restore CS0618 // Type or member is obsolete +#pragma warning restore CS0612 // Type or member is obsolete + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11853.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue11853.xaml new file mode 100644 index 000000000000..40ec84a4f0a1 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11853.xaml @@ -0,0 +1,35 @@ + + + + + + + + + +