This commit is contained in:
Stephane Delcroix 2019-08-06 10:07:12 +02:00
Родитель ca4d8b9059 e34b8fadb5
Коммит 5309a00268
22 изменённых файлов: 264 добавлений и 37 удалений

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

@ -256,8 +256,8 @@ namespace Xamarin.Forms.Controls.Issues
RunningApp.WaitForElement (q => q.Marked (DisappearingLabelId));
RunningApp.Screenshot ("There should be appearing and disappearing events for the Groups and Items.");
var appearing = int.Parse(RunningApp.Query(q => q.Marked(AppearingLabelId))[0].Text);
var disappearing = int.Parse(RunningApp.Query(q=> q.Marked(DisappearingLabelId))[0].Text);
var appearing = int.Parse(RunningApp.WaitForElement(AppearingLabelId)[0].ReadText());
var disappearing = int.Parse(RunningApp.WaitForElement(DisappearingLabelId)[0].ReadText());
Assert.IsTrue(appearing > 0, $"Test {_TestNumber}: No appearing events for groups found.");
Assert.IsTrue(disappearing > 0, $"Test {_TestNumber}: No disappearing events for groups found.");

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

@ -38,7 +38,7 @@ namespace Xamarin.Forms.Controls.Issues
public static async Task<Dictionary<string, double>> GetScenarioResults(string deviceId)
{
var response = await _client.GetAsync(GetScenarioResultsRoute + deviceId);
var response = await _client.GetAsync(GetScenarioResultsRoute + deviceId).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
return new Dictionary<string, double>();
@ -63,12 +63,12 @@ namespace Xamarin.Forms.Controls.Issues
};
var json = JsonConvert.SerializeObject(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.PostAsync(PostScenarioResultRoute + scenarioName, content);
var responseContent = await response.Content.ReadAsStringAsync();
var response = await _client.PostAsync(PostScenarioResultRoute + scenarioName, content).ConfigureAwait(false);
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var scenarioResult = JsonConvert.DeserializeObject<ScenarioResult>(responseContent);
await PostScenarioResultDetails(scenarioResult.Id, details);
await PostScenarioResultDetails(scenarioResult.Id, details).ConfigureAwait(false);
}
static async Task PostScenarioResultDetails(Guid scenarioResultId, Dictionary<string, PerformanceProvider.Statistic> details)
@ -84,7 +84,7 @@ namespace Xamarin.Forms.Controls.Issues
Name = detail.Key
};
var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
await _client.PostAsync(PostScenarioResultDetailsRoute + scenarioResultId, content);
await _client.PostAsync(PostScenarioResultDetailsRoute + scenarioResultId, content).ConfigureAwait(false);
}
}

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

@ -41,7 +41,7 @@ namespace Xamarin.Forms.Controls.Issues
PerformanceTracker _PerformanceTracker = new PerformanceTracker();
List<PerformanceScenario> _TestCases = new List<PerformanceScenario>();
int _TestNumber = 0;
Button nextButton;
PerformanceViewModel ViewModel => BindingContext as PerformanceViewModel;
protected override void Init()
@ -65,7 +65,7 @@ namespace Xamarin.Forms.Controls.Issues
_TestCases.AddRange(InflatePerformanceScenarios());
var nextButton = new Button { Text = Pending, IsEnabled = false, AutomationId = NextButtonId };
nextButton = new Button { Text = Pending, IsEnabled = false, AutomationId = NextButtonId };
nextButton.Clicked += NextButton_Clicked;
ViewModel.TestRunReferenceId = Guid.NewGuid();
@ -82,11 +82,30 @@ namespace Xamarin.Forms.Controls.Issues
};
Content = new StackLayout { Children = { testRunRef, nextButton, _PerformanceTracker } };
GetBenchmarkResults();
}
ViewModel.BenchmarkResults = Task.Run(() => PerformanceDataManager.GetScenarioResults(_DeviceIdentifier)).GetAwaiter().GetResult();
async void GetBenchmarkResults(int tryCount = 0)
{
bool success = false;
try
{
ViewModel.BenchmarkResults = await PerformanceDataManager.GetScenarioResults(_DeviceIdentifier);
success = true;
}
catch(Exception exc)
{
if (tryCount < 3)
GetBenchmarkResults(++tryCount);
else
nextButton.Text = exc.ToString();
}
nextButton.IsEnabled = true;
nextButton.Text = Next;
if (success)
{
nextButton.IsEnabled = true;
nextButton.Text = Next;
}
}
private static string GetBuildNumber()

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

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.Linq;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
using System.Threading;
using System.ComponentModel;
#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.None, 0, "Shell Gestures Test",
PlatformAffected.All)]
#if UITEST
[NUnit.Framework.Category(UITestCategories.Shell)]
#endif
public class ShellGestures : TestShell
{
const string Success = "Success";
const string SuccessId = "SuccessId";
protected override void Init()
{
var gesturePage = CreateContentPage(shellItemTitle: "Gestures");
var label = new Label()
{
Text = "Swipe Right and Text Should Change to Success",
AutomationId = SuccessId
};
gesturePage.Content = new StackLayout()
{
Children =
{
new Label(){ Text = "Click through flyout items for all the tests"},
label
},
GestureRecognizers =
{
new SwipeGestureRecognizer()
{
Direction = SwipeDirection.Right,
Command = new Command(() =>
{
label.Text = Success;
})
}
}
};
}
#if UITEST && (__IOS__ || __ANDROID__)
[Test]
public void GesturesTest()
{
RunningApp.WaitForElement(SuccessId);
RunningApp.SwipeLeftToRight(SuccessId);
RunningApp.WaitForElement(Success);
}
#endif
}
}

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

@ -613,11 +613,13 @@ namespace Xamarin.Forms.Controls
return page;
}
public ContentPage CreateContentPage()
public ContentPage CreateContentPage(string shellItemTitle = null)
{
shellItemTitle = shellItemTitle ?? $"Item: {Items.Count}";
ContentPage page = new ContentPage();
ShellItem item = new ShellItem()
{
Title = shellItemTitle,
Items =
{
new ShellSection()

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

@ -22,6 +22,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue6644.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)ShellGestures.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellInsets.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGrouping.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5412.cs" />

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

@ -2,7 +2,7 @@
{
internal class PropagateCodeGallery : ContentPage
{
public PropagateCodeGallery(IItemsLayout itemsLayout)
public PropagateCodeGallery(IItemsLayout itemsLayout, int itemsCount = 2)
{
Title = $"Propagate FlowDirection=RTL";
@ -21,16 +21,20 @@
var itemTemplate = ExampleTemplates.PropagationTemplate();
var emptyView = ExampleTemplates.PropagationTemplate().CreateContent() as View;
var collectionView = new CollectionView
{
ItemsLayout = itemsLayout,
ItemTemplate = itemTemplate,
EmptyView = emptyView
};
var generator = new ItemsSourceGenerator(collectionView, initialItems: 2);
var generator = new ItemsSourceGenerator(collectionView, initialItems: itemsCount);
layout.Children.Add(generator);
var instructions = new Label();
UpdateInstructions(layout, instructions);
UpdateInstructions(layout, instructions, itemsCount == 0);
Grid.SetRow(instructions, 2);
layout.Children.Add(instructions);
@ -44,7 +48,7 @@
? FlowDirection.LeftToRight
: FlowDirection.RightToLeft;
UpdateInstructions(layout, instructions);
UpdateInstructions(layout, instructions, itemsCount == 0);
};
switchLayout.Children.Add(switchLabel);
@ -62,9 +66,16 @@
generator.GenerateItems();
}
static void UpdateInstructions(Layout layout, Label instructions)
static void UpdateInstructions(Layout layout, Label instructions, bool isEmpty)
{
instructions.Text = $"The buttons in each item should be in order from {layout.FlowDirection}.";
if (isEmpty)
{
instructions.Text = $"The buttons in the empty view should be in order from {layout.FlowDirection}.";
}
else
{
instructions.Text = $"The buttons in each item should be in order from {layout.FlowDirection}.";
}
}
}
}

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

@ -18,6 +18,9 @@
descriptionLabel,
GalleryBuilder.NavButton("Propagate FlowDirection", () =>
new PropagateCodeGallery(ListItemsLayout.Vertical), Navigation),
GalleryBuilder.NavButton("Propagate FlowDirection in EmptyView", () =>
new PropagateCodeGallery(ListItemsLayout.Vertical, 0), Navigation),
}
}
};

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

@ -30,7 +30,8 @@ namespace Xamarin.Forms.Internals
public static void SetNameScope(BindableObject bindable, INameScope value)
{
bindable.SetValue(NameScopeProperty, value);
if (bindable.GetValue(NameScopeProperty) == null)
bindable.SetValue(NameScopeProperty, value);
}
}
}

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

@ -131,6 +131,11 @@ namespace Xamarin.Forms
public void AddLogicalChild(Element element)
{
if(element == null)
{
return;
}
_logicalChildren.Add(element);
PropertyPropagationExtensions.PropagatePropertyChanged(null, element);
@ -140,6 +145,11 @@ namespace Xamarin.Forms
public void RemoveLogicalChild(Element element)
{
if (element == null)
{
return;
}
element.Parent = null;
_logicalChildren.Remove(element);
}

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

@ -2,6 +2,7 @@ using System;
using Android.Content;
using Android.Runtime;
using Android.Support.V4.View;
using Android.Util;
using Android.Views;
namespace Xamarin.Forms.Platform.Android.AppCompat
@ -12,6 +13,10 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
{
}
public FormsViewPager(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
protected FormsViewPager(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}

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

@ -8,7 +8,7 @@ using Object = Java.Lang.Object;
namespace Xamarin.Forms.Platform.Android
{
public partial class EmptyViewAdapter : RecyclerView.Adapter
public class EmptyViewAdapter : RecyclerView.Adapter
{
int _itemViewType;
object _emptyView;
@ -53,27 +53,33 @@ namespace Xamarin.Forms.Platform.Android
{
templatedItemViewHolder.Recycle(ItemsView);
}
else if (holder is SimpleViewHolder emptyViewHolder)
{
emptyViewHolder.Recycle(ItemsView);
}
base.OnViewRecycled(holder);
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
if (EmptyView == null || EmptyViewTemplate == null)
if (EmptyView == null)
{
return;
}
if (holder is TemplatedItemViewHolder templatedItemViewHolder)
if (holder is SimpleViewHolder emptyViewHolder && emptyViewHolder.View != null)
{
// For templated empty views, this will happen on bind. But if we just have a plain-old View,
// we need to add it as a "child" of the ItemsView here so that stuff like Visual and FlowDirection
// propagate to the controls in the EmptyView
ItemsView.AddLogicalChild(emptyViewHolder.View);
}
else if (holder is TemplatedItemViewHolder templatedItemViewHolder && EmptyViewTemplate != null)
{
// Use EmptyView as the binding context for the template
templatedItemViewHolder.Bind(EmptyView, ItemsView);
}
if (!(holder is SimpleViewHolder))
{
return;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)

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

@ -472,6 +472,8 @@ namespace Xamarin.Forms.Platform.Android
_emptyViewAdapter.EmptyViewTemplate = emptyViewTemplate;
_emptyCollectionObserver.Start(ItemsViewAdapter);
_emptyViewAdapter.NotifyDataSetChanged();
}
else
{

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

@ -15,6 +15,11 @@ namespace Xamarin.Forms.Platform.Android
public View View { get; }
public void Recycle(ItemsView itemsView)
{
itemsView.RemoveLogicalChild(View);
}
public static SimpleViewHolder FromText(string text, Context context, bool fill = true)
{
var textView = new TextView(context) { Text = text };

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

@ -144,6 +144,7 @@ namespace Xamarin.Forms.Platform.Android
_viewPager = new FormsViewPager(Context)
{
LayoutParameters = new LP(LP.MatchParent, LP.MatchParent),
EnableGesture = false
};
_viewPager.AddOnPageChangeListener(this);

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

@ -328,6 +328,11 @@ namespace Xamarin.Forms.Platform.iOS
if (_emptyViewFormsElement != null)
{
if (ItemsView.EmptyViewTemplate == null)
{
ItemsView.AddLogicalChild(_emptyViewFormsElement);
}
// Now that the native empty view's frame is sized to the UICollectionView, we need to handle
// the Forms layout for its content
_emptyViewFormsElement.Layout(_emptyUIView.Frame.ToRectangle());
@ -339,6 +344,7 @@ namespace Xamarin.Forms.Platform.iOS
if (_currentBackgroundIsEmptyView)
{
CollectionView.BackgroundView = _backgroundUIView;
ItemsView.RemoveLogicalChild(_emptyViewFormsElement);
}
_currentBackgroundIsEmptyView = false;

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

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh6192">
<StackLayout BindableLayout.ItemsSource="{Binding Items}" x:Name="bindableStackLayout">
<BindableLayout.ItemTemplate>
<DataTemplate>
<local:Gh6192Template />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ContentPage>

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

@ -0,0 +1,36 @@
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class Gh6192 : ContentPage
{
public Gh6192() => InitializeComponent();
public Gh6192(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
class Tests
{
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
[TearDown] public void TearDown() => Device.PlatformServices = null;
[Test]
public void XamlCDoesntFail([Values(false, true)]bool useCompiledXaml)
{
var layout = new Gh6192(useCompiledXaml);
layout.BindingContext = new {
Items = new[] {
new {
Options = new [] { "Foo", "Bar" },
}
}
};
var lv = (layout.bindableStackLayout.Children[0] as ContentView).Content as ListView;
lv.ItemTemplate.CreateContent();
}
}
}
}

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

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh6192Template"
x:Name="listView">
<ListView ItemsSource="{Binding Options}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding .}" />
<Button
BackgroundColor="Blue"
Command="{Binding Source={x:Reference Name=listView}, Path=Parent.BindingContext.ShowMessageCommand}"
CommandParameter="{Binding .}"
Text="Show Message" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentView>

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

@ -0,0 +1,7 @@
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class Gh6192Template : ContentView
{
public Gh6192Template() => InitializeComponent();
}
}

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

@ -42,4 +42,4 @@ namespace Xamarin.Forms.Xaml
throw new XamlParseException($"Can not find the object referenced by `{Name}`", serviceProvider);
}
}
}
}

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

@ -170,16 +170,16 @@ namespace Xamarin.Forms.Xaml.Internals
public object FindByName(string name)
{
if (scope != null)
return scope.FindByName(name);
object value;
if ((value = scope?.FindByName(name)) != null)
return value;
for (var i = 0; i < objectAndParents.Length; i++) {
var bo = objectAndParents[i] as BindableObject;
if (bo == null) continue;
var ns = NameScope.GetNameScope(bo) as INameScope;
if (ns == null) continue;
var value = ns.FindByName(name);
if (value != null)
if (!(objectAndParents[i] is BindableObject bo))
continue;
if (!(NameScope.GetNameScope(bo) is INameScope ns))
continue;
if ((value = ns.FindByName(name)) != null)
return value;
}
return null;