зеркало из https://github.com/DeGsoft/maui-linux.git
Merge branch '4.2.0'
This commit is contained in:
Коммит
5309a00268
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче