This commit is contained in:
Samantha Houts 2019-09-12 15:56:32 -07:00
Родитель bde233fe9e 24fec62cdd
Коммит 151bdb5ebf
90 изменённых файлов: 1798 добавлений и 468 удалений

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

@ -18,7 +18,7 @@
</group>
<group targetFramework="MonoAndroid81">
<dependency id="Xamarin.GooglePlayServices.Maps" version="60.1142.1"/>
<dependency id="Xamarin.Android.Support.v7.AppCompat" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.v7.AppCompat" version="28.0.0.3"/>
<dependency id="Xamarin.Forms" version="$version$"/>
</group>
<group targetFramework="tizen40">

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

@ -20,8 +20,8 @@
<dependency id="Xamarin.Forms" version="$version$"/>
</group>
<group targetFramework="MonoAndroid90">
<dependency id="Xamarin.Android.Support.Design" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.v7.AppCompat" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.Design" version="28.0.0.3"/>
<dependency id="Xamarin.Android.Support.v7.AppCompat" version="28.0.0.3"/>
</group>
<group targetFramework="Xamarin.iOS10">
<dependency id="Xamarin.iOS.MaterialComponents" version="72.2.0.1"/>

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

@ -14,11 +14,11 @@
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<dependencies>
<group targetFramework="MonoAndroid81">
<dependency id="Xamarin.Android.Support.v4" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.Design" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.v7.AppCompat" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.v7.CardView" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.CustomTabs" version="28.0.0.1"/>
<dependency id="Xamarin.Android.Support.v4" version="28.0.0.3"/>
<dependency id="Xamarin.Android.Support.Design" version="28.0.0.3"/>
<dependency id="Xamarin.Android.Support.v7.AppCompat" version="28.0.0.3"/>
<dependency id="Xamarin.Android.Support.v7.CardView" version="28.0.0.3"/>
<dependency id="Xamarin.Android.Support.CustomTabs" version="28.0.0.3"/>
</group>
<group targetFramework="uap10.0">
<dependency id="NETStandard.Library" version="2.0.1"/>

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

@ -113,6 +113,7 @@
OptimizeIL = "true"
DebugSymbols = "$(DebugSymbols)"
DebugType = "$(DebugType)"
ValidateOnly = "$(XFXamlCValidateOnly)"
KeepXamlResources = "$(XFKeepXamlResources)" />
<Touch Files="$(IntermediateOutputPath)XamlC.stamp" AlwaysCreate="True" />
<ItemGroup>

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

@ -113,8 +113,8 @@
<Project>{e1586ce6-8eac-4388-a15a-1aabf108b5f8}</Project>
<Name>Xamarin.Forms.Material.Android</Name>
</ProjectReference>
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

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

@ -269,21 +269,21 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Annotations" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Compat" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Core.UI" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Fragment" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Transition" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.Palette" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Annotations" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Compat" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Core.UI" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Fragment" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Transition" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.Palette" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
</Project>

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

@ -69,8 +69,8 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
</Project>

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

@ -33,7 +33,12 @@ namespace Xamarin.Forms.Build.Tasks
internal string Type { get; set; }
internal MethodDefinition InitCompForType { get; private set; }
internal bool ReadOnly { get; set; }
/// <summary>
/// Enable to optimize for shorter build time
/// e.g. OptimizeIL unused, Debug symbols not loaded, no assemblies written
/// </summary>
public bool ValidateOnly { get; set; }
public override bool Execute(out IList<Exception> thrownExceptions)
{
@ -72,8 +77,8 @@ namespace Xamarin.Forms.Build.Tasks
var readerParameters = new ReaderParameters {
AssemblyResolver = resolver,
ReadWrite = !ReadOnly,
ReadSymbols = debug,
ReadWrite = !ValidateOnly,
ReadSymbols = debug && !ValidateOnly, // We don't need symbols for ValidateOnly, since we won't be writing
};
using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(Path.GetFullPath(Assembly),readerParameters)) {
@ -147,24 +152,29 @@ namespace Xamarin.Forms.Build.Tasks
(string)xamlFilePathAttr.ConstructorArguments[0].Value :
resource.Name;
var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
if (initCompRuntime != null)
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}__InitComponentRuntime already exists... not creating");
else {
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
initCompRuntime.Body.InitLocals = true;
LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
initCompRuntime.Body = new MethodBody(initCompRuntime);
var iCRIl = initCompRuntime.Body.GetILProcessor();
foreach (var instr in initComp.Body.Instructions)
iCRIl.Append(instr);
initComp.Body.Instructions.Clear();
initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
initComp.Body.InitLocals = true;
typeDef.Methods.Add(initCompRuntime);
LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
MethodDefinition initCompRuntime = null;
if (!ValidateOnly)
{
initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
if (initCompRuntime != null)
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}__InitComponentRuntime already exists... not creating");
else
{
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
initCompRuntime.Body.InitLocals = true;
LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
initCompRuntime.Body = new MethodBody(initCompRuntime);
var iCRIl = initCompRuntime.Body.GetILProcessor();
foreach (var instr in initComp.Body.Instructions)
iCRIl.Append(instr);
initComp.Body.Instructions.Clear();
initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
initComp.Body.InitLocals = true;
typeDef.Methods.Add(initCompRuntime);
LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
}
}
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
@ -197,6 +207,9 @@ namespace Xamarin.Forms.Build.Tasks
LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
if (ValidateOnly)
continue;
if (OptimizeIL) {
LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Optimizing IL");
initComp.Body.Optimize();
@ -224,14 +237,14 @@ namespace Xamarin.Forms.Build.Tasks
}
}
}
if (ValidateOnly) {
LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}ValidateOnly=True. Skipping writing assembly.");
return success;
}
if (!hasCompiledXamlResources) {
LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}No compiled resources. Skipping writing assembly.");
return success;
}
if (ReadOnly)
return success;
LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}Writing the assembly");
try {

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

@ -0,0 +1,24 @@
using System;
using Android.Content;
using Android.OS;
using Xamarin.Forms;
using Xamarin.Forms.ControlGallery.Android;
using Xamarin.Forms.Controls;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ApiLabel), typeof(ApiLabelRenderer))]
namespace Xamarin.Forms.ControlGallery.Android
{
public class ApiLabelRenderer : Xamarin.Forms.Platform.Android.FastRenderers.LabelRenderer
{
public ApiLabelRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
Element.Text = ((int)Build.VERSION.SdkInt).ToString();
base.OnElementChanged(e);
}
}
}

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

@ -112,6 +112,7 @@
<Compile Include="..\Xamarin.Forms.Controls\GalleryPages\OpenGLGalleries\AdvancedOpenGLGallery.cs">
<Link>GalleryPages\AdvancedOpenGLGallery.cs</Link>
</Compile>
<Compile Include="ApiLabelRenderer.cs" />
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\default.css" />
@ -341,21 +342,21 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Annotations" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Compat" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Core.UI" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Fragment" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Transition" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.Palette" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Animated.Vector.Drawable" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Annotations" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Compat" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Core.UI" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Fragment" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Transition" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.Palette" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\fonts\ionicons.ttf">

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

@ -0,0 +1,21 @@
using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.ControlGallery.iOS;
using Xamarin.Forms.Controls;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(ApiLabel), typeof(ApiLabelRenderer))]
namespace Xamarin.Forms.ControlGallery.iOS
{
public class ApiLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
Element.Text = UIDevice.CurrentDevice.SystemVersion.ToString();
base.OnElementChanged(e);
}
}
}

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

@ -126,6 +126,7 @@
<Compile Include="CustomEffects\GradientEffect.cs" />
<Compile Include="CustomRenderers\CustomRenderer.cs" />
<Compile Include="CustomRenderers\RoundedLabelRenderer.cs" />
<Compile Include="ApiLabelRenderer.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Xamarin.Forms.Controls\Xamarin.Forms.Controls.csproj">

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

@ -74,6 +74,12 @@ namespace Xamarin.Forms.Controls.Issues
RunningApp.Tap (q => q.Marked ("btnDismissModal"));
RunningApp.Tap (q => q.Marked ("btnMaster"));
}
else
{
// Wait for the test to finish loading before exiting otherwise
// the next UI test might start running while this is still loading
RunningApp.WaitForElement(q => q.Marked("btnModal"));
}
}
[TearDown]

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

@ -45,7 +45,7 @@ namespace Xamarin.Forms.Controls.Issues
#if UITEST && __IOS__
[Test]
[Category(UITestCategories.ManualReview)]
[Ignore]
[Ignore("Fails sometimes")]
public void Bugzilla35736Test()
{
RunningApp.WaitForElement(q => q.Marked("Bugzilla35736Editor"));

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

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.CollectionView)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.None, 0, "CollectionView ItemsSource Types", PlatformAffected.All)]
public class CollectionViewItemsSourceTypes : TestContentPage
{
protected override void Init()
{
#if APP
FlagTestHelpers.SetCollectionViewTestFlag();
#endif
Content = new StackLayout()
{
Children =
{
new Label()
{
Text = "If you see three 900s this test has passed"
},
new CollectionView()
{
ItemsSource = new[] { 900 },
HeightRequest = 50
},
new CollectionView()
{
ItemsSource = new[] { "900" }.ToList<object>(),
HeightRequest = 50
},
new CollectionView()
{
ItemsSource = new ObservableCollection<string>(new[] { "900" }),
HeightRequest = 50
}
}
};
}
#if UITEST
[Test]
public void CollectionViewItemsSourceTypesDisplayAndDontCrash()
{
RunningApp.QueryUntilPresent(() =>
{
var result = RunningApp.WaitForElement("900");
if (result.Length == 3)
return result;
return null;
});
}
#endif
}
}

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

@ -0,0 +1,11 @@
using System;
namespace Xamarin.Forms.Controls
{
public class ApiLabel : Label
{
public ApiLabel()
{
AutomationId = "ApiLabel";
}
}
}

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

@ -0,0 +1,356 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
using System.Threading.Tasks;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[NUnit.Framework.Category(UITestCategories.CollectionView)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 6889, "Labels disappearing in CollectionView", PlatformAffected.Android)]
public class Issue6889 : TestNavigationPage
{
protected override void Init()
{
#if APP
Device.SetFlags(new List<string>(Device.Flags ?? new List<string>()) { "CollectionView_Experimental" });
PushAsync(CreateRoot());
#endif
}
public ContentPage CreateRoot()
{
var page = new ContentPage { Title = "Issue6889" };
var layout = new StackLayout();
var instructions = new Label { Text = "Scroll the CollectionView below up and down quickly several times."
+ " If any rows of labels disappear, this test has failed" };
layout.Children.Add(instructions);
var cv = new CollectionView();
var template = new DataTemplate(() => {
var grid = new Grid
{
ColumnDefinitions = new ColumnDefinitionCollection
{
new ColumnDefinition { Width = GridLength.Auto },
new ColumnDefinition { Width = GridLength.Auto }
}
};
var label1 = new Label { HorizontalOptions = LayoutOptions.Start };
label1.SetBinding(Label.TextProperty, new Binding("Text1"));
grid.Children.Add(label1);
Grid.SetColumn(label1, 0);
var label2 = new Label { HorizontalOptions = LayoutOptions.StartAndExpand };
label2.SetBinding(Label.TextProperty, new Binding("Text2"));
grid.Children.Add(label2);
Grid.SetColumn(label2, 1);
return grid;
});
cv.ItemTemplate = template;
cv.SetBinding(ItemsView.ItemsSourceProperty, new Binding("SampleList"));
layout.Children.Add(cv);
page.Content = layout;
page.BindingContext = new _6889MainViewModel();
return page;
}
}
[Preserve(AllMembers = true)]
public class _6889TextModel
{
public string Text1 { get; set; }
public string Text2 { get; set; }
}
[Preserve(AllMembers = true)]
public class _6889MainViewModel
{
public _6889MainViewModel()
{
SampleList = new ObservableCollection<_6889TextModel>
{
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
new _6889TextModel { Text1="Text1",Text2="Text2"},
};
}
public ObservableCollection<_6889TextModel> SampleList { get; set; }
}
}

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

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.ComponentModel;
using System.Collections.ObjectModel;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[NUnit.Framework.Category(UITestCategories.CollectionView)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 7128, "[iOS] Changing model property scrolls CollectionView back to top",
PlatformAffected.iOS)]
public class Issue7128 : TestNavigationPage
{
protected override void Init()
{
FlagTestHelpers.SetCollectionViewTestFlag();
PushAsync(CreateRoot());
}
class _7128Model : INotifyPropertyChanged
{
private string _url;
private string _text;
public _7128Model(string url, string text)
{
Url = url;
Text = text;
}
public event PropertyChangedEventHandler PropertyChanged;
public string Url
{
get => _url;
set
{
_url = value;
OnPropertyChanged();
}
}
public string Text
{
get => _text;
set
{
_text = value;
OnPropertyChanged();
}
}
protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
View Template()
{
var layout = new Grid();
layout.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
layout.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
var image = new Image { Aspect = Aspect.AspectFill };
image.SetBinding(Image.SourceProperty, new Binding("Url"));
var label = new Label { Margin = 10, BackgroundColor = Color.Red, HorizontalOptions = LayoutOptions.Fill };
label.SetBinding(Label.TextProperty, new Binding("Text"));
layout.Children.Add(image);
layout.Children.Add(label);
Grid.SetRow(image, 0);
Grid.SetRow(image, 1);
var tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += Tapped;
label.GestureRecognizers.Add(tapGesture);
return layout;
}
void Tapped(object sender, EventArgs e)
{
var label = sender as Label;
var model = (_7128Model)label.BindingContext;
model.Text = DateTime.UtcNow.Millisecond.ToString();
}
Page CreateRoot()
{
var page = new ContentPage() { Title = "Issue7128" };
var layout = new StackLayout() { Padding = 5 };
var instructions = new Label { Text = "Scroll the CollectionView down several pages, then click on one " +
"of the labels. The text of the label should change, but the CollectionView should not scroll to a " +
"different location. If it does scroll, the test has failed."
};
layout.Children.Add(instructions);
var cv = new CollectionView
{
ItemTemplate = new DataTemplate(() => Template())
};
var source = new ObservableCollection<_7128Model>();
var images = new string[] {
"https://raw.githubusercontent.com/xamarin/Xamarin.Forms/master/Xamarin.Forms.ControlGallery.iOS/oasis.jpg",
"https://raw.githubusercontent.com/xamarin/Xamarin.Forms/master/Xamarin.Forms.ControlGallery.iOS/photo.jpg",
"https://raw.githubusercontent.com/xamarin/Xamarin.Forms/master/Xamarin.Forms.ControlGallery.iOS/xamarinstore.jpg",
"https://raw.githubusercontent.com/xamarin/Xamarin.Forms/master/Xamarin.Forms.ControlGallery.iOS/crimson.jpg",
"https://raw.githubusercontent.com/xamarin/Xamarin.Forms/master/Xamarin.Forms.ControlGallery.WindowsUniversal/cover1.jpg"
};
for (int n = 0; n < 35; n++)
{
source.Add(new _7128Model(images[n % 5], $"{n}.jpg"));
}
cv.ItemsSource = source;
layout.Children.Add(cv);
page.Content = layout;
return page;
}
}
}

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

@ -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 System.Threading.Tasks;
#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 7329, "[Android] ListView scroll not working when inside a ScrollView",
PlatformAffected.Android)]
#if UITEST
[NUnit.Framework.Category(UITestCategories.ListView)]
[NUnit.Framework.Category(UITestCategories.ScrollView)]
#endif
public class Issue7329 : TestContentPage
{
ListView listView = null;
protected override void Init()
{
listView = new ListView() { AutomationId = "NestedListView" };
listView.ItemsSource = Enumerable.Range(0, 200).Select(x=> new Data() { Text = x }).ToList();
Content = new ScrollView()
{
AutomationId = "ParentScrollView",
Content = new StackLayout()
{
Children =
{
new ApiLabel(),
new Label() { Text = "If the List View can scroll the test has passed"},
listView
}
}
};
}
[Preserve(AllMembers = true)]
public class Data
{
public int Text { get; set; }
public override string ToString()
{
return Text.ToString();
}
}
#if UITEST
[Test]
public void ScrollListViewInsideScrollView()
{
#if __ANDROID__
if (!RunningApp.IsApiHigherThan(21))
return;
#endif
RunningApp.WaitForElement("1");
RunningApp.ScrollDownTo("30", strategy: ScrollStrategy.Gesture);
}
#endif
}
}

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

@ -0,0 +1,46 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.Threading.Tasks;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.ListView)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 7371, "iOS race condition(or not checking for null) of refreshing(offset animation) causes NullReferenceException", PlatformAffected.iOS)]
public class Issue7371 : TestContentPage
{
ListView ListView => Content as ListView;
protected override void Init()
{
Content = new ListView();
}
protected override void OnAppearing()
{
base.OnAppearing();
ListView.IsRefreshing = true;
Application.Current.MainPage = new ContentPage() { Content = new Label { Text = "Success", VerticalOptions = LayoutOptions.Center } };
ListView.IsRefreshing = false;
}
#if UITEST
[Test]
public async Task RefreshingListViewCrashesWhenDisposedTest()
{
await Task.Delay(500);
RunningApp.WaitForElement(q => q.Marked("Success"));
}
#endif
}
}

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

@ -240,9 +240,7 @@ namespace Xamarin.Forms.Controls
public void SwipeRight()
{
#pragma warning disable 618
_app.SwipeRight();
#pragma warning restore 618
SwipeLeftToRight();
}
public void SwipeLeftToRight(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)
@ -257,9 +255,7 @@ namespace Xamarin.Forms.Controls
public void SwipeLeft()
{
#pragma warning disable 618
_app.SwipeLeft();
#pragma warning restore 618
SwipeRightToLeft();
}
public void SwipeRightToLeft(double swipePercentage = 0.67, int swipeSpeed = 500, bool withInertia = true)

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

@ -783,7 +783,7 @@ namespace Xamarin.Forms.Controls.Issues
[SetUpFixture]
public class IssuesSetup
{
[SetUp]
[OneTimeSetUp]
public void RunBeforeAnyTests()
{
AppSetup.RunningApp = AppSetup.Setup(null);

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

@ -9,6 +9,7 @@
<Import_RootNamespace>Xamarin.Forms.Controls.Issues</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewItemsSourceTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1455.xaml.cs">
<DependentUpon>Issue1455.xaml</DependentUpon>
<SubType>Code</SubType>
@ -18,7 +19,9 @@
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewItemsUpdatingScrollMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3475.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6889.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6945.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7329.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7290.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7240.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5046.xaml.cs">
@ -38,6 +41,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ScrollToGroup.cs" />
<Compile Include="$(MSBuildThisFileDirectory)NestedCollectionViews.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellFlyoutBehavior.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7128.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellGestures.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellBackButtonBehavior.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7102.cs" />
@ -568,6 +572,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla39853.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MultipleClipToBounds.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6994.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7371.cs" />
<Compile Include="$(MSBuildThisFileDirectory)_TemplateMarkup.xaml.cs">
<DependentUpon>_TemplateMarkup.xaml</DependentUpon>
<SubType>Code</SubType>
@ -1042,6 +1047,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue7053.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6894.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue6929.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\ApiLabel.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
@ -1374,4 +1380,4 @@
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>

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

@ -46,12 +46,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NUnit" Version="2.6.4" />
<PackageReference Include="NUnitTestAdapter">
<Version>2.2.0</Version>
</PackageReference>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
<PackageReference Include="Xamarin.UITest" Version="2.2.7" />
<PackageReference Include="Xamarin.UITest" Version="3.0.3" />
<PackageReference Include="NUnit3TestAdapter">
<Version>3.15.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="BaseViewContainerRemoteAndroid.cs" />

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

@ -17,7 +17,7 @@ namespace Xamarin.Forms.Core.UITests
public static AppRect ScreenBounds { get; set; }
[TestFixtureTearDown]
[OneTimeTearDown]
protected virtual void FixtureTeardown()
{
}
@ -45,7 +45,7 @@ namespace Xamarin.Forms.Core.UITests
[SetUp]
protected virtual void TestSetup()
{
EnsureMemory();
//EnsureMemory();
}
[TearDown]
@ -55,9 +55,7 @@ namespace Xamarin.Forms.Core.UITests
protected abstract void NavigateToGallery();
#pragma warning disable 618
[TestFixtureSetUp]
#pragma warning restore 618
[OneTimeSetUp]
protected virtual void FixtureSetup()
{
ResetApp();
@ -111,7 +109,6 @@ namespace Xamarin.Forms.Core.UITests
}
}
}
#if UITEST
namespace Xamarin.Forms.Core.UITests
@ -121,7 +118,7 @@ namespace Xamarin.Forms.Core.UITests
[SetUpFixture]
public class CoreUITestsSetup
{
[SetUp]
[OneTimeSetUp]
public void RunBeforeAnyTests()
{
LaunchApp();
@ -138,4 +135,4 @@ namespace Xamarin.Forms.Core.UITests
}
}
#endif
#endif

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

@ -5,6 +5,7 @@ using Xamarin.UITest;
using Xamarin.UITest.Queries;
using System.Text.RegularExpressions;
using System.Threading;
using Xamarin.Forms.Controls.Issues;
#if __IOS__
using Xamarin.UITest.iOS;
#endif
@ -32,6 +33,16 @@ namespace Xamarin.UITest
return results;
}
public static bool IsApiHigherThan(this IApp app, int apiLevel, string apiLabelId = "ApiLevel")
{
var api = Convert.ToInt32(app.WaitForElement("ApiLabel")[0].ReadText());
if (api < apiLevel)
return false;
return true;
}
#if __IOS__
public static void SendAppToBackground(this IApp app, TimeSpan timeSpan)
{

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

@ -8,7 +8,7 @@ namespace Xamarin.Forms.Core.UnitTests
{
[Test]
//https://bugzilla.xamarin.com/show_bug.cgi?id=51424
public async void AnimationRepeats()
public async Task AnimationRepeats()
{
var box = new BoxView();
Assume.That(box.Rotation, Is.EqualTo(0d));

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

@ -1588,7 +1588,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That (() => bindable.SetBinding (MockBindable.TextProperty, new Binding ("Text2")), Throws.Nothing);
Assert.That (bindable.Text, Is.EqualTo (MockBindable.TextProperty.DefaultValue));
Assert.That (log.Messages.Count, Is.EqualTo (1), "An error was not logged");
Assert.That (log.Messages[0], Is.StringContaining (String.Format (BindingExpression.PropertyNotFoundErrorMessage,
Assert.That (log.Messages[0], Does.Contain(String.Format (BindingExpression.PropertyNotFoundErrorMessage,
"Text2",
"Xamarin.Forms.Core.UnitTests.BindingUnitTests+DifferentViewModel",
"Xamarin.Forms.Core.UnitTests.MockBindable",
@ -1607,7 +1607,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That (bindable.Text, Is.EqualTo ("Foo"));
Assert.That (log.Messages.Count, Is.Not.GreaterThan (1), "Too many errors were logged");
Assert.That (log.Messages[0], Is.StringContaining (String.Format (BindingExpression.PropertyNotFoundErrorMessage,
Assert.That (log.Messages[0], Does.Contain(String.Format (BindingExpression.PropertyNotFoundErrorMessage,
"Text",
"Xamarin.Forms.Core.UnitTests.BindingUnitTests+EmptyViewModel",
"Xamarin.Forms.Core.UnitTests.MockBindable",
@ -1621,7 +1621,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That (() => bindable.SetBinding (MockBindable.TextProperty, new Binding ("Text")), Throws.Nothing);
Assert.That (log.Messages.Count, Is.EqualTo (1), "An error was not logged");
Assert.That (log.Messages[0], Is.StringContaining (String.Format (BindingExpression.PropertyNotFoundErrorMessage,
Assert.That (log.Messages[0], Does.Contain(String.Format (BindingExpression.PropertyNotFoundErrorMessage,
"Text",
"Xamarin.Forms.Core.UnitTests.BindingUnitTests+DifferentViewModel",
"Xamarin.Forms.Core.UnitTests.MockBindable",
@ -1637,7 +1637,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That (() => bindable.SetBinding (MockBindable.TextProperty, new Binding ("PrivateSetter")), Throws.Nothing);
Assert.That (log.Messages.Count, Is.EqualTo (1), "An error was not logged");
Assert.That (log.Messages[0], Is.StringContaining (String.Format (BindingExpression.PropertyNotFoundErrorMessage,
Assert.That (log.Messages[0], Does.Contain(String.Format (BindingExpression.PropertyNotFoundErrorMessage,
"PrivateSetter",
"Xamarin.Forms.Core.UnitTests.BindingUnitTests+DifferentViewModel",
"Xamarin.Forms.Core.UnitTests.MockBindable",
@ -1646,7 +1646,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That (() => bindable.SetValueCore (MockBindable.TextProperty, "foo"), Throws.Nothing);
Assert.That (log.Messages.Count, Is.EqualTo (2), "An error was not logged");
Assert.That (log.Messages[1], Is.StringContaining (String.Format (BindingExpression.PropertyNotFoundErrorMessage,
Assert.That (log.Messages[1], Does.Contain(String.Format (BindingExpression.PropertyNotFoundErrorMessage,
"PrivateSetter",
"Xamarin.Forms.Core.UnitTests.BindingUnitTests+DifferentViewModel",
"Xamarin.Forms.Core.UnitTests.MockBindable",
@ -1660,7 +1660,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That (() => bindable.SetBinding (MockBindable.TextProperty, new Binding ("MissingProperty")), Throws.Nothing);
Assert.That (log.Messages.Count, Is.EqualTo (1), "An error was not logged");
Assert.That (log.Messages[0], Is.StringContaining (String.Format (BindingExpression.PropertyNotFoundErrorMessage,
Assert.That (log.Messages[0], Does.Contain(String.Format (BindingExpression.PropertyNotFoundErrorMessage,
"MissingProperty",
"Xamarin.Forms.Core.UnitTests.MockViewModel",
"Xamarin.Forms.Core.UnitTests.MockBindable",
@ -1688,7 +1688,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.That (() => bindable.SetBinding (MockBindable.TextProperty, new Binding ("Model.MissingProperty")), Throws.Nothing);
Assert.That (log.Messages.Count, Is.EqualTo (1), "An error was not logged");
Assert.That (log.Messages[0], Is.StringContaining (String.Format (BindingExpression.PropertyNotFoundErrorMessage,
Assert.That (log.Messages[0], Does.Contain(String.Format (BindingExpression.PropertyNotFoundErrorMessage,
"MissingProperty",
"Xamarin.Forms.Core.UnitTests.BindingBaseUnitTests+ComplexMockViewModel",
"Xamarin.Forms.Core.UnitTests.MockBindable",

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

@ -1,5 +1,6 @@
using NUnit.Framework;
using System;
using System.Threading.Tasks;
namespace Xamarin.Forms.Core.UnitTests
{
@ -153,7 +154,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public async void ForceUpdateSizeCallsAreRateLimited()
public async Task ForceUpdateSizeCallsAreRateLimited()
{
var lv = new ListView { HasUnevenRows = true };
var cell = new ViewCell { Parent = lv };
@ -172,7 +173,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public async void ForceUpdateSizeWillNotBeCalledIfParentIsNotAListViewWithUnevenRows ()
public async Task ForceUpdateSizeWillNotBeCalledIfParentIsNotAListViewWithUnevenRows ()
{
var lv = new ListView { HasUnevenRows = false };
var cell = new ViewCell { Parent = lv };

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

@ -11,7 +11,7 @@ namespace Xamarin.Forms.Core.UnitTests
public class GeocoderUnitTests : BaseTestFixture
{
[Test]
public async void AddressesForPosition ()
public async Task AddressesForPosition ()
{
Geocoder.GetAddressesForPositionFuncAsync = GetAddressesForPositionFuncAsync;
var geocoder = new Geocoder ();
@ -26,7 +26,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public async void PositionsForAddress () {
public async Task PositionsForAddress () {
Geocoder.GetPositionsForAddressAsyncFunc = GetPositionsForAddressAsyncFunc ;
var geocoder = new Geocoder ();
var result = await geocoder.GetPositionsForAddressAsync ("quux");

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

@ -61,14 +61,14 @@ namespace Xamarin.Forms.Core.UnitTests
[TestFixture]
public class MotionTests : BaseTestFixture
{
[TestFixtureSetUp]
[OneTimeSetUp]
public void Init ()
{
Device.PlatformServices = new MockPlatformServices ();
Ticker.Default = new BlockingTicker ();
}
[TestFixtureTearDown]
[OneTimeTearDown]
public void End ()
{
Device.PlatformServices = null;
@ -154,14 +154,14 @@ namespace Xamarin.Forms.Core.UnitTests
[TestFixture]
public class TickerSystemEnabledTests
{
[TestFixtureSetUp]
[OneTimeSetUp]
public void Init ()
{
Device.PlatformServices = new MockPlatformServices ();
Ticker.Default = new AsyncTicker();
}
[TestFixtureTearDown]
[OneTimeTearDown]
public void End ()
{
Device.PlatformServices = null;

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

@ -441,7 +441,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public async void HandlesPopToRoot ()
public async Task HandlesPopToRoot ()
{
var root = new ContentPage { Title = "Root" };
var navPage = new NavigationPage (root);
@ -489,7 +489,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public async void NavigatesBackWhenBackButtonPressed ()
public async Task NavigatesBackWhenBackButtonPressed ()
{
var root = new ContentPage { Title = "Root" };
var navPage = new NavigationPage (root);
@ -503,7 +503,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public async void DoesNotNavigatesBackWhenBackButtonPressedIfHandled ()
public async Task DoesNotNavigatesBackWhenBackButtonPressedIfHandled ()
{
var root = new BackButtonPage { Title = "Root" };
var second = new BackButtonPage () {Handle = true};
@ -562,7 +562,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public async void TestRemovePage()
public async Task TestRemovePage()
{
var root = new ContentPage { Title = "Root" };
var newPage = new ContentPage();

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

@ -261,7 +261,7 @@ namespace Xamarin.Forms.Core.UnitTests
var rd = new ResourceDictionary();
rd.Add("foo", "bar");
var ex = Assert.Throws<KeyNotFoundException>(() => { var foo = rd ["test_invalid_key"]; });
Assert.That(ex.Message, Is.StringContaining("test_invalid_key"));
Assert.That(ex.Message, Does.Contain("test_invalid_key"));
}
class MyRD : ResourceDictionary

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

@ -342,6 +342,37 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public void AppearingOnlyForVisiblePage()
{
Shell shell = new Shell();
var pageAppearing = new ContentPage();
var pageNotAppearing = new ContentPage();
FlyoutItem flyoutItem = new FlyoutItem();
Tab tab = new Tab();
ShellContent content = new ShellContent() { Content = pageAppearing };
bool pageAppearingFired = false;
bool pageNotAppearingFired = false;
pageAppearing.Appearing += (_, __) => pageAppearingFired = true;
pageNotAppearing.Appearing += (_, __) =>
{
pageNotAppearingFired = true;
};
shell.Items.Add(flyoutItem);
flyoutItem.Items.Add(tab);
tab.Items.Add(content);
var notAppearingContent = new ShellContent();
tab.Items.Add(notAppearingContent);
notAppearingContent.Content = pageNotAppearing;
Assert.True(pageAppearingFired, "Correct Page Appearing Fired");
Assert.False(pageNotAppearingFired, "Incorrect Page Appearing Fired");
}
class ShellLifeCycleState

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

@ -668,7 +668,7 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.AreEqual(bindingContext, menuItem2.BindingContext);
}
[Test]
[Test]
public async Task TitleViewLogicalChild()
{
Shell shell = new Shell();
@ -709,9 +709,37 @@ namespace Xamarin.Forms.Core.UnitTests
shell.FlyoutHeader = null;
Assert.False(shell.ChildrenNotDrawnByThisElement.Contains(layout));
}
}
[Test]
public async Task ShellFlyoutBehaviorCalculation()
{
Shell shell = new Shell();
ContentPage page = new ContentPage();
shell.Items.Add(CreateShellItem(page: page));
Assert.AreEqual(FlyoutBehavior.Flyout, shell.GetEffectiveFlyoutBehavior());
Shell.SetFlyoutBehavior(page, FlyoutBehavior.Disabled);
Shell.SetFlyoutBehavior(shell.Items[0].Items[0].Items[0], FlyoutBehavior.Flyout);
Shell.SetFlyoutBehavior(shell.Items[0].Items[0], FlyoutBehavior.Disabled);
Shell.SetFlyoutBehavior(shell.Items[0], FlyoutBehavior.Locked);
Assert.AreEqual(FlyoutBehavior.Disabled, shell.GetEffectiveFlyoutBehavior());
page.ClearValue(Shell.FlyoutBehaviorProperty);
Assert.AreEqual(FlyoutBehavior.Flyout, shell.GetEffectiveFlyoutBehavior());
shell.Items[0].Items[0].Items[0].ClearValue(Shell.FlyoutBehaviorProperty);
Assert.AreEqual(FlyoutBehavior.Disabled, shell.GetEffectiveFlyoutBehavior());
shell.Items[0].Items[0].ClearValue(Shell.FlyoutBehaviorProperty);
Assert.AreEqual(FlyoutBehavior.Locked, shell.GetEffectiveFlyoutBehavior());
shell.Items[0].ClearValue(Shell.FlyoutBehaviorProperty);
Assert.AreEqual(FlyoutBehavior.Flyout, shell.GetEffectiveFlyoutBehavior());
}
[Test]
public async Task TabBarAutoCreation()
{

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

@ -1,23 +1,45 @@
using NUnit.Framework;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Core.UnitTests
{
[TestFixture]
public class StyleTests : BaseTestFixture
{
internal class Logger : LogListener
{
public IReadOnlyList<string> Messages {
get { return messages; }
}
public override void Warning(string category, string message)
{
messages.Add("[" + category + "] " + message);
}
readonly List<string> messages = new List<string>();
}
internal Logger log;
[SetUp]
public override void Setup ()
{
base.Setup ();
log = new Logger();
Device.PlatformServices = new MockPlatformServices ();
Log.Listeners.Add(log);
}
[TearDown]
public override void TearDown()
{
base.TearDown();
Log.Listeners.Remove(log);
Application.Current = null;
}
@ -411,7 +433,7 @@ namespace Xamarin.Forms.Core.UnitTests
[Test]
//https://bugzilla.xamarin.com/show_bug.cgi?id=31207
public async void StyleDontHoldStrongReferences ()
public async Task StyleDontHoldStrongReferences ()
{
var style = new Style (typeof(Label));
var label = new Label ();
@ -828,27 +850,39 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
public void MismatchTargetTypeThrowsError1()
public void MismatchTargetTypeLogsWarningMessage1()
{
var s = new Style(typeof(Button));
var t = new View();
Assert.Throws<ArgumentException>(() => t.Style = s);
t.Style = s;
Assert.AreEqual(log.Messages.Count, 1);
Assert.AreEqual(log.Messages.FirstOrDefault(), $"[Styles] Style TargetType Xamarin.Forms.Button is not compatible with element target type Xamarin.Forms.View");
}
[Test]
public void MismatchTargetTypeThrowsError2()
public void MismatchTargetTypeLogsWarningMessage2()
{
var s = new Style(typeof(Button));
var t = new Label();
Assert.Throws<ArgumentException>(() => t.Style = s);
t.Style = s;
Assert.AreEqual(log.Messages.Count, 1);
Assert.AreEqual(log.Messages.FirstOrDefault(), $"[Styles] Style TargetType Xamarin.Forms.Button is not compatible with element target type Xamarin.Forms.Label");
}
[Test]
public void MatchTargetTypeDoesntThrowError()
public void MatchTargetTypeDoesntLogWarningMessage()
{
var s = new Style(typeof(View));
var t = new Button();
Assert.DoesNotThrow(() => t.Style = s);
t.Style = s;
Assert.That(log.Messages.Count, Is.EqualTo(0),
"A warning was logged: " + log.Messages.FirstOrDefault());
}
}
}

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

@ -1490,7 +1490,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
[Ignore]
[Ignore("SpeedTestApply")]
public void SpeedTestApply()
{
@ -1560,7 +1560,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
[Ignore]
[Ignore("SpeedTestSetBC")]
public void SpeedTestSetBC()
{
var property = BindableProperty.Create("Foo", typeof(string), typeof(MockBindable));

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

@ -48,7 +48,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
[Ignore]
[Ignore("LoadImageFromStream")]
public void LoadImageFromStream ()
{
var loader = new UriImageSource {
@ -60,7 +60,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
[Ignore]
[Ignore("SecondCallLoadFromCache")]
public void SecondCallLoadFromCache ()
{
var loader = new UriImageSource {
@ -80,7 +80,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
[Ignore]
[Ignore("DoNotKeepFailedRetrieveInCache")]
public void DoNotKeepFailedRetrieveInCache ()
{
var loader = new UriImageSource {
@ -98,7 +98,7 @@ namespace Xamarin.Forms.Core.UnitTests
}
[Test]
[Ignore]
[Ignore("ConcurrentCallsOnSameUriAreQueued")]
public void ConcurrentCallsOnSameUriAreQueued ()
{
var loader = new UriImageSource {

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

@ -45,8 +45,10 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="2.6.4" />
<PackageReference Include="NUnitTestAdapter" Version="2.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter">
<Version>3.15.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
@ -246,8 +248,9 @@
</ItemGroup>
<Target Name="_CopyNUnitTestAdapterFiles" AfterTargets="Build">
<ItemGroup>
<_NUnitTestAdapterFiles Include="$(NuGetPackageRoot)NUnitTestAdapter\%(Version)\**" Condition="@(PackageReference -> '%(Identity)') == 'NUnitTestAdapter'" InProject="False" />
<_NUnitTestAdapterFiles Include="$(NuGetPackageRoot)NUnit3TestAdapter\%(Version)\build\net35\**" Condition="@(PackageReference -> '%(Identity)') == 'NUnit3TestAdapter'" InProject="False" />
</ItemGroup>
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\tools\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\build\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
</Target>
</Project>

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

@ -49,14 +49,14 @@
<PackageReference Include="Castle.Core" Version="4.3.1" />
<PackageReference Include="DotNetSeleniumExtras.PageObjects" Version="3.11.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NUnit" Version="2.6.4" />
<PackageReference Include="NUnitTestAdapter">
<Version>2.2.0</Version>
</PackageReference>
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="Selenium.Support" Version="3.14.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.14.0" />
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
<PackageReference Include="Xamarin.UITest" Version="2.2.7" />
<PackageReference Include="Xamarin.UITest" Version="3.0.3" />
<PackageReference Include="NUnit3TestAdapter">
<Version>3.15.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="WindowsTestBase.cs" />

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

@ -46,9 +46,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NUnit" Version="2.6.4" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
<PackageReference Include="Xamarin.UITest" Version="2.2.7" />
<PackageReference Include="Xamarin.UITest" Version="3.0.3" />
</ItemGroup>
<ItemGroup>
<Compile Include="BaseViewContainerRemoteiOS.cs" />

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

@ -48,12 +48,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NUnit" Version="2.6.4" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="ServiceStack.Client" Version="4.5.12" />
<PackageReference Include="ServiceStack.Interfaces" Version="4.5.12" />
<PackageReference Include="ServiceStack.Text" Version="4.5.12" />
<PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
<PackageReference Include="Xamarin.UITest" Version="2.2.7" />
<PackageReference Include="Xamarin.UITest" Version="3.0.3" />
<PackageReference Include="Xamarin.UITest.Desktop" Version="0.0.7" />
</ItemGroup>
<ItemGroup>
@ -89,4 +89,4 @@
</ItemGroup>
<Copy SourceFiles="@(_XamarinUITestFiles)" DestinationFolder="$(SolutionDir)packages\Xamarin.UITest.AnyVersion\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
</Target>
</Project>
</Project>

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

@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms.Platform;
@ -216,11 +217,13 @@ namespace Xamarin.Forms
return 0;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void SetCurrentItem(object item)
{
SetValueFromRenderer(CurrentItemProperty, item);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public void SetIsDragging(bool value)
{
SetValue(IsDraggingPropertyKey, value);

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

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@ -40,7 +40,7 @@ namespace Xamarin.Forms
if (_style == value)
return;
if (value != null && !value.TargetType.IsAssignableFrom(TargetType))
throw new ArgumentException($"Style TargetType {value.TargetType.FullName} is not compatible with element target type {TargetType}");
Log.Warning("Styles", $"Style TargetType {value.TargetType.FullName} is not compatible with element target type {TargetType}");
SetStyle(ImplicitStyle, ClassStyles, value);
}
}

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

@ -954,17 +954,21 @@ namespace Xamarin.Forms
return lookupDict;
}
FlyoutBehavior GetEffectiveFlyoutBehavior()
{
var page = WalkToPage(this);
internal FlyoutBehavior GetEffectiveFlyoutBehavior() => GetEffectiveValue(Shell.FlyoutBehaviorProperty, FlyoutBehavior);
while (page != this && page != null)
T GetEffectiveValue<T>(BindableProperty property, T defaultValue)
{
Element element = GetVisiblePage();
while (element != this && element != null)
{
if (page.IsSet(FlyoutBehaviorProperty))
return GetFlyoutBehavior(page);
page = page.Parent;
if (element.IsSet(property))
return (T)element.GetValue(property);
element = element.Parent;
}
return FlyoutBehavior;
return defaultValue;
}
ShellAppearance GetAppearanceForPivot(Element pivot)
@ -988,7 +992,7 @@ namespace Xamarin.Forms
// One minor deviation here. Even though a pushed page is technically the child of
// a ShellSection and not the ShellContent, we want the root ShellContent to
// be taken into account. Yes this could behavior oddly if the developer switches
// be taken into account. Yes this could behave oddly if the developer switches
// tabs while a page is pushed, however that is in the developers wheelhouse
// and this will be the generally expected behavior.
if (!foundShellContent && pivot is ShellSection shellSection && shellSection.CurrentItem != null)
@ -1060,6 +1064,14 @@ namespace Xamarin.Forms
return !navArgs.Cancelled;
}
internal Element GetVisiblePage()
{
if (CurrentItem?.CurrentItem is IShellSectionController scc)
return scc.PresentedPage;
return null;
}
Element WalkToPage(Element element)
{
switch (element)

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

@ -86,7 +86,7 @@ namespace Xamarin.Forms
public ShellContent() => ((INotifyCollectionChanged)MenuItems).CollectionChanged += MenuItemsCollectionChanged;
internal bool IsVisibleContent => Parent is ShellSection shellSection && shellSection.IsVisibleSection;
internal bool IsVisibleContent => Parent is ShellSection shellSection && shellSection.IsVisibleSection && shellSection.CurrentItem == this;
internal override ReadOnlyCollection<Element> LogicalChildrenInternal => _logicalChildrenReadOnly ?? (_logicalChildrenReadOnly = new ReadOnlyCollection<Element>(_logicalChildren));
internal override void SendDisappearing()

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

@ -78,7 +78,7 @@
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="60.1142.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />

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

@ -69,8 +69,8 @@
<Compile Include="MaterialCheckBoxRenderer.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values-v21\styles.xml">

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

@ -42,8 +42,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="NUnit" Version="2.6.4" />
<PackageReference Include="NUnitTestAdapter" Version="2.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter">
<Version>3.15.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Xamarin.Forms.Core.UnitTests\MockDispatcherProvider.cs">
@ -83,8 +85,9 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="_CopyNUnitTestAdapterFiles" AfterTargets="Build">
<ItemGroup>
<_NUnitTestAdapterFiles Include="$(NuGetPackageRoot)NUnitTestAdapter\%(Version)\**" Condition="@(PackageReference -> '%(Identity)') == 'NUnitTestAdapter'" InProject="False" />
<_NUnitTestAdapterFiles Include="$(NuGetPackageRoot)NUnit3TestAdapter\%(Version)\build\net35\**" Condition="@(PackageReference -> '%(Identity)') == 'NUnit3TestAdapter'" InProject="False" />
</ItemGroup>
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\tools\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
<Copy SourceFiles="@(_NUnitTestAdapterFiles)" DestinationFolder="$(SolutionDir)packages\NUnitTestAdapter.AnyVersion\build\%(RecursiveDir)" ContinueOnError="true" Retries="0" />
</Target>
</Project>

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

@ -66,7 +66,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.GooglePlayServices.AppIndexing" Version="60.1142.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectToBuild Include="Xamarin.Forms.Platform.Android.AppLinks.csproj">

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

@ -19,6 +19,7 @@ namespace Xamarin.Forms.Platform.Android
public ListSource(IEnumerable enumerable)
{
_itemsSource = new List<object>();
foreach (object item in enumerable)
{
_itemsSource.Add(item);

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

@ -34,7 +34,6 @@ namespace Xamarin.Forms.Platform.Android
public void Recycle(ItemsView itemsView)
{
View.BindingContext = null;
itemsView.RemoveLogicalChild(View);
}
@ -51,7 +50,7 @@ namespace Xamarin.Forms.Platform.Android
_selectedTemplate = template;
}
_itemContentView.HandleItemSizingStrategy(reportMeasure, size);
_itemContentView.HandleItemSizingStrategy(reportMeasure, size);
// Set the binding context before we add it as a child of the ItemsView; otherwise, it will
// inherit the ItemsView's binding context

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

@ -666,15 +666,18 @@ namespace Xamarin.Forms
public async Task<Stream> GetStreamAsync(Uri uri, CancellationToken cancellationToken)
{
using (var client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(uri, cancellationToken))
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(uri, cancellationToken).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
Internals.Log.Warning("HTTP Request", $"Could not retrieve {uri}, status code {response.StatusCode}");
return null;
}
return await response.Content.ReadAsStreamAsync();
// the HttpResponseMessage needs to be disposed of after the calling code is done with the stream
// otherwise the stream may get disposed before the caller can use it
return new StreamWrapper(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), response);
}
}

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

@ -0,0 +1,81 @@
using System;
using System.IO;
namespace Xamarin.Forms
{
internal class StreamWrapper : Stream
{
Stream _wrapped;
IDisposable _additionalDisposable;
public StreamWrapper(Stream wrapped, IDisposable additionalDisposable)
{
if (wrapped == null)
throw new ArgumentNullException("wrapped");
_wrapped = wrapped;
_additionalDisposable = additionalDisposable;
}
public override bool CanRead
{
get { return _wrapped.CanRead; }
}
public override bool CanSeek
{
get { return _wrapped.CanSeek; }
}
public override bool CanWrite
{
get { return _wrapped.CanWrite; }
}
public override long Length
{
get { return _wrapped.Length; }
}
public override long Position
{
get { return _wrapped.Position; }
set { _wrapped.Position = value; }
}
public override void Flush()
{
_wrapped.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _wrapped.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _wrapped.Seek(offset, origin);
}
public override void SetLength(long value)
{
_wrapped.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
_wrapped.Write(buffer, offset, count);
}
protected override void Dispose(bool disposing)
{
_wrapped.Dispose();
_additionalDisposable?.Dispose();
_additionalDisposable = null;
base.Dispose(disposing);
}
}
}

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

@ -116,8 +116,7 @@ namespace Xamarin.Forms.Platform.Android
internal static T GetParentOfType<T>(this IViewParent view)
where T : class
{
T t = view as T;
if (view != null)
if (view is T t)
return t;
while (view != null)
@ -142,4 +141,4 @@ namespace Xamarin.Forms.Platform.Android
return view.Parent.GetParentOfType<T>();
}
}
}
}

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

@ -255,6 +255,7 @@
<Compile Include="Renderers\ViewCellExtensions.cs" />
<Compile Include="Renderers\ViewGroupExtensions.cs" />
<AndroidResource Include="Resources\Layout\RootLayout.axml" />
<Compile Include="StreamWrapper.cs" />
<Compile Include="TapGestureHandler.cs" />
<Compile Include="TextColorSwitcher.cs" />
<Compile Include="ViewInitializedEventArgs.cs" />
@ -353,9 +354,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0.1" />
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0.3" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\Layout\ShellContent.axml" />

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

@ -104,12 +104,17 @@ namespace Xamarin.Forms.Platform.UWP
}
var itemTemplate = Element.ItemTemplate;
if (_collectionViewSource != null)
{
if (_collectionViewSource.Source is ObservableItemTemplateCollection observableItemTemplateCollection)
{
observableItemTemplateCollection.CleanUp();
}
}
if (itemTemplate != null)
{
// The ItemContentControls need the actual data item and the template so they can inflate the template
// and bind the result to the data item.
// ItemTemplateEnumerator handles pairing them up for the ItemContentControls to consume
_collectionViewSource = new CollectionViewSource
{
Source = TemplatedItemSourceFactory.Create(itemsSource, itemTemplate, Element),
@ -135,33 +140,9 @@ namespace Xamarin.Forms.Platform.UWP
return;
}
var formsTemplate = Element.ItemTemplate;
var itemsControlItemTemplate = ListViewBase.ItemTemplate;
ListViewBase.ItemTemplate = Element.ItemTemplate == null ? null : ItemsViewTemplate;
if (formsTemplate == null)
{
ListViewBase.ItemTemplate = null;
if (itemsControlItemTemplate != null)
{
// We've removed the template; the itemssource should be updated
// TODO hartez 2018/06/25 21:25:24 I don't love that changing the template might reset the whole itemssource. We should think about a way to make that unnecessary
UpdateItemsSource();
}
return;
}
// TODO hartez 2018/06/23 13:47:27 Handle DataTemplateSelector case
// Actually, DataTemplateExtensions CreateContent might handle the selector for us
ListViewBase.ItemTemplate = ItemsViewTemplate;
if (itemsControlItemTemplate == null)
{
// We're using a data template now, so we'll need to update the itemsource
UpdateItemsSource();
}
UpdateItemsSource();
}
protected virtual void UpdateHeader()

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

@ -7,9 +7,10 @@ namespace Xamarin.Forms.Platform.UWP
{
internal class ObservableItemTemplateCollection : ObservableCollection<ItemTemplateContext>
{
readonly IList _innerSource;
readonly IList _itemsSource;
readonly DataTemplate _itemTemplate;
readonly BindableObject _container;
readonly INotifyCollectionChanged _notifyCollectionChanged;
public ObservableItemTemplateCollection(IList itemsSource, DataTemplate itemTemplate, BindableObject container)
{
@ -18,7 +19,9 @@ namespace Xamarin.Forms.Platform.UWP
throw new ArgumentException($"{nameof(itemsSource)} must implement {nameof(INotifyCollectionChanged)}");
}
_innerSource = itemsSource;
_notifyCollectionChanged = notifyCollectionChanged;
_itemsSource = itemsSource;
_itemTemplate = itemTemplate;
_container = container;
for (int n = 0; n < itemsSource.Count; n++)
@ -26,25 +29,32 @@ namespace Xamarin.Forms.Platform.UWP
Add(new ItemTemplateContext (itemTemplate, itemsSource[n], container));
}
notifyCollectionChanged.CollectionChanged += InnerCollectionChanged;
_notifyCollectionChanged.CollectionChanged += InnerCollectionChanged;
}
public void CleanUp()
{
_notifyCollectionChanged.CollectionChanged -= InnerCollectionChanged;
}
void InnerCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
// TODO hartez 2018/07/31 16:02:50 Handle the rest of these cases
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
Add(args);
break;
case NotifyCollectionChangedAction.Move:
Move(args);
break;
case NotifyCollectionChangedAction.Remove:
Remove(args);
break;
case NotifyCollectionChangedAction.Replace:
Replace(args);
break;
case NotifyCollectionChangedAction.Reset:
Reset();
break;
default:
throw new ArgumentOutOfRangeException();
@ -53,24 +63,90 @@ namespace Xamarin.Forms.Platform.UWP
void Add(NotifyCollectionChangedEventArgs args)
{
// TODO hartez 2018-07-31 01:47 PM Figure out what scenarios might cause a NewStartingIndex of -1
// I'm worried that the IndexOf lookup could cause problems when the list has duplicate items
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _innerSource.IndexOf(args.NewItems[0]);
var startIndex = args.NewStartingIndex > -1 ? args.NewStartingIndex : _itemsSource.IndexOf(args.NewItems[0]);
for (int n = args.NewItems.Count - 1; n >= 0; n--)
var count = args.NewItems.Count;
for(int n = 0; n < count; n++)
{
Insert(startIndex, new ItemTemplateContext(_itemTemplate, args.NewItems[n], _container));
}
}
void Move(NotifyCollectionChangedEventArgs args)
{
var count = args.NewItems.Count;
if (args.OldStartingIndex > args.NewStartingIndex)
{
for (int n = 0; n < count; n++)
{
Move(args.OldStartingIndex + n, args.NewStartingIndex + n);
}
return;
}
for(int n = count - 1; n >= 0; n--)
{
Move(args.OldStartingIndex + n, args.NewStartingIndex + n);
}
}
void Remove(NotifyCollectionChangedEventArgs args)
{
var startIndex = args.OldStartingIndex > -1 ? args.OldStartingIndex : _innerSource.IndexOf(args.OldItems[0]);
var startIndex = args.OldStartingIndex;
for (int n = 0; n < args.OldItems.Count; n++)
if (startIndex < 0)
{
RemoveAt(startIndex);
// INCC implementation isn't giving us enough information to know where the removed items were in the
// collection. So the best we can do is a full Reset.
Reset();
return;
}
var count = args.OldItems.Count;
for(int n = startIndex + count - 1; n >= startIndex; n--)
{
RemoveAt(n);
}
}
void Replace(NotifyCollectionChangedEventArgs args)
{
var newItemCount = args.NewItems.Count;
if (newItemCount == args.OldItems.Count)
{
for (int n = 0; n < newItemCount; n++)
{
var index = args.OldStartingIndex + n;
var oldItem = this[index];
var newItem = new ItemTemplateContext(_itemTemplate, args.NewItems[n], _container);
Items[index] = newItem;
var update = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, newItem, oldItem, index);
OnCollectionChanged(update);
}
}
else
{
// If we're replacing one set with an equal size set, we can do a soft reset; if not, we have to completely
// rebuild the collection
Reset();
}
}
void Reset()
{
Items.Clear();
for (int n = 0; n < _itemsSource.Count; n++)
{
Items.Add(new ItemTemplateContext(_itemTemplate, _itemsSource[n], _container));
}
var reset = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
OnCollectionChanged(reset);
}
}
}

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

@ -27,5 +27,10 @@ namespace Xamarin.Forms.Platform.iOS
{
return new CGSize(_constrain.Width,_constrain.Height);
}
protected override (bool, Size) NeedsContentSizeUpdate(Size currentSize)
{
return (false, Size.Zero);
}
}
}

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

@ -48,10 +48,10 @@ namespace Xamarin.Forms.Platform.iOS
void RegisterSupplementaryViews(UICollectionElementKindSection kind)
{
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalTemplatedSupplementalView),
kind, HorizontalTemplatedSupplementalView.ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(VerticalTemplatedSupplementalView),
kind, VerticalTemplatedSupplementalView.ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalSupplementaryView),
kind, HorizontalSupplementaryView.ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(VerticalSupplementaryView),
kind, VerticalSupplementaryView.ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalDefaultSupplementalView),
kind, HorizontalDefaultSupplementalView.ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(VerticalDefaultSupplementalView),
@ -82,7 +82,7 @@ namespace Xamarin.Forms.Platform.iOS
{
cell.Label.Text = ItemsSource.Group(indexPath).ToString();
if (cell is ItemsViewCell constrainedCell)
if (cell is ItemsViewCell)
{
cell.ConstrainTo(ItemsViewLayout.ConstrainedDimension);
}
@ -90,34 +90,20 @@ namespace Xamarin.Forms.Platform.iOS
void UpdateTemplatedSupplementaryView(TemplatedCell cell, NSString elementKind, NSIndexPath indexPath)
{
ApplyTemplateAndDataContext(cell, elementKind, indexPath);
DataTemplate template = elementKind == UICollectionElementKindSectionKey.Header
? GroupableItemsView.GroupHeaderTemplate
: GroupableItemsView.GroupFooterTemplate;
if (cell is ItemsViewCell constrainedCell)
var bindingContext = ItemsSource.Group(indexPath);
cell.Bind(template, bindingContext, ItemsView);
if (cell is ItemsViewCell)
{
cell.ConstrainTo(ItemsViewLayout.ConstrainedDimension);
}
}
void ApplyTemplateAndDataContext(TemplatedCell cell, NSString elementKind, NSIndexPath indexPath)
{
DataTemplate template;
if (elementKind == UICollectionElementKindSectionKey.Header)
{
template = GroupableItemsView.GroupHeaderTemplate;
}
else
{
template = GroupableItemsView.GroupFooterTemplate;
}
var templateElement = template.CreateContent() as View;
var renderer = CreateRenderer(templateElement);
BindableObject.SetInheritedBindingContext(renderer.Element, ItemsSource.Group(indexPath));
cell.SetRenderer(renderer);
}
string DetermineViewReuseId(NSString elementKind)
{
if (elementKind == UICollectionElementKindSectionKey.Header)
@ -139,8 +125,8 @@ namespace Xamarin.Forms.Platform.iOS
}
return ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Horizontal
? HorizontalTemplatedSupplementalView.ReuseId
: VerticalTemplatedSupplementalView.ReuseId;
? HorizontalSupplementaryView.ReuseId
: VerticalSupplementaryView.ReuseId;
}
internal CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICollectionViewLayout layout, nint section)

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

@ -0,0 +1,47 @@
using CoreGraphics;
using Foundation;
namespace Xamarin.Forms.Platform.iOS
{
internal abstract partial class HeightConstrainedTemplatedCell : TemplatedCell
{
[Export("initWithFrame:")]
public HeightConstrainedTemplatedCell(CGRect frame) : base(frame)
{
}
public override void ConstrainTo(CGSize constraint)
{
ConstrainedDimension = constraint.Height;
Layout(constraint);
}
protected override (bool, Size) NeedsContentSizeUpdate(Size currentSize)
{
var size = Size.Zero;
if (VisualElementRenderer?.Element == null)
{
return (false, size);
}
var bounds = VisualElementRenderer.Element.Bounds;
if (bounds.Width <= 0 || bounds.Height <= 0)
{
return (false, size);
}
var desiredBounds = VisualElementRenderer.Element.Measure(double.PositiveInfinity, bounds.Height,
MeasureFlags.IncludeMargins);
if (desiredBounds.Request.Width == currentSize.Width)
{
// Nothing in the cell needs more room, so leave it as it is
return (false, size);
}
return (true, desiredBounds.Request);
}
}
}

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

@ -3,27 +3,21 @@ using Foundation;
namespace Xamarin.Forms.Platform.iOS
{
internal sealed class HorizontalTemplatedCell : TemplatedCell
internal sealed class HorizontalCell : HeightConstrainedTemplatedCell
{
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.HorizontalTemplatedCell");
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.HorizontalCell");
[Export("initWithFrame:")]
public HorizontalTemplatedCell(CGRect frame) : base(frame)
public HorizontalCell(CGRect frame) : base(frame)
{
}
public override CGSize Measure()
{
var measure = VisualElementRenderer.Element.Measure(double.PositiveInfinity,
var measure = VisualElementRenderer.Element.Measure(double.PositiveInfinity,
ConstrainedDimension, MeasureFlags.IncludeMargins);
return new CGSize(measure.Request.Width, ConstrainedDimension);
}
public override void ConstrainTo(CGSize constraint)
{
ConstrainedDimension = constraint.Height;
Layout(constraint);
}
}
}

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

@ -3,12 +3,12 @@ using Foundation;
namespace Xamarin.Forms.Platform.iOS
{
public class HorizontalTemplatedSupplementalView : TemplatedCell
internal sealed class HorizontalSupplementaryView : HeightConstrainedTemplatedCell
{
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.HorizontalTemplatedSupplementalView");
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.HorizontalSupplementaryView");
[Export("initWithFrame:")]
public HorizontalTemplatedSupplementalView(CGRect frame) : base(frame)
public HorizontalSupplementaryView(CGRect frame) : base(frame)
{
}
@ -22,11 +22,5 @@ namespace Xamarin.Forms.Platform.iOS
return new CGSize(width, ConstrainedDimension);
}
public override void ConstrainTo(CGSize constraint)
{
ConstrainedDimension = constraint.Height;
Layout(constraint);
}
}
}

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

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Foundation;
using UIKit;
using Xamarin.Forms.Internals;
@ -199,12 +198,13 @@ namespace Xamarin.Forms.Platform.iOS
protected virtual void UpdateTemplatedCell(TemplatedCell cell, NSIndexPath indexPath)
{
ApplyTemplateAndDataContext(cell, indexPath);
cell.ContentSizeChanged -= CellContentSizeChanged;
if (cell is ItemsViewCell constrainedCell)
{
ItemsViewLayout.PrepareCellForLayout(constrainedCell);
}
cell.Bind(ItemsView, ItemsSource[indexPath]);
cell.ContentSizeChanged += CellContentSizeChanged;
ItemsViewLayout.PrepareCellForLayout(cell);
}
public virtual NSIndexPath GetIndexForItem(object item)
@ -217,28 +217,6 @@ namespace Xamarin.Forms.Platform.iOS
return ItemsSource[index];
}
void ApplyTemplateAndDataContext(TemplatedCell cell, NSIndexPath indexPath)
{
var template = ItemsView.ItemTemplate;
var item = ItemsSource[indexPath];
// Run this through the extension method in case it's really a DataTemplateSelector
template = template.SelectDataTemplate(item, ItemsView);
// Create the content and renderer for the view and
var view = template.CreateContent() as View;
var renderer = CreateRenderer(view);
cell.SetRenderer(renderer);
// Bind the view to the data item
view.BindingContext = ItemsSource[indexPath];
// And make sure it's a "child" of the ItemsView
ItemsView.AddLogicalChild(view);
cell.ContentSizeChanged += CellContentSizeChanged;
}
void CellContentSizeChanged(object sender, EventArgs e)
{
if (_disposed)
@ -247,43 +225,13 @@ namespace Xamarin.Forms.Platform.iOS
Layout?.InvalidateLayout();
}
internal void PrepareCellForRemoval(UICollectionViewCell cell)
{
if (cell is TemplatedCell templatedCell)
{
templatedCell.ContentSizeChanged -= CellContentSizeChanged;
var oldView = templatedCell.VisualElementRenderer?.Element;
if (oldView != null)
{
oldView.BindingContext = null;
ItemsView.RemoveLogicalChild(oldView);
}
templatedCell.PrepareForRemoval();
}
}
protected IVisualElementRenderer CreateRenderer(View view)
{
if (view == null)
{
throw new ArgumentNullException(nameof(view));
}
var renderer = Platform.CreateRenderer(view);
Platform.SetRenderer(view, renderer);
return renderer;
}
protected virtual string DetermineCellReuseId()
{
if (ItemsView.ItemTemplate != null)
{
return ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Horizontal
? HorizontalTemplatedCell.ReuseId
: VerticalTemplatedCell.ReuseId;
? HorizontalCell.ReuseId
: VerticalCell.ReuseId;
}
return ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Horizontal
@ -323,9 +271,9 @@ namespace Xamarin.Forms.Platform.iOS
{
CollectionView.RegisterClassForCell(typeof(HorizontalDefaultCell), HorizontalDefaultCell.ReuseId);
CollectionView.RegisterClassForCell(typeof(VerticalDefaultCell), VerticalDefaultCell.ReuseId);
CollectionView.RegisterClassForCell(typeof(HorizontalTemplatedCell),
HorizontalTemplatedCell.ReuseId);
CollectionView.RegisterClassForCell(typeof(VerticalTemplatedCell), VerticalTemplatedCell.ReuseId);
CollectionView.RegisterClassForCell(typeof(HorizontalCell),
HorizontalCell.ReuseId);
CollectionView.RegisterClassForCell(typeof(VerticalCell), VerticalCell.ReuseId);
}
bool IsHorizontal => (ItemsView?.ItemsLayout as ItemsLayout)?.Orientation == ItemsLayoutOrientation.Horizontal;
@ -462,7 +410,7 @@ namespace Xamarin.Forms.Platform.iOS
{
// Create the native renderer for the view, and keep the actual Forms element (if any)
// around for updating the layout later
var (NativeView, FormsElement) = RealizeView(view, viewTemplate);
var (NativeView, FormsElement) = TemplateHelpers.RealizeView(view, viewTemplate, ItemsView);
uiView = NativeView;
formsElement = FormsElement;
}
@ -507,33 +455,5 @@ namespace Xamarin.Forms.Platform.iOS
_currentBackgroundIsEmptyView = false;
}
}
internal (UIView NativeView, VisualElement FormsElement) RealizeView(object view, DataTemplate viewTemplate)
{
if (viewTemplate != null)
{
// Run this through the extension method in case it's really a DataTemplateSelector
viewTemplate = viewTemplate.SelectDataTemplate(view, ItemsView);
// We have a template; turn it into a Forms view
var templateElement = viewTemplate.CreateContent() as View;
var renderer = CreateRenderer(templateElement);
// and set the EmptyView as its BindingContext
BindableObject.SetInheritedBindingContext(renderer.Element, view);
return (renderer.NativeView, renderer.Element);
}
if (view is View formsView)
{
// No template, and the EmptyView is a Forms view; use that
var renderer = CreateRenderer(formsView);
return (renderer.NativeView, renderer.Element);
}
return (new UILabel { Text = $"{view}" }, null);
}
}
}

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

@ -0,0 +1,50 @@
using System;
using UIKit;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Platform.iOS
{
internal static class TemplateHelpers
{
public static IVisualElementRenderer CreateRenderer(View view)
{
if (view == null)
{
throw new ArgumentNullException(nameof(view));
}
var renderer = Platform.CreateRenderer(view);
Platform.SetRenderer(view, renderer);
return renderer;
}
public static (UIView NativeView, VisualElement FormsElement) RealizeView(object view, DataTemplate viewTemplate, ItemsView itemsView)
{
if (viewTemplate != null)
{
// Run this through the extension method in case it's really a DataTemplateSelector
viewTemplate = viewTemplate.SelectDataTemplate(view, itemsView);
// We have a template; turn it into a Forms view
var templateElement = viewTemplate.CreateContent() as View;
var renderer = CreateRenderer(templateElement);
// and set the EmptyView as its BindingContext
BindableObject.SetInheritedBindingContext(renderer.Element, view);
return (renderer.NativeView, renderer.Element);
}
if (view is View formsView)
{
// No template, and the EmptyView is a Forms view; use that
var renderer = CreateRenderer(formsView);
return (renderer.NativeView, renderer.Element);
}
return (new UILabel { Text = $"{view}" }, null);
}
}
}

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

@ -2,20 +2,28 @@
using CoreGraphics;
using Foundation;
using UIKit;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Platform.iOS
{
public abstract class TemplatedCell : ItemsViewCell
{
public event EventHandler<EventArgs> ContentSizeChanged;
protected nfloat ConstrainedDimension;
DataTemplate _currentTemplate;
// Keep track of the cell size so we can verify whether a measure invalidation
// actually changed the size of the cell
Size _size;
[Export("initWithFrame:")]
protected TemplatedCell(CGRect frame) : base(frame)
{
}
public IVisualElementRenderer VisualElementRenderer { get; private set; }
internal IVisualElementRenderer VisualElementRenderer { get; private set; }
public override void ConstrainTo(nfloat constant)
{
@ -35,7 +43,9 @@ namespace Xamarin.Forms.Platform.iOS
nativeView.Frame = new CGRect(CGPoint.Empty, size);
// Layout the Forms element
VisualElementRenderer.Element.Layout(nativeView.Frame.ToRectangle());
var nativeBounds = nativeView.Frame.ToRectangle();
VisualElementRenderer.Element.Layout(nativeBounds);
_size = nativeBounds.Size;
// Adjust the preferred attributes to include space for the Forms element
preferredAttributes.Frame = new CGRect(preferredAttributes.Frame.Location, size);
@ -43,13 +53,55 @@ namespace Xamarin.Forms.Platform.iOS
return preferredAttributes;
}
public override void PrepareForReuse()
public void Bind(ItemsView itemsView, object bindingContext)
{
base.PrepareForReuse();
ClearSubviews();
var template = itemsView.ItemTemplate;
// Run this through the extension method in case it's really a DataTemplateSelector
template = template.SelectDataTemplate(bindingContext, itemsView);
Bind(template, bindingContext, itemsView);
}
public void SetRenderer(IVisualElementRenderer renderer)
public void Bind(DataTemplate template, object bindingContext, ItemsView itemsView)
{
var oldElement = VisualElementRenderer?.Element;
if (template != _currentTemplate)
{
// Remove the old view, if it exists
if (oldElement != null)
{
oldElement.MeasureInvalidated -= MeasureInvalidated;
itemsView.RemoveLogicalChild(oldElement);
ClearSubviews();
_size = Size.Zero;
}
// Create the content and renderer for the view
var view = template.CreateContent() as View;
var renderer = TemplateHelpers.CreateRenderer(view);
SetRenderer(renderer);
}
var currentElement = VisualElementRenderer?.Element;
// Bind the view to the data item
currentElement.BindingContext = bindingContext;
if (template != _currentTemplate)
{
// And make the Element a "child" of the ItemsView
// We deliberately do this _after_ setting the binding context for the new element;
// if we do it before, the element briefly inherits the ItemsView's bindingcontext and we
// emit a bunch of needless binding errors
itemsView.AddLogicalChild(currentElement);
}
_currentTemplate = template;
}
void SetRenderer(IVisualElementRenderer renderer)
{
VisualElementRenderer = renderer;
var nativeView = VisualElementRenderer.NativeView;
@ -99,31 +151,24 @@ namespace Xamarin.Forms.Platform.iOS
}
}
protected abstract (bool, Size) NeedsContentSizeUpdate(Size currentSize);
void MeasureInvalidated(object sender, EventArgs args)
{
if (VisualElementRenderer?.Element == null)
var (needsUpdate, toSize) = NeedsContentSizeUpdate(_size);
if (!needsUpdate)
{
return;
}
var bounds = VisualElementRenderer.Element.Bounds;
if (bounds.Width <= 0 || bounds.Height <= 0)
{
return;
}
// Cache the size for next time
_size = toSize;
// Let the controller know that things need to be laid out again
OnContentSizeChanged();
}
public void PrepareForRemoval()
{
if (VisualElementRenderer?.Element != null)
{
VisualElementRenderer.Element.MeasureInvalidated -= MeasureInvalidated;
}
}
protected void OnContentSizeChanged()
{
ContentSizeChanged?.Invoke(this, EventArgs.Empty);

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

@ -140,8 +140,6 @@ namespace Xamarin.Forms.Platform.iOS
if (collectionView.ContentOffset.Y >= actualHeight || collectionView.ContentOffset.Y < 0)
return;
}
ItemsViewController.PrepareCellForRemoval(cell);
}
public override CGSize GetReferenceSizeForHeader(UICollectionView collectionView, UICollectionViewLayout layout, nint section)

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

@ -1,29 +1,23 @@
using CoreGraphics;
using CoreGraphics;
using Foundation;
namespace Xamarin.Forms.Platform.iOS
{
internal sealed class VerticalTemplatedCell : TemplatedCell
internal sealed class VerticalCell : WidthConstrainedTemplatedCell
{
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.VerticalTemplatedCell");
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.VerticalCell");
[Export("initWithFrame:")]
public VerticalTemplatedCell(CGRect frame) : base(frame)
public VerticalCell(CGRect frame) : base(frame)
{
}
public override CGSize Measure()
{
var measure = VisualElementRenderer.Element.Measure(ConstrainedDimension,
var measure = VisualElementRenderer.Element.Measure(ConstrainedDimension,
double.PositiveInfinity, MeasureFlags.IncludeMargins);
return new CGSize(ConstrainedDimension, measure.Request.Height);
}
public override void ConstrainTo(CGSize constraint)
{
ConstrainedDimension = constraint.Width;
Layout(constraint);
}
}
}

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

@ -3,12 +3,12 @@ using Foundation;
namespace Xamarin.Forms.Platform.iOS
{
public class VerticalTemplatedSupplementalView : TemplatedCell
internal sealed class VerticalSupplementaryView : WidthConstrainedTemplatedCell
{
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.VerticalTemplatedSupplementalView");
public static NSString ReuseId = new NSString("Xamarin.Forms.Platform.iOS.VerticalSupplementaryView");
[Export("initWithFrame:")]
public VerticalTemplatedSupplementalView(CGRect frame) : base(frame)
public VerticalSupplementaryView(CGRect frame) : base(frame)
{
}
@ -22,11 +22,5 @@ namespace Xamarin.Forms.Platform.iOS
return new CGSize(ConstrainedDimension, height);
}
public override void ConstrainTo(CGSize constraint)
{
ConstrainedDimension = constraint.Width;
Layout(constraint);
}
}
}

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

@ -0,0 +1,47 @@
using CoreGraphics;
using Foundation;
namespace Xamarin.Forms.Platform.iOS
{
internal abstract class WidthConstrainedTemplatedCell : TemplatedCell
{
[Export("initWithFrame:")]
public WidthConstrainedTemplatedCell(CGRect frame) : base(frame)
{
}
public override void ConstrainTo(CGSize constraint)
{
ConstrainedDimension = constraint.Width;
Layout(constraint);
}
protected override (bool, Size) NeedsContentSizeUpdate(Size currentSize)
{
var size = Size.Zero;
if (VisualElementRenderer?.Element == null)
{
return (false, size);
}
var bounds = VisualElementRenderer.Element.Bounds;
if (bounds.Width <= 0 || bounds.Height <= 0)
{
return (false, size);
}
var desiredBounds = VisualElementRenderer.Element.Measure(bounds.Width, double.PositiveInfinity,
MeasureFlags.IncludeMargins);
if (desiredBounds.Request.Height == currentSize.Height)
{
// Nothing in the cell needs more room, so leave it as it is
return (false, size);
}
return (true, desiredBounds.Request);
}
}
}

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

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Foundation;
using UIKit;
namespace Xamarin.Forms.Platform.iOS
{
internal static class NSObjectExtensions
{
public static void QueueForLater(this NSObject nsObject, Action action) =>
nsObject.BeginInvokeOnMainThread(action);
}
}

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

@ -360,7 +360,7 @@ namespace Xamarin.Forms.Platform.iOS
Control.TableHeaderView = _headerRenderer.NativeView;
}
async void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e)
void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e)
{
if (Superview == null)
{
@ -386,15 +386,17 @@ namespace Xamarin.Forms.Platform.iOS
Control.Layer.RemoveAllAnimations();
//iOS11 hack
if (Forms.IsiOS11OrNewer)
{
await Task.Delay(1);
}
Control.ScrollToRow(NSIndexPath.FromRowSection(index, 0), position, e.ShouldAnimate);
this.QueueForLater(() =>
{
if (Control != null && !_disposed)
Control.ScrollToRow(NSIndexPath.FromRowSection(index, 0), position, e.ShouldAnimate);
});
else
Control.ScrollToRow(NSIndexPath.FromRowSection(index, 0), position, e.ShouldAnimate);
}
}
}
void UpdateFooter()
{
var footer = ListView.FooterElement;
@ -1490,6 +1492,9 @@ namespace Xamarin.Forms.Platform.iOS
//This also forces the spinner color to be correct if we started refreshing immediately after changing it.
UpdateContentOffset(TableView.ContentOffset.Y - _refresh.Frame.Height, () =>
{
if (_refresh == null)
return;
_refresh.BeginRefreshing();
//hack: when we don't have cells in our UITableView the spinner fails to appear
CheckContentSize();

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

@ -111,6 +111,7 @@
<Compile Include="CollectionView\EmptySource.cs" />
<Compile Include="CollectionView\GroupableItemsViewController.cs" />
<Compile Include="CollectionView\GroupableItemsViewRenderer.cs" />
<Compile Include="CollectionView\HorizontalCell.cs" />
<Compile Include="CollectionView\HorizontalDefaultSupplementalView.cs" />
<Compile Include="CollectionView\HorizontalTemplatedHeaderView.cs" />
<Compile Include="CollectionView\IItemsViewSource.cs" />
@ -124,7 +125,9 @@
<Compile Include="CollectionView\ScrollToPositionExtensions.cs" />
<Compile Include="CollectionView\SelectableItemsViewController.cs" />
<Compile Include="CollectionView\SelectableItemsViewRenderer.cs" />
<Compile Include="CollectionView\TemplateHelpers.cs" />
<Compile Include="CollectionView\UICollectionViewDelegator.cs" />
<Compile Include="CollectionView\VerticalCell.cs" />
<Compile Include="CollectionView\VerticalDefaultCell.cs" />
<Compile Include="CollectionView\GridViewLayout.cs" />
<Compile Include="CollectionView\ItemsViewLayout.cs" />
@ -134,10 +137,10 @@
<Compile Include="CollectionView\PropertyChangedEventArgsExtensions.cs" />
<Compile Include="CollectionView\SnapHelpers.cs" />
<Compile Include="CollectionView\TemplatedCell.cs" />
<Compile Include="CollectionView\HorizontalTemplatedCell.cs" />
<Compile Include="CollectionView\HeightConstrainedTemplatedCell.cs" />
<Compile Include="CollectionView\VerticalDefaultSupplementalView.cs" />
<Compile Include="CollectionView\VerticalTemplatedCell.cs" />
<Compile Include="CollectionView\VerticalTemplatedHeaderView.cs" />
<Compile Include="CollectionView\WidthConstrainedTemplatedCell.cs" />
<Compile Include="CollectionView\VerticalSupplementaryView.cs" />
<Compile Include="DisposeHelpers.cs" />
<Compile Include="EffectUtilities.cs" />
<Compile Include="ExportCellAttribute.cs" />
@ -145,6 +148,7 @@
<Compile Include="ExportRendererAttribute.cs" />
<Compile Include="Extensions\ArrayExtensions.cs" />
<Compile Include="Extensions\FlowDirectionExtensions.cs" />
<Compile Include="Extensions\NSObjectExtensions.cs" />
<Compile Include="Extensions\PlatformConfigurationExtensions.cs" />
<Compile Include="Extensions\LabelExtensions.cs" />
<Compile Include="Extensions\VisualElementExtensions.cs" />

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

@ -167,7 +167,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
Assert.That(page.Content.BackgroundColor, Is.EqualTo(Color.Red));
}
[Test][Ignore]
[Test][Ignore(nameof(ImplicitStyleAppliedToMissingType))]
public void ImplicitStyleAppliedToMissingType()
{
XamlLoader.FallbackTypeResolver = (p, type) => type ?? typeof(Button);
@ -224,7 +224,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
Assert.That(myButton.BackgroundColor, Is.Not.EqualTo(Color.Red));
}
[Test][Ignore]
[Test][Ignore(nameof(StyleTargetingMissingTypeNotAppliedToFallbackType))]
public void StyleTargetingMissingTypeNotAppliedToFallbackType()
{
XamlLoader.FallbackTypeResolver = (p, type) => type ?? typeof(Button);

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

@ -113,16 +113,17 @@ namespace Xamarin.Forms.Xaml.UnitTests
"Release";
#endif
var dir = Path.GetFullPath(
Path.Combine(
TestContext.CurrentContext.TestDirectory, "Xamarin.Forms.Controls.dll"));
var xamlg = new XamlGTask()
{
BuildEngine = new DummyBuildEngine(),
AssemblyName = "test",
Language = "C#",
XamlFiles = new[] { item },
OutputFiles = new [] { new TaskItem(xamlOutputFile) },
References = Path.GetFullPath(
Path.Combine(
Directory.GetCurrentDirectory(), "Xamarin.Forms.Controls.dll"))
OutputFiles = new[] { new TaskItem(xamlOutputFile) },
References = dir
};
var generator = new XamlGenerator(item, xamlg.Language, xamlg.AssemblyName, xamlOutputFile, xamlg.References, null);

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

@ -795,8 +795,12 @@ namespace Xamarin.Forms.Xaml.UnitTests
var bindingType = XamlParser.GetElementType(new XmlType("http://xamarin.com/schemas/2014/forms", "Binding", null), null, null, out var ex);
Assert.That(ex, Is.Null);
Assert.That(bindingType, Is.EqualTo(typeof(BindingExtension)));
var bindingTypeRef = new XmlType("http://xamarin.com/schemas/2014/forms", "Binding", null).GetTypeReference(ModuleDefinition.CreateModule("foo", ModuleKind.Dll), null);
var module = ModuleDefinition.CreateModule("foo", new ModuleParameters()
{
AssemblyResolver = new MockAssemblyResolver(),
Kind = ModuleKind.Dll,
});
var bindingTypeRef = new XmlType("http://xamarin.com/schemas/2014/forms", "Binding", null).GetTypeReference(module, null);
Assert.That(bindingType.FullName, Is.EqualTo("Xamarin.Forms.Xaml.BindingExtension"));
}
}

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

@ -1,9 +1,11 @@
using Microsoft.Build.Locator;
using Mono.Cecil;
using NUnit.Framework;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using static Xamarin.Forms.MSBuild.UnitTests.MSBuildXmlExtensions;
@ -117,7 +119,6 @@ namespace Xamarin.Forms.MSBuild.UnitTests
/// <param name="sdkStyle">If true, uses a new SDK-style project</param>
XElement NewProject (bool sdkStyle)
{
var path = Path.GetTempFileName ();
var project = NewElement ("Project");
var propertyGroup = NewElement ("PropertyGroup");
@ -136,6 +137,7 @@ namespace Xamarin.Forms.MSBuild.UnitTests
propertyGroup.Add (NewElement ("OutputType").WithValue ("Library"));
propertyGroup.Add (NewElement ("OutputPath").WithValue ("bin\\Debug"));
propertyGroup.Add (NewElement ("TargetFrameworkVersion").WithValue ("v4.7"));
propertyGroup.Add(NewElement("RootNamespace").WithValue("test"));
}
propertyGroup.Add(NewElement("_XFBuildTasksLocation").WithValue($"{testDirectory}\\"));
@ -195,8 +197,19 @@ namespace Xamarin.Forms.MSBuild.UnitTests
}
}
void Build (string projectFile, string target = "Build", string additionalArgs = "")
string Build (string projectFile, string target = "Build", string additionalArgs = "", bool shouldSucceed = true)
{
var builder = new StringBuilder();
void onData(object s, DataReceivedEventArgs e)
{
lock (builder)
if (e.Data != null)
{
builder.AppendLine(e.Data);
Console.WriteLine(e.Data);
}
};
var psi = new ProcessStartInfo {
FileName = FindMSBuild (),
Arguments = $"/v:normal /nologo {projectFile} /t:{target} /bl {additionalArgs}",
@ -208,14 +221,19 @@ namespace Xamarin.Forms.MSBuild.UnitTests
WorkingDirectory = tempDirectory,
};
using (var p = new Process { StartInfo = psi }) {
p.ErrorDataReceived += (s, e) => Console.Error.WriteLine (e.Data);
p.OutputDataReceived += (s, e) => Console.WriteLine (e.Data);
p.ErrorDataReceived += onData;
p.OutputDataReceived += onData;
p.Start ();
p.BeginErrorReadLine ();
p.BeginOutputReadLine ();
p.WaitForExit ();
Assert.AreEqual (0, p.ExitCode, "MSBuild exited with {0}", p.ExitCode);
if (shouldSucceed)
Assert.AreEqual(0, p.ExitCode, "MSBuild exited with {0}", p.ExitCode);
else
Assert.AreNotEqual(0, p.ExitCode, "MSBuild exited with {0}", p.ExitCode);
return builder.ToString();
}
}
@ -250,6 +268,40 @@ namespace Xamarin.Forms.MSBuild.UnitTests
AssertExists (Path.Combine (intermediateDirectory, "XamlC.stamp"));
}
// Tests the XFXamlCValidateOnly=True MSBuild property
[Test]
public void ValidateOnly([Values(false, true)] bool sdkStyle)
{
var project = NewProject(sdkStyle);
project.Add(AddFile("MainPage.xaml", "EmbeddedResource", Xaml.MainPage));
var projectFile = Path.Combine(tempDirectory, "test.csproj");
project.Save(projectFile);
RestoreIfNeeded(projectFile, sdkStyle);
Build(projectFile, additionalArgs: "/p:XFXamlCValidateOnly=True");
var testDll = Path.Combine(intermediateDirectory, "test.dll");
AssertExists(testDll, nonEmpty: true);
using (var assembly = AssemblyDefinition.ReadAssembly(testDll))
{
// XAML files should remain as EmbeddedResource
var resources = assembly.MainModule.Resources.OfType<EmbeddedResource>().Select(e => e.Name).ToArray();
CollectionAssert.Contains(resources, "test.MainPage.xaml");
}
}
[Test]
public void ValidateOnly_WithErrors([Values(false, true)] bool sdkStyle)
{
var project = NewProject(sdkStyle);
project.Add(AddFile("MainPage.xaml", "EmbeddedResource", Xaml.MainPage.Replace ("</ContentPage>", "<NotARealThing/></ContentPage>")));
var projectFile = Path.Combine(tempDirectory, "test.csproj");
project.Save(projectFile);
RestoreIfNeeded(projectFile, sdkStyle);
string log = Build(projectFile, additionalArgs: "/p:XFXamlCValidateOnly=True", shouldSucceed: false);
StringAssert.Contains("MainPage.xaml(7,6): error : Position 7:6. Type NotARealThing not found", log);
}
/// <summary>
/// Tests that XamlG and XamlC targets skip, as well as checking IncrementalClean doesn't delete generated files
/// </summary>
@ -488,15 +540,15 @@ namespace Xamarin.Forms.MSBuild.UnitTests
AssertExists (Path.Combine (intermediateDirectory, "XamlC.stamp"));
}
[Test, ExpectedException (typeof(AssertionException))]
public void InvalidXml ([Values (false, true)] bool sdkStyle)
[Test]
public void InvalidXml([Values(false, true)] bool sdkStyle)
{
var project = NewProject (sdkStyle);
project.Add (AddFile ("MainPage.xaml", "EmbeddedResource", "notxmlatall"));
var projectFile = Path.Combine (tempDirectory, "test.csproj");
project.Save (projectFile);
RestoreIfNeeded (projectFile, sdkStyle);
Build (projectFile);
var project = NewProject(sdkStyle);
project.Add(AddFile("MainPage.xaml", "EmbeddedResource", "notxmlatall"));
var projectFile = Path.Combine(tempDirectory, "test.csproj");
project.Save(projectFile);
RestoreIfNeeded(projectFile, sdkStyle);
Assert.Throws<AssertionException>(() => Build(projectFile));
}
[Test]

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

@ -0,0 +1,20 @@
using Mono.Cecil;
using NUnit.Framework;
using System.IO;
namespace Xamarin.Forms.Xaml.UnitTests
{
public class MockAssemblyResolver : BaseAssemblyResolver
{
public override AssemblyDefinition Resolve(AssemblyNameReference name)
{
AssemblyDefinition assembly;
var localPath = Path.GetFullPath(Path.Combine(TestContext.CurrentContext.TestDirectory, $"{name.Name}.dll"));
if (File.Exists(localPath))
assembly = AssemblyDefinition.ReadAssembly(localPath);
else
assembly = base.Resolve(name);
return assembly;
}
}
}

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

@ -30,7 +30,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
KeepXamlResources = true,
OptimizeIL = true,
DebugSymbols = false,
ReadOnly = true,
ValidateOnly = true,
Type = type.FullName,
BuildEngine = new MSBuild.UnitTests.DummyBuildEngine()
};

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

@ -46,7 +46,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
}
[Test]
[Ignore]
[Ignore(nameof(XamlCIs20TimesFasterThanXaml))]
public void XamlCIs20TimesFasterThanXaml ()
{
var swXamlC = new Stopwatch ();
@ -66,7 +66,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
}
[Test]
[Ignore]
[Ignore(nameof(XamlCIsNotMuchSlowerThanCode))]
public void XamlCIsNotMuchSlowerThanCode ()
{
var swXamlC = new Stopwatch ();

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

@ -4,7 +4,7 @@
<RootNamespace>Xamarin.Forms.Xaml.UnitTests</RootNamespace>
<AssemblyName>Xamarin.Forms.Xaml.UnitTests</AssemblyName>
<WarningLevel>4</WarningLevel>
<NoWarn>0672;0219;0414</NoWarn>
<NoWarn>0672;0219;0414;CS0436</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
@ -19,8 +19,9 @@
<ProjectReference Include="..\Xamarin.Forms.Build.Tasks\Xamarin.Forms.Build.Tasks.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="2.6.4" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Xamarin.Forms.Core.UnitTests\MockDispatcherProvider.cs">

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

@ -6,6 +6,7 @@ using Mono.Cecil;
using Xamarin.Forms.Build.Tasks;
using NUnit.Framework;
using Xamarin.Forms.Xaml.UnitTests;
namespace Xamarin.Forms.XamlcUnitTests
{
@ -31,7 +32,11 @@ namespace Xamarin.Forms.XamlcUnitTests
[SetUp]
public void SetUp ()
{
module = ModuleDefinition.CreateModule ("foo", ModuleKind.Dll);
module = ModuleDefinition.CreateModule("foo", new ModuleParameters()
{
AssemblyResolver = new MockAssemblyResolver(),
Kind = ModuleKind.Dll,
});
}
[Test]

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

@ -7,6 +7,7 @@ using Xamarin.Forms.Build.Tasks;
using NUnit.Framework;
using System.Collections.Generic;
using Xamarin.Forms.Xaml.UnitTests;
namespace Xamarin.Forms.XamlcUnitTests
{
@ -33,7 +34,11 @@ namespace Xamarin.Forms.XamlcUnitTests
[SetUp]
public void SetUp()
{
module = ModuleDefinition.CreateModule("foo", ModuleKind.Dll);
module = ModuleDefinition.CreateModule("foo", new ModuleParameters()
{
AssemblyResolver = new MockAssemblyResolver(),
Kind = ModuleKind.Dll,
});
}
[Test]

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

@ -1,4 +1,3 @@
using System;
using System.Linq;
using Mono.Cecil;
@ -7,6 +6,7 @@ using Xamarin.Forms.Build.Tasks;
using NUnit.Framework;
using System.Collections.Generic;
using Xamarin.Forms.Xaml.UnitTests;
namespace Xamarin.Forms.XamlcUnitTests
{
@ -23,9 +23,13 @@ namespace Xamarin.Forms.XamlcUnitTests
}
[SetUp]
public void SetUp ()
public void SetUp()
{
module = ModuleDefinition.CreateModule ("foo", ModuleKind.Dll);
module = ModuleDefinition.CreateModule("foo", new ModuleParameters()
{
AssemblyResolver = new MockAssemblyResolver(),
Kind = ModuleKind.Dll,
});
}
[Test]

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

@ -2,7 +2,7 @@ using System;
using NUnit.Framework.Constraints;
namespace Xamarin.Forms.Xaml.UnitTests
{
{
public class XamlParseExceptionConstraint : ExceptionTypeConstraint
{
bool haslineinfo;
@ -10,13 +10,14 @@ namespace Xamarin.Forms.Xaml.UnitTests
int lineposition;
Func<string, bool> messagePredicate;
XamlParseExceptionConstraint (bool haslineinfo) : base (typeof (XamlParseException))
XamlParseExceptionConstraint(bool haslineinfo) : base(typeof(XamlParseException))
{
this.haslineinfo = haslineinfo;
DisplayName = "xamlparse";
}
public XamlParseExceptionConstraint () : this (false)
public override string DisplayName => "xamlparse";
public XamlParseExceptionConstraint() : this(false)
{
}
@ -27,9 +28,8 @@ namespace Xamarin.Forms.Xaml.UnitTests
this.messagePredicate = messagePredicate;
}
public override bool Matches (object actual)
protected override bool Matches (object actual)
{
this.actual = actual;
if (!base.Matches (actual))
return false;
var xmlInfo = ((XamlParseException)actual).XmlInfo;
@ -43,25 +43,30 @@ namespace Xamarin.Forms.Xaml.UnitTests
return xmlInfo.LineNumber == linenumber && xmlInfo.LinePosition == lineposition;
}
public override void WriteDescriptionTo (MessageWriter writer)
public override string Description
{
base.WriteDescriptionTo (writer);
if (haslineinfo)
writer.Write (string.Format (" line {0}, position {1}", linenumber, lineposition));
}
public override void WriteActualValueTo (MessageWriter writer)
{
var ex = actual as XamlParseException;
writer.WriteActualValue ((actual == null) ? null : actual.GetType ());
if (ex != null) {
if (ex.XmlInfo != null && ex.XmlInfo.HasLineInfo ())
writer.Write (" line {0}, position {1}", ex.XmlInfo.LineNumber, ex.XmlInfo.LinePosition);
else
writer.Write (" no line info");
writer.WriteLine (" ({0})", ex.Message);
writer.Write (ex.StackTrace);
get
{
if (haslineinfo)
{
return string.Format($"{base.Description} line {linenumber}, position {lineposition}");
}
return base.Description;
}
}
//public override void WriteActualValueTo (MessageWriter writer)
//{
// var ex = actual as XamlParseException;
// writer.WriteActualValue ((actual == null) ? null : actual.GetType ());
// if (ex != null) {
// if (ex.XmlInfo != null && ex.XmlInfo.HasLineInfo ())
// writer.Write (" line {0}, position {1}", ex.XmlInfo.LineNumber, ex.XmlInfo.LinePosition);
// else
// writer.Write (" no line info");
// writer.WriteLine (" ({0})", ex.Message);
// writer.Write (ex.StackTrace);
// }
//}
}
}

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

@ -5,6 +5,7 @@ using System.Linq;
using System.Reflection;
using System.Xml;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml.Diagnostics;
using Xamarin.Forms.Xaml.Internals;
using static System.String;
@ -344,16 +345,25 @@ namespace Xamarin.Forms.Xaml
return;
//If it's a BindableProberty, SetValue
if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe))
if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe)) {
VisualDiagnostics.RegisterSourceInfo(value, null, ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition);
VisualDiagnostics.SendVisualTreeChanged(xamlelement, value);
return;
}
//If we can assign that value to a normal property, let's do it
if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, context, out xpe))
if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, context, out xpe)) {
VisualDiagnostics.RegisterSourceInfo(value, null, ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition);
VisualDiagnostics.SendVisualTreeChanged(xamlelement, value);
return;
}
//If it's an already initialized property, add to it
if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe))
if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe)) {
VisualDiagnostics.RegisterSourceInfo(value, null, ((IXmlLineInfo)node).LineNumber, ((IXmlLineInfo)node).LinePosition);
VisualDiagnostics.SendVisualTreeChanged(xamlelement, value);
return;
}
xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exist, or is not assignable, or mismatching type between value and property", lineInfo);
if (context.ExceptionHandler != null)

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

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Diagnostics;
namespace Xamarin.Forms.Xaml.Diagnostics
{
static class DebuggerHelper
{
internal static bool _mockDebuggerIsAttached;
public static bool DebuggerIsAttached => _mockDebuggerIsAttached || Debugger.IsAttached;
}
}

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

@ -4,7 +4,11 @@ namespace Xamarin.Forms.Xaml.Diagnostics
internal static class ResourceDictionaryDiagnostics
{
internal static void OnStaticResourceResolved(ResourceDictionary resourceDictionary, string key, object targetObject, object targetProperty)
=> StaticResourceResolved?.Invoke(resourceDictionary, new StaticResourceResolvedEventArgs(resourceDictionary, key, targetObject, targetProperty));
{
if (DebuggerHelper.DebuggerIsAttached)
StaticResourceResolved?.Invoke(resourceDictionary, new StaticResourceResolvedEventArgs(resourceDictionary, key, targetObject, targetProperty));
}
public static event EventHandler<StaticResourceResolvedEventArgs> StaticResourceResolved;
}
}

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

@ -0,0 +1,71 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Xamarin.Forms.Xaml.Diagnostics
{
class VisualDiagnostics
{
static ConditionalWeakTable<object, XamlSourceInfo> sourceInfos = new ConditionalWeakTable<object, XamlSourceInfo>();
internal static void RegisterSourceInfo(object target, Uri uri, int lineNumber, int linePosition)
{
if (DebuggerHelper.DebuggerIsAttached)
sourceInfos.Add(target, new XamlSourceInfo(uri, lineNumber, linePosition));
}
internal static void SendVisualTreeChanged(object parent, object child)
{
if (DebuggerHelper.DebuggerIsAttached)
VisualTreeChanged?.Invoke(parent, new VisualTreeChangeEventArgs(parent, child, -1, VisualTreeChangeType.Add));
}
public static event EventHandler<VisualTreeChangeEventArgs> VisualTreeChanged;
public static XamlSourceInfo GetXamlSourceInfo(object obj) => sourceInfos.TryGetValue(obj, out var sourceinfo) ? sourceinfo : null;
}
class XamlSourceInfo
{
public XamlSourceInfo(Uri sourceUri, int lineNumber, int linePosition)
{
SourceUri = sourceUri;
LineNumber = lineNumber;
LinePosition = linePosition;
}
public Uri SourceUri { get; }
public int LineNumber { get; }
public int LinePosition { get; }
public void Deconstruct(out Uri sourceUri, out int lineNumber, out int linePosition)
{
sourceUri = SourceUri;
lineNumber = LineNumber;
linePosition = LinePosition;
}
}
class VisualTreeChangeEventArgs : EventArgs
{
public VisualTreeChangeEventArgs(object parent, object child, int childIndex, VisualTreeChangeType changeType)
{
Parent = parent;
Child = child;
ChildIndex = childIndex;
ChangeType = changeType;
}
public object Parent { get; }
public object Child { get; }
public int ChildIndex { get; }
public VisualTreeChangeType ChangeType { get; }
}
enum VisualTreeChangeType
{
Add = 0,
Remove = 1
}
}

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

@ -10,8 +10,6 @@ namespace Xamarin.Forms.Xaml
[ContentProperty(nameof(Key))]
public sealed class StaticResourceExtension : IMarkupExtension
{
internal static bool _mockDebuggerIsAttached; //for unit testing
public string Key { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
@ -28,8 +26,7 @@ namespace Xamarin.Forms.Xaml
&& !TryGetApplicationLevelResource(Key, out resource, out resourceDictionary))
throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
if (System.Diagnostics.Debugger.IsAttached || _mockDebuggerIsAttached)
Diagnostics.ResourceDictionaryDiagnostics.OnStaticResourceResolved(resourceDictionary, Key, valueProvider.TargetObject, valueProvider.TargetProperty);
Diagnostics.ResourceDictionaryDiagnostics.OnStaticResourceResolved(resourceDictionary, Key, valueProvider.TargetObject, valueProvider.TargetProperty);
return CastTo(resource, valueProvider.TargetProperty);
}