maui-linux/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issu.../Bugzilla57910.cs

258 строки
6.8 KiB
C#
Исходник Обычный вид История

using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System;
using System.Linq;
using System.ComponentModel;
using System.Collections.ObjectModel;
#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[NUnit.Framework.Category(Core.UITests.UITestCategories.Bugzilla)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Bugzilla, 57910, "ObjectDisposedException in Xamarin.Forms.Platform.Android.Renderers.ProgressBarRenderer", PlatformAffected.Android)]
public class Bugzilla57910 : QuickCollectNavigationPage
{
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.";
protected override void Init()
{
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<ListItemViewModel> _items;
string _footer;
string _header;
int _counter;
public ListPageViewModel()
{
_header = "Header!";
_footer = "Footer!";
_counter = 0;
_items = new ObservableCollection<ListItemViewModel>(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
Device.StartTimer(TimeSpan.FromMilliseconds((100)), () =>
{
Header = $"Header! {_counter++}";
Footer = $"Footer! {_counter++}";
return true;
});
}
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ListItemViewModel> 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
Device.StartTimer(TimeSpan.FromMilliseconds((1000)), () =>
{
DownloadProgressPercentage += 0.05d;
if (DownloadProgressPercentage > 0.99d)
{
State = InstallableState.Local;
}
return DownloadProgressPercentage != 1.0d;
});
}
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();
}
}
#if UITEST
[Test]
public void Bugzilla57910Test()
{
for (int i = 0; i < 10; i++)
{
RunningApp.WaitForElement(q => q.Marked(ButtonId));
RunningApp.Tap(q => q.Marked(ButtonId));
RunningApp.WaitForElement(q => q.Marked(Button2Id));
RunningApp.Tap(q => q.Marked(Button2Id));
}
}
#endif
}
}