Merge branch '3.6.0' into 4.0.0

This commit is contained in:
Stephane Delcroix 2019-03-18 09:40:11 +01:00
Родитель 7c71feec26 6ce52612e2
Коммит fb169ce976
21 изменённых файлов: 203 добавлений и 43 удалений

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

@ -1,4 +1,5 @@
using Android.Content;
#if !FORMS_APPLICATION_ACTIVITY && !PRE_APPLICATION_CLASS
using Android.Content;
using Xamarin.Forms;
using Xamarin.Forms.ControlGallery.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
@ -24,4 +25,5 @@ namespace Xamarin.Forms.ControlGallery.Android
transaction.SetCustomAnimations(Resource.Animation.enter_from_left, Resource.Animation.exit_to_right);
}
}
}
}
#endif

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

@ -246,6 +246,7 @@ namespace Xamarin.Forms.Controls
[Preserve(AllMembers = true)]
internal class CorePageView : ListView
{
[Preserve(AllMembers = true)]
internal class GalleryPageFactory
{
public GalleryPageFactory(Func<Page> create, string title)
@ -258,11 +259,18 @@ namespace Xamarin.Forms.Controls
};
Title = title;
TitleAutomationId = $"{Title}AutomationId";
}
public Func<Page> Realize { get; set; }
public string Title { get; set; }
public string TitleAutomationId
{
get;
set;
}
public override string ToString()
{
// a11y: let Narrator read a friendly string instead of the default ToString()
@ -287,7 +295,6 @@ namespace Xamarin.Forms.Controls
new GalleryPageFactory(() => new CellForceUpdateSizeGalleryPage(), "Cell Force Update Size Gallery"),
new GalleryPageFactory(() => new AppearingGalleryPage(), "Appearing Gallery"),
new GalleryPageFactory(() => new EntryCoreGalleryPage(), "Entry Gallery"),
new GalleryPageFactory(() => new EntryCoreGalleryPage{ Visual = VisualMarker.Material }, "Entry Gallery (Material)"),
new GalleryPageFactory(() => new MaterialEntryGalleryPage(), "Entry Material Demos"),
new GalleryPageFactory(() => new NavBarTitleTestPage(), "Titles And Navbar Windows"),
new GalleryPageFactory(() => new PanGestureGalleryPage(), "Pan gesture Gallery"),
@ -390,7 +397,7 @@ namespace Xamarin.Forms.Controls
new GalleryPageFactory(() => new TableViewGallery(), "TableView Gallery - Legacy"),
new GalleryPageFactory(() => new TemplatedCarouselGallery(), "TemplatedCarouselPage Gallery - Legacy"),
new GalleryPageFactory(() => new TemplatedTabbedGallery(), "TemplatedTabbedPage Gallery - Legacy"),
new GalleryPageFactory(() => new UnevenViewCellGallery(), "UnevenViewCell Gallery - Legacy"),
new GalleryPageFactory(() => new UnevenViewCellGallery(), "UnevenViewCell Gallery - Legacy"),
new GalleryPageFactory(() => new UnevenListGallery(), "UnevenList Gallery - Legacy"),
new GalleryPageFactory(() => new ViewCellGallery(), "ViewCell Gallery - Legacy"),
new GalleryPageFactory(() => new WebViewGallery(), "WebView Gallery - Legacy"),
@ -435,9 +442,12 @@ namespace Xamarin.Forms.Controls
}
})
});
return cell;
});
template.SetBinding(TextCell.TextProperty, "Title");
template.SetBinding(TextCell.AutomationIdProperty, "TitleAutomationId");
BindingContext = _pages;
ItemTemplate = template;

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

@ -98,6 +98,19 @@ namespace Xamarin.Forms.Controls
_isVisibleStateViewContainer.View.IsVisible = !_isVisibleStateViewContainer.View.IsVisible;
});
_isFocusedStateViewContainer.StateChangeButton.Command = new Command(() => {
if ((bool)isFocusedView.GetValue(VisualElement.IsFocusedProperty))
{
isFocusedView.SetValueCore(IsFocusedPropertyKey, false);
}
else
{
isFocusedView.SetValueCore(IsFocusedPropertyKey, true);
}
});
_focusStateViewContainer.StateChangeButton.Command = new Command (() => {
if (_focusStateViewContainer.View.IsFocused) {
_focusStateViewContainer.View.Unfocus ();

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

@ -24,8 +24,11 @@ namespace Xamarin.Forms.Controls
BindingContext = view,
AutomationId = name + "StateLabel"
};
if (name != "Focus")
stateValueLabel.SetBinding (Label.TextProperty, name, converter: new GenericValueConverter (o => o.ToString()));
if(name == "Focus" || name == "Unfocused" || name == "Focused")
stateValueLabel.SetBinding(Label.TextProperty, "IsFocused", converter: new GenericValueConverter(o => o.ToString()));
else
stateValueLabel.SetBinding (Label.TextProperty, name, converter: new GenericValueConverter (o => o.ToString()));
StateChangeButton = new Button {
Text = "Change State: " + name,

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

@ -1,8 +1,10 @@
using NUnit.Framework;
using Xamarin.Forms.Controls.Issues;
using Xamarin.Forms.CustomAttributes;
namespace Xamarin.Forms.Core.UITests
{
[TestFixture]
[Category(UITestCategories.Entry)]
internal class EntryUITests : _ViewUITests
@ -17,9 +19,20 @@ namespace Xamarin.Forms.Core.UITests
App.NavigateToGallery(GalleryQueries.EntryGallery);
}
// TODO
[Test]
[UiTest(typeof(Entry), "Focus")]
public override void _Focus()
{
var remote = new StateViewContainerRemote(App, Test.VisualElement.Focus, PlatformViewType);
remote.GoTo();
bool isFocused = System.Convert.ToBoolean( App.Query("FocusStateLabel")[0].ReadText());
Assert.IsFalse(isFocused);
remote.TapView();
isFocused = System.Convert.ToBoolean(App.Query("FocusStateLabel")[0].ReadText());
Assert.IsTrue(isFocused);
App.Tap("FocusStateLabel");
isFocused = System.Convert.ToBoolean(App.Query("FocusStateLabel")[0].ReadText());
Assert.IsFalse(isFocused);
}
[UiTestExempt(ExemptReason.CannotTest, "Invalid interaction")]
@ -27,7 +40,6 @@ namespace Xamarin.Forms.Core.UITests
{
}
// TODO
public override void _IsFocused()
{
}
@ -37,6 +49,8 @@ namespace Xamarin.Forms.Core.UITests
{
}
// TODO
// Implement control specific ui tests
[Test]

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

@ -0,0 +1,27 @@
using NUnit.Framework;
using Xamarin.Forms.Controls.Issues;
using Xamarin.Forms.CustomAttributes;
namespace Xamarin.Forms.Core.UITests
{
#if __ANDROID__ || __IOS__
[TestFixture]
[Category(UITestCategories.Entry)]
[Category(UITestCategories.Visual)]
internal class MaterialEntryUITests : EntryUITests
{
protected override void NavigateToGallery()
{
App.NavigateToGallery(GalleryQueries.EntryGallery, "Material");
}
[Test]
[UiTest(typeof(Entry), "Focus")]
public override void _Focus()
{
base._Focus();
}
}
#endif
}

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

@ -9,29 +9,45 @@ namespace Xamarin.Forms.Core.UITests
{
internal static class AppExtensions
{
public static AppRect ScreenBounds (this IApp app)
public static AppRect ScreenBounds(this IApp app)
{
return app.Query (Queries.Root ()).First().Rect;
return app.Query(Queries.Root()).First().Rect;
}
public static void NavigateBack (this IApp app)
public static void NavigateBack(this IApp app)
{
app.Back();
}
public static void NavigateToGallery (this IApp app, string page)
public static void NavigateToGallery(this IApp app, string page)
{
NavigateToGallery(app, page, null);
}
public static void NavigateToGallery(this IApp app, string page, string visual)
{
const string goToTestButtonQuery = "* marked:'GoToTestButton'";
app.WaitForElement(q => q.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromSeconds(10));
var text = Regex.Match (page, "'(?<text>[^']*)'").Groups["text"].Value;
var text = Regex.Match(page, "'(?<text>[^']*)'").Groups["text"].Value;
app.WaitForElement("SearchBar");
app.EnterText (q => q.Raw ("* marked:'SearchBar'"), text);
app.EnterText(q => q.Raw("* marked:'SearchBar'"), text);
app.Tap (q => q.Raw (goToTestButtonQuery));
app.WaitForNoElement (o => o.Raw (goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromMinutes(2));
if(!String.IsNullOrWhiteSpace(visual))
{
app.DismissKeyboard();
app.ActivateContextMenu($"{text}AutomationId");
app.Tap("Select Visual");
app.Tap("Material");
}
else
{
app.Tap(q => q.Raw(goToTestButtonQuery));
}
app.WaitForNoElement(o => o.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromMinutes(2));
}
@ -43,10 +59,11 @@ namespace Xamarin.Forms.Core.UITests
{
elements = app.Query(elementQuery);
tryCount++;
if (elements.Length == 0 && onFail != null) onFail();
if (elements.Length == 0 && onFail != null)
onFail();
}
return elements;
}
}
}
}

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

@ -35,6 +35,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Tests\Legacy-CellsUITests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tests\Legacy-UnevenListTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tests\MapUITests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tests\MaterialEntryUITests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tests\PickerUITests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tests\ProgressBarUITests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tests\RootGalleryUITests.cs" />

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

@ -61,6 +61,8 @@ namespace Xamarin.Forms
if (result != null && result.Parent != this)
OnChildAdded(result);
if (result == null)
throw new InvalidOperationException($"No Content found for {nameof(ShellContent)}, Title:{Title}, Route {Route}");
if (_delayedQueryParams != null && result != null) {
ApplyQueryAttributes(result, _delayedQueryParams);
@ -138,6 +140,10 @@ namespace Xamarin.Forms
// parent new item
shellContent.OnChildAdded(newElement);
}
else if(newValue != null)
{
throw new InvalidOperationException($"{nameof(ShellContent)} {nameof(Content)} should be of type {nameof(Page)}. Title {shellContent?.Title}, Route {shellContent?.Route} ");
}
}
if (shellContent.Parent?.Parent is ShellItem shellItem)

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

@ -10,7 +10,7 @@ using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Xamarin.Forms.Entry), typeof(MaterialEntryRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace Xamarin.Forms.Material.Android
{
public sealed class MaterialEntryRenderer : EntryRendererBase<MaterialFormsTextInputLayout>
public class MaterialEntryRenderer : EntryRendererBase<MaterialFormsTextInputLayout>
{
MaterialFormsEditText _textInputEditText;
MaterialFormsTextInputLayout _textInputLayout;

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

@ -6,6 +6,8 @@ using Android.Runtime;
using Android.Util;
using Android.Support.V4.View;
using Android.Content.Res;
using AView = Android.Views.View;
using Xamarin.Forms.Platform.Android.AppCompat;
namespace Xamarin.Forms.Material.Android
{
@ -94,9 +96,16 @@ namespace Xamarin.Forms.Material.Android
* and this is the only way to set it away from that and to whatever the user specified
* 2) The HintTextColor has a different alpha when focused vs not focused
* */
void OnFocusChange(object sender, FocusChangeEventArgs e) =>
void OnFocusChange(object sender, FocusChangeEventArgs e)
{
Device.BeginInvokeOnMainThread(() => ApplyTheme());
// propagate the focus changed event to the View Renderer base class
if (Parent is AView.IOnFocusChangeListener focusChangeListener)
focusChangeListener.OnFocusChange(EditText, e.HasFocus);
}
internal void SetHint(string hint, VisualElement element)
{
if (HintEnabled != !String.IsNullOrWhiteSpace(hint))

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

@ -1,3 +1,4 @@
using System;
using System.ComponentModel;
using Android.Content;
using Android.Views;
@ -20,6 +21,7 @@ namespace Xamarin.Forms.Platform.Android
UpdateHeight();
UpdateIsEnabled();
UpdateFlowDirection();
UpdateAutomationId();
View.SetImageVisible(false);
return View;
@ -37,6 +39,13 @@ namespace Xamarin.Forms.Platform.Android
UpdateHeight();
else if (args.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
UpdateFlowDirection();
else if (args.PropertyName == VisualElement.AutomationIdProperty.PropertyName)
UpdateAutomationId();
}
void UpdateAutomationId()
{
View.ContentDescription = Cell.AutomationId;
}
void UpdateDetailText()

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

@ -16,6 +16,8 @@ namespace Xamarin.Forms.Platform.Android
{
internal static void HandleScrollBarVisibilityChange(this IScrollView scrollView)
{
if (Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat)
return;
// According to the Android Documentation
// * <p>AwakenScrollBars method should be invoked every time a subclass directly updates

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

@ -76,8 +76,7 @@ namespace Xamarin.Forms.Platform.Android
{
base.Draw(canvas);
}
catch (Java.Lang.NullPointerException npe)
when (npe.Message.Contains("ScrollBarDrawable.mutate()"))
catch (Java.Lang.NullPointerException)
{
// This will most likely never run since UpdateScrollBars is called
// when the scrollbars visibilities are updated but I left it here

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

@ -143,8 +143,7 @@ namespace Xamarin.Forms.Platform.Android
base.Draw(canvas);
}
catch (Java.Lang.NullPointerException npe)
when(npe.Message.Contains("ScrollBarDrawable.mutate()"))
catch (Java.Lang.NullPointerException)
{
// This will most likely never run since UpdateScrollBars is called
// when the scrollbars visibilities are updated but I left it here

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

@ -23,6 +23,7 @@ namespace Xamarin.Forms.Platform.Android
[Obsolete("This constructor is obsolete as of version 2.5. Please use ViewRenderer(Context) instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
protected ViewRenderer()
{
}
}
@ -37,6 +38,7 @@ namespace Xamarin.Forms.Platform.Android
[EditorBrowsable(EditorBrowsableState.Never)]
protected ViewRenderer()
{
}
protected virtual TNativeView CreateNativeControl()

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

@ -236,7 +236,7 @@
</Style>
<DataTemplate x:Key="TextCell">
<StackPanel>
<StackPanel AutomationProperties.AutomationId="{Binding AutomationId}">
<TextBlock
Text="{Binding Text}"
Style="{ThemeResource BaseTextBlockStyle}"

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

@ -34,6 +34,7 @@ namespace Xamarin.Forms.Platform.iOS
UpdateBackground(tvc, item);
SetAccessibility(tvc, item);
UpdateAutomationId(tvc, textCell);
return tvc;
}
@ -59,9 +60,15 @@ namespace Xamarin.Forms.Platform.iOS
tvc.DetailTextLabel.TextColor = textCell.DetailColor.ToUIColor(DefaultTextColor);
else if (args.PropertyName == Cell.IsEnabledProperty.PropertyName)
UpdateIsEnabled(tvc, textCell);
else if (args.PropertyName == TextCell.AutomationIdProperty.PropertyName)
UpdateAutomationId(tvc, textCell);
HandlePropertyChanged(tvc, args);
}
void UpdateAutomationId(CellTableViewCell tvc, TextCell cell)
{
tvc.AccessibilityIdentifier = cell.AutomationId;
}
protected virtual void HandlePropertyChanged(object sender, PropertyChangedEventArgs args)
{

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

@ -564,14 +564,14 @@ namespace Xamarin.Forms.Xaml.UnitTests
<StackLayout>
<ListView ItemsSource=""{x:Static Foo}"" />
<ListView ItemsSource=""{local:Missing Test}"" />
<Label Text=""{Binding Foo"" />
</StackLayout>
</ContentPage>";
var exceptions = new List<Exception>();
Xamarin.Forms.Internals.ResourceLoader.ExceptionHandler = exceptions.Add;
Assert.DoesNotThrow(() => XamlLoader.Create(xaml, true));
Assert.That(exceptions.Count, Is.GreaterThan(1));
}
}
[Test]
public void CanResolveRootNode()
@ -580,7 +580,6 @@ namespace Xamarin.Forms.Xaml.UnitTests
string clrNamespace = null;
string typeName = null;
XamlLoader.FallbackTypeResolver = (fallbackTypeInfos, type) =>
{
assemblyName = fallbackTypeInfos?[1].AssemblyName;
@ -628,6 +627,25 @@ namespace Xamarin.Forms.Xaml.UnitTests
Assert.That(clrNamespace, Is.EqualTo("my.namespace"));
Assert.That(typeName, Is.EqualTo("MissingType"));
}
[Test]
public void IgnoreNamedMissingTypeException()
{
var xaml = @"
<ContentPage xmlns=""http://xamarin.com/schemas/2014/forms""
xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
xmlns:local=""clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests"">
<StackLayout>
<local:Missing x:Name=""MyName"" />
<Button x:Name=""button"" />
<Button x:Name=""button"" />
</StackLayout>
</ContentPage>";
var exceptions = new List<Exception>();
Xamarin.Forms.Internals.ResourceLoader.ExceptionHandler = exceptions.Add;
Assert.DoesNotThrow(() => XamlLoader.Create(xaml, true));
Assert.That(exceptions.Count, Is.GreaterThan(1));
}
}
public class InstantiateThrows

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

@ -78,17 +78,28 @@ namespace Xamarin.Forms.Xaml
if (expression.StartsWith("{}", StringComparison.Ordinal))
return new ValueNode(expression.Substring(2), null);
if (expression[expression.Length - 1] != '}')
throw new Exception("Expression must end with '}'");
if (expression[expression.Length - 1] != '}') {
var ex = new XamlParseException("Expression must end with '}'", xmlLineInfo);
if (Context.ExceptionHandler != null) {
Context.ExceptionHandler(ex);
return null;
}
throw ex;
}
int len;
string match;
if (!MarkupExpressionParser.MatchMarkup(out match, expression, out len))
if (!MarkupExpressionParser.MatchMarkup(out var match, expression, out var len))
throw new Exception();
expression = expression.Substring(len).TrimStart();
if (expression.Length == 0)
throw new Exception("Expression did not end in '}'");
expression = expression.Substring(len).TrimStart();
if (expression.Length == 0) {
var ex = new XamlParseException("Expression did not end in '}'", xmlLineInfo);
if (Context.ExceptionHandler != null)
{
Context.ExceptionHandler(ex);
return null;
}
throw ex;
}
var serviceProvider = new XamlServiceProvider(node, Context);
serviceProvider.Add(typeof (IXmlNamespaceResolver), nsResolver);

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

@ -30,18 +30,29 @@ namespace Xamarin.Forms.Xaml
{
if (!IsXNameProperty(node, parentNode))
return;
try
{
try {
((IElementNode)parentNode).Namescope.RegisterName((string)node.Value, Values[parentNode]);
}
catch (ArgumentException ae)
{
catch (ArgumentException ae) {
if (ae.ParamName != "name")
throw ae;
throw new XamlParseException($"An element with the name \"{(string)node.Value}\" already exists in this NameScope", node);
var xpe = new XamlParseException($"An element with the name \"{(string)node.Value}\" already exists in this NameScope", node);
if (Context.ExceptionHandler != null) {
Context.ExceptionHandler(xpe);
return;
}
throw xpe;
}
var element = Values[parentNode] as Element;
if (element != null)
catch (KeyNotFoundException knfe) {
if (Context.ExceptionHandler != null) {
Context.ExceptionHandler(knfe);
return;
}
throw knfe;
}
if (Values[parentNode] is Element element)
element.StyleId = element.StyleId ?? (string)node.Value;
}