Merge branch '4.2.0' into 4.3.0

This commit is contained in:
Samantha Houts 2019-09-05 10:27:20 -07:00
Родитель b4c24ac249 00f772fdca
Коммит 0dfade22be
25 изменённых файлов: 603 добавлений и 310 удалений

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

@ -113,8 +113,16 @@ namespace Xamarin.Forms.Build.Tasks
var br2 = Instruction.Create(OpCodes.Ldarg_0);
var ret = Instruction.Create(OpCodes.Ret);
il.Emit(OpCodes.Ldarg_0);
var baseCtor = module.ImportReference(typeDef.BaseType.Resolve().GetConstructors().First(c => c.HasParameters == false));
baseCtor = module.ImportReference(baseCtor.ResolveGenericParameters(typeDef.BaseType, module));
MethodReference baseCtor;
if (typeDef.BaseType.Resolve().GetConstructors().FirstOrDefault(c => c.HasParameters && c.Parameters.Count == 1 && c.Parameters[0].Name == "useCompiledXaml") is MethodDefinition baseCtorDef) {
baseCtor = module.ImportReference(baseCtorDef);
baseCtor = module.ImportReference(baseCtor.ResolveGenericParameters(typeDef.BaseType, module));
il.Emit(OpCodes.Ldarg_1);
}
else {
baseCtor = module.ImportReference(typeDef.BaseType.Resolve().GetConstructors().First(c => c.HasParameters == false));
baseCtor = module.ImportReference(baseCtor.ResolveGenericParameters(typeDef.BaseType, module));
}
il.Emit(OpCodes.Callvirt, baseCtor);
il.Emit(OpCodes.Nop);

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

@ -10,10 +10,7 @@ namespace Xamarin.Forms.Build.Tasks
{
class SetNamescopesAndRegisterNamesVisitor : IXamlNodeVisitor
{
public SetNamescopesAndRegisterNamesVisitor(ILContext context)
{
Context = context;
}
public SetNamescopesAndRegisterNamesVisitor(ILContext context) => Context = context;
ILContext Context { get; }
@ -25,7 +22,7 @@ namespace Xamarin.Forms.Build.Tasks
public bool IsResourceDictionary(ElementNode node)
{
var parentVar = Context.Variables[(IElementNode)node];
var parentVar = Context.Variables[node];
return parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary"
|| parentVar.VariableType.Resolve().BaseType?.FullName == "Xamarin.Forms.ResourceDictionary";
}
@ -64,7 +61,7 @@ namespace Xamarin.Forms.Build.Tasks
public void Visit(RootNode node, INode parentNode)
{
var namescopeVarDef = CreateNamescope();
var namescopeVarDef = GetOrCreateNameScope(node);
IList<string> namesInNamescope = new List<string>();
if (Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Body.Method.Module.ImportReference(("Xamarin.Forms.Core", "Xamarin.Forms", "BindableObject"))))
SetNameScope(node, namescopeVarDef);
@ -77,33 +74,38 @@ namespace Xamarin.Forms.Build.Tasks
}
static bool IsDataTemplate(INode node, INode parentNode)
{
var parentElement = parentNode as IElementNode;
INode createContent;
if (parentElement != null && parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
createContent == node)
return true;
return false;
}
=> parentNode is IElementNode parentElement && parentElement.Properties.TryGetValue(XmlName._CreateContent, out INode createContent) && createContent == node;
static bool IsStyle(INode node, INode parentNode)
{
var pnode = parentNode as ElementNode;
return pnode != null && pnode.XmlType.Name == "Style";
}
static bool IsStyle(INode node, INode parentNode) => parentNode is ElementNode pnode && pnode.XmlType.Name == "Style";
static bool IsVisualStateGroupList(ElementNode node)
{
return node != null && node.XmlType.Name == "VisualStateGroup" && node.Parent is IListNode;
}
static bool IsVisualStateGroupList(ElementNode node) => node != null && node.XmlType.Name == "VisualStateGroup" && node.Parent is IListNode;
static bool IsXNameProperty(ValueNode node, INode parentNode)
=> parentNode is IElementNode parentElement && parentElement.Properties.TryGetValue(XmlName.xName, out INode xNameNode) && xNameNode == node;
VariableDefinition GetOrCreateNameScope(ElementNode node)
{
var parentElement = parentNode as IElementNode;
INode xNameNode;
if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
return true;
return false;
var module = Context.Body.Method.Module;
var vardef = new VariableDefinition(module.ImportReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "NameScope")));
Context.Body.Variables.Add(vardef);
var stloc = Instruction.Create(OpCodes.Stloc, vardef);
if (Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Body.Method.Module.ImportReference(("Xamarin.Forms.Core", "Xamarin.Forms", "BindableObject")))) {
var namescoperef = ("Xamarin.Forms.Core", "Xamarin.Forms", "BindableObject");
Context.IL.Append(Context.Variables[node].LoadAs(module.GetTypeDefinition(namescoperef), module));
Context.IL.Emit(OpCodes.Call, module.ImportMethodReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "NameScope"),
methodName: "GetNameScope",
parameterTypes: new[] { namescoperef },
isStatic: true));
Context.IL.Emit(OpCodes.Dup);
Context.IL.Emit(OpCodes.Brtrue, stloc);
Context.IL.Emit(OpCodes.Pop);
}
Context.IL.Emit(OpCodes.Newobj, module.ImportCtorReference(("Xamarin.Forms.Core", "Xamarin.Forms.Internals", "NameScope"), parameterTypes: null));
Context.IL.Append(stloc);
return vardef;
}
VariableDefinition CreateNamescope()

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

@ -1,21 +1,41 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System;
#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 2818, "Right-to-Left MasterDetail in Xamarin.Forms Hamburger icon issue", PlatformAffected.Android)]
public class Issue2818 : MasterDetailPage
public class Issue2818 : TestMasterDetailPage
{
public Issue2818()
protected override void Init()
{
FlowDirection = FlowDirection.RightToLeft;
Master = new ContentPage
{
Title = "Master",
BackgroundColor = Color.SkyBlue,
IconImageSource = "menuIcon"
IconImageSource = "menuIcon",
Content = new StackLayout()
{
Children =
{
new Button()
{
Text = "If you can see me the test has passed",
AutomationId = "CloseMasterView",
Command = new Command(() => IsPresented = false)
}
},
AutomationId = "MasterLayout"
},
Padding = new Thickness(0, 42, 0, 0)
};
Detail = new NavigationPage(new ContentPage
@ -26,21 +46,92 @@ namespace Xamarin.Forms.Controls.Issues
Children = {
new Label
{
Text = "The page must be with RightToLeft FlowDirection. Hamburger icon in main page must be going to right side."
Text = "The page must be with RightToLeft FlowDirection. Hamburger icon in main page must be going to right side. There should be visible text inside the Master View"
},
new Button
{
Text = "Set RightToLeft",
Command = new Command(() => FlowDirection = FlowDirection.RightToLeft)
Command = new Command(() => FlowDirection = FlowDirection.RightToLeft),
AutomationId = "ShowRightToLeft"
},
new Button
{
Text = "Set LeftToRight",
Command = new Command(() => FlowDirection = FlowDirection.LeftToRight)
Command = new Command(() => FlowDirection = FlowDirection.LeftToRight),
AutomationId = "ShowLeftToRight"
},
new Button
{
Text = "Open Master View",
Command = new Command(() => IsPresented = true),
AutomationId = "OpenMasterView"
},
new Label()
{
Text = Device.Idiom.ToString(),
AutomationId = "Idiom"
}
}
}
});
}
#if UITEST
[Test]
public void MasterViewMovesAndContentIsVisible()
{
var idiom = RunningApp.WaitForElement("Idiom");
// This behavior is currently broken on a phone device Issue 7270
if (idiom[0].ReadText() != "Tablet")
return;
RunningApp.Tap("OpenMasterView");
RunningApp.Tap("CloseMasterView");
RunningApp.SetOrientationLandscape();
RunningApp.Tap("OpenMasterView");
var positionStart = RunningApp.WaitForElement("CloseMasterView");
RunningApp.Tap("ShowLeftToRight");
var results = RunningApp.QueryUntilPresent(() =>
{
var secondPosition = RunningApp.Query("CloseMasterView");
if (secondPosition.Length == 0)
return null;
if (secondPosition[0].Rect.X < positionStart[0].Rect.X)
return secondPosition;
return null;
});
Assert.IsNotNull(results, "Master View Did not change flow direction correctly");
Assert.AreEqual(1, results.Length, "Master View Did not change flow direction correctly");
}
#if __IOS__
[Test]
public void MasterViewSizeDoesntChangeAfterBackground()
{
var idiom = RunningApp.WaitForElement("Idiom");
// This behavior is currently broken on a phone device Issue 7270
if (idiom[0].ReadText() != "Tablet")
return;
RunningApp.SetOrientationLandscape();
RunningApp.Tap("CloseMasterView");
RunningApp.Tap("ShowLeftToRight");
var windowSize = RunningApp.WaitForElement("MasterLayout")[0];
RunningApp.SendAppToBackground(TimeSpan.FromSeconds(5));
var newWindowSize = RunningApp.WaitForElement("MasterLayout")[0];
Assert.AreEqual(newWindowSize.Rect.Width, windowSize.Rect.Width);
Assert.AreEqual(newWindowSize.Rect.Height, windowSize.Rect.Height);
}
#endif
#endif
}
}

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

@ -4,6 +4,10 @@ using System.IO;
using Xamarin.UITest;
using Xamarin.UITest.Queries;
#if __IOS__
using Xamarin.UITest.iOS;
#endif
namespace Xamarin.Forms.Controls
{
/// <summary>
@ -445,6 +449,16 @@ namespace Xamarin.Forms.Controls
{
get { return _app.TestServer; }
}
#if __IOS__
public void SendAppToBackground(TimeSpan timeSpan)
{
if (_app is iOSApp app)
{
app.SendAppToBackground(timeSpan);
}
}
#endif
}
}
#endif

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

@ -21,6 +21,7 @@
GalleryBuilder.NavButton("Header/Footer (Template)", () => new HeaderFooterTemplate(), Navigation),
GalleryBuilder.NavButton("Header/Footer (Grid)", () => new HeaderFooterGrid(), Navigation),
GalleryBuilder.NavButton("Footer Only (String)", () => new FooterOnlyString(), Navigation),
GalleryBuilder.NavButton("Header/Footer (Grid Horizontal)", () => new HeaderFooterGridHorizontal(), Navigation),
}
}
};

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

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.HeaderFooterGalleries.HeaderFooterGridHorizontal">
<ContentPage.Content>
<CollectionView x:Name="CollectionView" >
<CollectionView.ItemsLayout>
<GridItemsLayout Span="3" Orientation="Horizontal" HorizontalItemSpacing="4" VerticalItemSpacing="2"></GridItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.Header>
<StackLayout>
<Image Source="oasis.jpg" Aspect="AspectFill" HeightRequest="60"></Image>
<Label Text="This Is A Header" TextColor="AntiqueWhite" HorizontalTextAlignment="Center"
FontAttributes="Bold" FontSize="36" />
<StackLayout Orientation="Horizontal">
<Button Text="Add Content" Clicked="Handle_Clicked"></Button>
</StackLayout>
</StackLayout>
</CollectionView.Header>
<CollectionView.Footer>
<StackLayout>
<Image Source="cover1.jpg" Aspect="AspectFill" HeightRequest="80"></Image>
<Label Text="This Is A Footer" TextColor="AntiqueWhite" HorizontalTextAlignment="Center" Rotation="10"
FontAttributes="Bold" FontSize="20" />
<StackLayout Orientation="Horizontal">
<Button Text="Add Content" Clicked="Handle_Clicked"></Button>
</StackLayout>
</StackLayout>
</CollectionView.Footer>
</CollectionView>
</ContentPage.Content>
</ContentPage>

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

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.HeaderFooterGalleries
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class HeaderFooterGridHorizontal : ContentPage
{
readonly DemoFilteredItemSource _demoFilteredItemSource = new DemoFilteredItemSource(10);
public HeaderFooterGridHorizontal()
{
InitializeComponent();
CollectionView.ItemTemplate = ExampleTemplates.PhotoTemplate();
CollectionView.ItemsSource = _demoFilteredItemSource.Items;
}
void Handle_Clicked(object sender, System.EventArgs e)
{
if (sender is VisualElement ve && ve.Parent is StackLayout sl)
sl.Children.Add(new Label() { Text = "Grow" });
}
}
}

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

@ -80,6 +80,9 @@
<EmbeddedResource Update="GalleryPages\MapElementsGallery.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Update="GalleryPages\CollectionViewGalleries\HeaderFooterGalleries\HeaderFooterGridHorizontal.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Update="GalleryPages\MapGallery.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>

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

@ -5,6 +5,9 @@ using Xamarin.UITest;
using Xamarin.UITest.Queries;
using System.Text.RegularExpressions;
using System.Threading;
#if __IOS__
using Xamarin.UITest.iOS;
#endif
namespace Xamarin.UITest
{
@ -28,6 +31,17 @@ namespace Xamarin.UITest
return results;
}
#if __IOS__
public static void SendAppToBackground(this IApp app, TimeSpan timeSpan)
{
if(app is Xamarin.Forms.Controls.ScreenshotConditionalApp sca)
{
sca.SendAppToBackground(timeSpan);
Thread.Sleep(timeSpan.Add(TimeSpan.FromSeconds(2)));
}
}
#endif
}
}

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

@ -23,10 +23,7 @@ namespace Xamarin.Forms.Internals
_names[name] = scopedElement;
}
public static INameScope GetNameScope(BindableObject bindable)
{
return (INameScope)bindable.GetValue(NameScopeProperty);
}
public static INameScope GetNameScope(BindableObject bindable) => (INameScope)bindable.GetValue(NameScopeProperty);
public static void SetNameScope(BindableObject bindable, INameScope value)
{

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

@ -43,7 +43,7 @@ namespace Xamarin.Forms.Platform.Android
// If power saver is active, then animations will not run
_energySaveModeDisabled = !powerSaveOn;
// Notify the ticker that this value has changed, so it can manage animations in progress
OnSystemEnabledChanged();
}
@ -56,8 +56,20 @@ namespace Xamarin.Forms.Platform.Android
return false;
}
var scale = global::Android.Provider.Settings.Global.GetFloat(resolver, global::Android.Provider.Settings.Global.AnimatorDurationScale, 0);
return scale > 0;
float animationScale;
if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr1)
{
animationScale = global::Android.Provider.Settings.Global.GetFloat(resolver, global::Android.Provider.Settings.Global.AnimatorDurationScale, 1);
}
else
{
#pragma warning disable 0618
animationScale = global::Android.Provider.Settings.System.GetFloat(resolver, global::Android.Provider.Settings.System.AnimatorDurationScale, 1);
#pragma warning restore 0618
}
return animationScale > 0;
}
public void Dispose()
@ -95,4 +107,4 @@ namespace Xamarin.Forms.Platform.Android
SendSignals();
}
}
}
}

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

@ -45,7 +45,7 @@ namespace Xamarin.Forms.Platform.iOS
// If we're updating from a previous layout, we should keep any settings for the SelectableItemsViewController around
var selectableItemsViewController = Delegator?.SelectableItemsViewController;
Delegator = new UICollectionViewDelegator(ItemsViewLayout, this);
CollectionView.Delegate = Delegator;
if (CollectionView.CollectionViewLayout != ItemsViewLayout)
@ -54,9 +54,9 @@ namespace Xamarin.Forms.Platform.iOS
// Make sure the new layout is sized properly
ItemsViewLayout.ConstrainTo(CollectionView.Bounds.Size);
CollectionView.SetCollectionViewLayout(ItemsViewLayout, false);
// Reload the data so the currently visible cells get laid out according to the new layout
CollectionView.ReloadData();
}
@ -154,8 +154,19 @@ namespace Xamarin.Forms.Platform.iOS
// This update is only relevant if you have a footer view because it's used to place the footer view
// based on the ContentSize so we just update the positions if the ContentSize has changed
if(_footerUIView != null && _footerUIView.Frame.Y != ItemsViewLayout.CollectionViewContentSize.Height)
UpdateHeaderFooterPosition();
if (_footerUIView != null)
{
if (IsHorizontal)
{
if (_footerUIView.Frame.X != ItemsViewLayout.CollectionViewContentSize.Width)
UpdateHeaderFooterPosition();
}
else
{
if (_footerUIView.Frame.Y != ItemsViewLayout.CollectionViewContentSize.Height)
UpdateHeaderFooterPosition();
}
}
}
protected virtual IItemsViewSource CreateItemsViewSource()
@ -172,7 +183,7 @@ namespace Xamarin.Forms.Platform.iOS
public override nint NumberOfSections(UICollectionView collectionView)
{
CheckForEmptySource();
CheckForEmptySource();
return ItemsSource.GroupCount;
}
@ -317,26 +328,53 @@ namespace Xamarin.Forms.Platform.iOS
CollectionView.RegisterClassForCell(typeof(VerticalTemplatedCell), VerticalTemplatedCell.ReuseId);
}
bool IsHorizontal => (ItemsView?.ItemsLayout as ItemsLayout)?.Orientation == ItemsLayoutOrientation.Horizontal;
void UpdateHeaderFooterPosition()
{
var currentInset = CollectionView.ContentInset;
nfloat headerHeight = _headerUIView?.Frame.Height ?? 0f;
nfloat footerHeight = _footerUIView?.Frame.Height ?? 0f;
if(_headerUIView != null && _headerUIView.Frame.Y != headerHeight)
_headerUIView.Frame = new CoreGraphics.CGRect(0, -headerHeight, CollectionView.Frame.Width, headerHeight);
if (_footerUIView != null && (_footerUIView.Frame.Y != ItemsViewLayout.CollectionViewContentSize.Height))
_footerUIView.Frame = new CoreGraphics.CGRect(0, ItemsViewLayout.CollectionViewContentSize.Height, CollectionView.Frame.Width, footerHeight);
if (CollectionView.ContentInset.Top != headerHeight || CollectionView.ContentInset.Bottom != footerHeight)
if (IsHorizontal)
{
CollectionView.ContentInset = new UIEdgeInsets(headerHeight, 0, footerHeight, 0);
var currentInset = CollectionView.ContentInset;
// if the header grows it will scroll off the screen because if you change the content inset iOS adjusts the content offset so the list doesn't move
// this changes the offset of the list by how much ever the header size has changed
CollectionView.ContentOffset = new CoreGraphics.CGPoint(CollectionView.ContentOffset.X, CollectionView.ContentOffset.Y + (currentInset.Top - CollectionView.ContentInset.Top));
nfloat headerWidth = _headerUIView?.Frame.Width ?? 0f;
nfloat footerWidth = _footerUIView?.Frame.Width ?? 0f;
if (_headerUIView != null && _headerUIView.Frame.X != headerWidth)
_headerUIView.Frame = new CoreGraphics.CGRect(-headerWidth, 0, headerWidth, CollectionView.Frame.Height);
if (_footerUIView != null && (_footerUIView.Frame.X != ItemsViewLayout.CollectionViewContentSize.Width))
_footerUIView.Frame = new CoreGraphics.CGRect(ItemsViewLayout.CollectionViewContentSize.Width, 0, footerWidth, CollectionView.Frame.Height);
if (CollectionView.ContentInset.Left != headerWidth || CollectionView.ContentInset.Right != footerWidth)
{
CollectionView.ContentInset = new UIEdgeInsets(0, headerWidth, 0, footerWidth);
// if the header grows it will scroll off the screen because if you change the content inset iOS adjusts the content offset so the list doesn't move
// this changes the offset of the list by however much the header size has changed
CollectionView.ContentOffset = new CoreGraphics.CGPoint(CollectionView.ContentOffset.X + (currentInset.Left - CollectionView.ContentInset.Left), CollectionView.ContentOffset.Y);
}
}
else
{
var currentInset = CollectionView.ContentInset;
nfloat headerHeight = _headerUIView?.Frame.Height ?? 0f;
nfloat footerHeight = _footerUIView?.Frame.Height ?? 0f;
if (_headerUIView != null && _headerUIView.Frame.Y != headerHeight)
_headerUIView.Frame = new CoreGraphics.CGRect(0, -headerHeight, CollectionView.Frame.Width, headerHeight);
if (_footerUIView != null && (_footerUIView.Frame.Y != ItemsViewLayout.CollectionViewContentSize.Height))
_footerUIView.Frame = new CoreGraphics.CGRect(0, ItemsViewLayout.CollectionViewContentSize.Height, CollectionView.Frame.Width, footerHeight);
if (CollectionView.ContentInset.Top != headerHeight || CollectionView.ContentInset.Bottom != footerHeight)
{
CollectionView.ContentInset = new UIEdgeInsets(headerHeight, 0, footerHeight, 0);
// if the header grows it will scroll off the screen because if you change the content inset iOS adjusts the content offset so the list doesn't move
// this changes the offset of the list by however much the header size has changed
CollectionView.ContentOffset = new CoreGraphics.CGPoint(CollectionView.ContentOffset.X, CollectionView.ContentOffset.Y + (currentInset.Top - CollectionView.ContentInset.Top));
}
}
}
@ -379,9 +417,7 @@ namespace Xamarin.Forms.Platform.iOS
if (formsElement != null)
{
var request = formsElement.Measure(CollectionView.Frame.Width, double.PositiveInfinity, MeasureFlags.IncludeMargins);
Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion(formsElement, new Rectangle(0, -request.Request.Height, CollectionView.Frame.Width, request.Request.Height));
RemeasureLayout(formsElement);
formsElement.MeasureInvalidated += OnFormsElementMeasureInvalidated;
}
else if (uiView != null)
@ -390,13 +426,25 @@ namespace Xamarin.Forms.Platform.iOS
}
}
void OnFormsElementMeasureInvalidated(object sender, EventArgs e)
void RemeasureLayout(VisualElement formsElement)
{
if(sender is VisualElement formsElement)
if (IsHorizontal)
{
var request = formsElement.Measure(double.PositiveInfinity, CollectionView.Frame.Height, MeasureFlags.IncludeMargins);
Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion(formsElement, new Rectangle(-request.Request.Width, 0, request.Request.Width, CollectionView.Frame.Height));
}
else
{
var request = formsElement.Measure(CollectionView.Frame.Width, double.PositiveInfinity, MeasureFlags.IncludeMargins);
Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion(formsElement, new Rectangle(0, -request.Request.Height, CollectionView.Frame.Width, request.Request.Height));
}
}
void OnFormsElementMeasureInvalidated(object sender, EventArgs e)
{
if (sender is VisualElement formsElement)
{
RemeasureLayout(formsElement);
UpdateHeaderFooterPosition();
}
}
@ -488,4 +536,4 @@ namespace Xamarin.Forms.Platform.iOS
return (new UILabel { Text = $"{view}" }, null);
}
}
}
}

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

@ -18,16 +18,25 @@ namespace Xamarin.Forms.Platform.iOS
}
}
internal static void UpdateFlowDirection(this UIView view, IVisualElementController controller)
internal static bool UpdateFlowDirection(this UIView view, IVisualElementController controller)
{
if (controller == null || view == null || !Forms.IsiOS9OrNewer)
return;
return false;
UISemanticContentAttribute updateValue = view.SemanticContentAttribute;
if (controller.EffectiveFlowDirection.IsRightToLeft())
view.SemanticContentAttribute = UISemanticContentAttribute.ForceRightToLeft;
updateValue = UISemanticContentAttribute.ForceRightToLeft;
else if (controller.EffectiveFlowDirection.IsLeftToRight())
view.SemanticContentAttribute = UISemanticContentAttribute.ForceLeftToRight;
updateValue = UISemanticContentAttribute.ForceLeftToRight;
if(updateValue != view.SemanticContentAttribute)
{
view.SemanticContentAttribute = updateValue;
return true;
}
return false;
}
internal static void UpdateTextAlignment(this UITextField control, IVisualElementController controller)

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

@ -195,7 +195,11 @@ namespace Xamarin.Forms.Platform.iOS
if (layoutMaster)
{
var masterBounds = _masterController.View.Frame;
_masterWidth = (nfloat)Math.Max(_masterWidth, masterBounds.Width);
if (Forms.IsiOS13OrNewer)
_masterWidth = masterBounds.Width;
else
_masterWidth = (nfloat)Math.Max(_masterWidth, masterBounds.Width);
if (!masterBounds.IsEmpty)
MasterDetailPage.MasterBounds = new Rectangle(0, 0, _masterWidth, masterBounds.Height);
@ -385,7 +389,12 @@ namespace Xamarin.Forms.Platform.iOS
void UpdateFlowDirection()
{
NativeView.UpdateFlowDirection(Element);
if(NativeView.UpdateFlowDirection(Element) && Forms.IsiOS13OrNewer && NativeView.Superview != null)
{
var view = NativeView.Superview;
NativeView.RemoveFromSuperview();
view.AddSubview(NativeView);
}
}
class InnerDelegate : UISplitViewControllerDelegate

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

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<local:Gh7097Base
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh7097"
Title="Foo"
x:Name="self">
<CollectionView ItemsSource="{Binding Items}" x:Name="collectionview">
<CollectionView.ItemsLayout>
<ListItemsLayout ItemSpacing="4">
<x:Arguments>
<ItemsLayoutOrientation>Vertical</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" BackgroundColor="Green">
<Button
Text="BTN 1"
HorizontalOptions="FillAndExpand"
CommandParameter="{Binding}"
Command="{Binding BindingContext.Button1Command, Source={x:Reference self}}"/>
<Button
Text="BTN 2"
HorizontalOptions="FillAndExpand"
CommandParameter="{Binding}"
Command="{Binding BindingContext.Button2Command, Source={x:Reference self}}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</local:Gh7097Base>

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

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Windows.Input;
using NUnit.Framework;
using Xamarin.Forms;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class Gh7097 : Gh7097Base
{
public Gh7097() => InitializeComponent();
public Gh7097(bool useCompiledXaml) : base(useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
class Tests
{
IReadOnlyList<string> _flags;
[SetUp]
public void Setup()
{
Device.PlatformServices = new MockPlatformServices();
_flags = Device.Flags;
Device.SetFlags(new List<string>(Device.Flags ?? new List<string>()) { "CollectionView_Experimental" }.AsReadOnly());
}
[TearDown]
public void TearDown()
{
Device.PlatformServices = null;
Device.SetFlags(_flags);
}
[Test]
public void CanXReferenceRoot([Values(false, true)]bool useCompiledXaml)
{
var layout = new Gh7097(useCompiledXaml) { BindingContext = new {
Button1Command = new MockCommand(),
Button2Command = new MockCommand(),
} };
var cv = layout.Content as CollectionView;
var content = cv.ItemTemplate.CreateContent() as StackLayout;
var btn1 = content.Children[0] as Button;
Assert.That(btn1.Command, Is.TypeOf<MockCommand>());
}
[Test]
//this was later reported as https://github.com/xamarin/Xamarin.Forms/issues/7286
public void RegisteringXNameOnSubPages([Values(false, true)]bool useCompiledXaml)
{
var layout = new Gh7097(useCompiledXaml);
var s = layout.FindByName("self");
Assert.That(layout.self, Is.Not.Null);
Assert.That(layout.collectionview, Is.Not.Null);
}
class MockCommand : ICommand
{
#pragma warning disable 0067
public event EventHandler CanExecuteChanged;
#pragma warning restore 0067
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) => throw new NotImplementedException();
}
}
}
}

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

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh7097Base">
<ContentPage.ControlTemplate>
<ControlTemplate>
<StackLayout>
<Label Text="BASE" FontSize="30" FontAttributes="Bold" HorizontalOptions="CenterAndExpand" TextColor="Red"/>
<ContentPresenter HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</StackLayout>
</ControlTemplate>
</ContentPage.ControlTemplate>
</ContentPage>

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

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class Gh7097Base : ContentPage
{
public Gh7097Base() => InitializeComponent();
public Gh7097Base(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
}
}

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

@ -36,11 +36,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
public List<XmlName> SkipProperties { get; set; }
public Forms.Internals.INameScope Namescope {
get {
throw new NotImplementedException ();
}
}
public NameScopeRef NameScopeRef => throw new NotImplementedException();
public XmlType XmlType {
get;

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

@ -157,8 +157,7 @@ namespace Xamarin.Forms.Xaml
Exception xpe = null;
var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
object _;
var collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _) as IEnumerable;
var collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _, out _) as IEnumerable;
if (collection == null)
xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
@ -363,11 +362,10 @@ namespace Xamarin.Forms.Xaml
throw xpe;
}
public static object GetPropertyValue(object xamlElement, XmlName propertyName, HydrationContext context, IXmlLineInfo lineInfo, out object targetProperty)
public static object GetPropertyValue(object xamlElement, XmlName propertyName, HydrationContext context, IXmlLineInfo lineInfo, out Exception xpe, out object targetProperty)
{
var localName = propertyName.LocalName;
Exception xpe = null;
object value;
xpe = null;
targetProperty = null;
//If it's an attached BP, update elementType and propertyName
@ -376,7 +374,7 @@ namespace Xamarin.Forms.Xaml
var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false);
//If it's a BindableProberty, GetValue
if (xpe == null && TryGetValue(xamlElement, property, attached, out value, lineInfo, out xpe, out targetProperty))
if (xpe == null && TryGetValue(xamlElement, property, attached, out var value, lineInfo, out xpe, out targetProperty))
return value;
//If it's a normal property, get it
@ -384,10 +382,6 @@ namespace Xamarin.Forms.Xaml
return value;
xpe = xpe ?? new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
if (context.ExceptionHandler != null)
context.ExceptionHandler(xpe);
else
throw xpe;
return null;
}
@ -638,11 +632,7 @@ namespace Xamarin.Forms.Xaml
static bool TryAddToProperty(object element, XmlName propertyName, object value, string xKey, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
{
exception = null;
object targetProperty;
var collection = GetPropertyValue(element, propertyName, context, lineInfo, out targetProperty) as IEnumerable;
if (collection == null)
if (!(GetPropertyValue(element, propertyName, context, lineInfo, out _, out var targetProperty) is IEnumerable collection))
return false;
if (exception == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, lineInfo, out exception))

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

@ -141,8 +141,8 @@ namespace Xamarin.Forms.Xaml
Values[node] = value;
}
if (value is BindableObject bindableValue && node.Namescope != (parentNode as IElementNode)?.Namescope)
NameScope.SetNameScope(bindableValue, node.Namescope);
if (value is BindableObject bindableValue && node.NameScopeRef != (parentNode as IElementNode)?.NameScopeRef)
NameScope.SetNameScope(bindableValue, node.NameScopeRef.NameScope);
if (XamlLoader.ValueCreatedCallback != null) {
var name = node.XmlType.Name;
@ -157,16 +157,18 @@ namespace Xamarin.Forms.Xaml
var rnode = (XamlLoader.RuntimeRootNode)node;
Values[node] = rnode.Root;
Context.Types[node] = rnode.Root.GetType();
var bindableRoot = rnode.Root as BindableObject;
if (bindableRoot != null)
NameScope.SetNameScope(bindableRoot, node.Namescope);
if (rnode.Root is BindableObject bindable) {
if (NameScope.GetNameScope(bindable) is INameScope existingNs)
node.NameScopeRef.NameScope = existingNs;
else
NameScope.SetNameScope(bindable, node.NameScopeRef?.NameScope);
}
}
public void Visit(ListNode node, INode parentNode)
{
//this is a gross hack to keep ListNode alive. ListNode must go in favor of Properties
XmlName name;
if (ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out name))
if (ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out XmlName name))
node.XmlName = name;
}
@ -181,14 +183,12 @@ namespace Xamarin.Forms.Xaml
ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof (ParameterAttribute))));
if (ctorInfo == null)
return true;
foreach (var parameter in ctorInfo.GetParameters())
{
foreach (var parameter in ctorInfo.GetParameters()) {
var propname =
parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Xamarin.Forms.ParameterAttribute")
.ConstructorArguments.First()
.Value as string;
if (!node.Properties.ContainsKey(new XmlName("", propname)))
{
if (!node.Properties.ContainsKey(new XmlName("", propname))) {
missingArgName = propname;
return false;
}
@ -219,8 +219,7 @@ namespace Xamarin.Forms.Xaml
{
object[] arguments = CreateArgumentsArray(node);
if (!node.Properties.ContainsKey(XmlName.xFactoryMethod))
{
if (!node.Properties.ContainsKey(XmlName.xFactoryMethod)) {
//non-default ctor
try {
return Activator.CreateInstance(nodeType, arguments);
@ -232,7 +231,9 @@ namespace Xamarin.Forms.Xaml
var factoryMethod = ((string)((ValueNode)node.Properties[XmlName.xFactoryMethod]).Value);
Type[] types = arguments == null ? new Type[0] : arguments.Select(a => a.GetType()).ToArray();
Func<MethodInfo, bool> isMatch = m => {
bool isMatch(MethodInfo m)
{
if (m.Name != factoryMethod)
return false;
var p = m.GetParameters();
@ -241,17 +242,18 @@ namespace Xamarin.Forms.Xaml
if (!m.IsStatic)
return false;
for (var i = 0; i < p.Length; i++) {
if ((p [i].ParameterType.IsAssignableFrom(types [i])))
if ((p[i].ParameterType.IsAssignableFrom(types[i])))
continue;
var op_impl = p[i].ParameterType.GetImplicitConversionOperator(fromType: types[i], toType: p[i].ParameterType)
var op_impl = p[i].ParameterType.GetImplicitConversionOperator(fromType: types[i], toType: p[i].ParameterType)
?? types[i].GetImplicitConversionOperator(fromType: types[i], toType: p[i].ParameterType);
if (op_impl == null)
return false;
arguments [i] = op_impl.Invoke(null, new [] { arguments [i]});
arguments[i] = op_impl.Invoke(null, new[] { arguments[i] });
}
return true;
};
}
try {
var mi = nodeType.GetRuntimeMethods().FirstOrDefault(isMatch);
if (mi == null)
@ -268,17 +270,13 @@ namespace Xamarin.Forms.Xaml
if (!enode.Properties.ContainsKey(XmlName.xArguments))
return null;
var node = enode.Properties[XmlName.xArguments];
var elementNode = node as ElementNode;
if (elementNode != null)
{
if (node is ElementNode elementNode) {
var array = new object[1];
array[0] = Values[elementNode];
return array;
}
var listnode = node as ListNode;
if (listnode != null)
{
if (node is ListNode listnode) {
var array = new object[listnode.CollectionItems.Count];
for (var i = 0; i < listnode.CollectionItems.Count; i++)
array[i] = Values[(ElementNode)listnode.CollectionItems[i]];
@ -291,21 +289,15 @@ namespace Xamarin.Forms.Xaml
{
var n = ctorInfo.GetParameters().Length;
var array = new object[n];
for (var i = 0; i < n; i++)
{
for (var i = 0; i < n; i++) {
var parameter = ctorInfo.GetParameters()[i];
var propname =
parameter.CustomAttributes.First(attr => attr.AttributeType == typeof (ParameterAttribute))
.ConstructorArguments.First()
.Value as string;
var name = new XmlName("", propname);
INode node;
if (!enode.Properties.TryGetValue(name, out node))
{
throw new XamlParseException(
String.Format("The Property {0} is required to create a {1} object.", propname, ctorInfo.DeclaringType.FullName),
enode as IXmlLineInfo);
}
if (!enode.Properties.TryGetValue(name, out INode node))
throw new XamlParseException($"The Property {propname} is required to create a {ctorInfo.DeclaringType.FullName} object.", enode as IXmlLineInfo);
if (!enode.SkipProperties.Contains(name))
enode.SkipProperties.Add(name);
var value = Context.Values[node];
@ -319,14 +311,11 @@ namespace Xamarin.Forms.Xaml
return array;
}
static bool IsXaml2009LanguagePrimitive(IElementNode node)
{
return node.NamespaceURI == XamlParser.X2009Uri;
}
static bool IsXaml2009LanguagePrimitive(IElementNode node) => node.NamespaceURI == XamlParser.X2009Uri;
static object CreateLanguagePrimitive(Type nodeType, IElementNode node)
{
object value = null;
object value;
if (nodeType == typeof (string))
value = String.Empty;
else if (nodeType == typeof (Uri))
@ -334,95 +323,43 @@ namespace Xamarin.Forms.Xaml
else
value = Activator.CreateInstance(nodeType);
if (node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode &&
((ValueNode)node.CollectionItems[0]).Value is string)
{
var valuestring = ((ValueNode)node.CollectionItems[0]).Value as string;
if (nodeType == typeof(SByte)) {
sbyte retval;
if (sbyte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Int16)) {
short retval;
if (short.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Int32)) {
int retval;
if (int.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Int64)) {
long retval;
if (long.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Byte)) {
byte retval;
if (byte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(UInt16)) {
ushort retval;
if (ushort.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(UInt32)) {
uint retval;
if (uint.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(UInt64)) {
ulong retval;
if (ulong.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Single)) {
float retval;
if (float.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof(Double)) {
double retval;
if (double.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof (Boolean))
{
bool outbool;
if (bool.TryParse(valuestring, out outbool))
return outbool;
}
if (nodeType == typeof(TimeSpan)) {
TimeSpan retval;
if (TimeSpan.TryParse(valuestring, CultureInfo.InvariantCulture, out retval))
return retval;
}
if (nodeType == typeof (char))
{
char retval;
if (char.TryParse(valuestring, out retval))
return retval;
}
if ( node.CollectionItems.Count == 1
&& node.CollectionItems[0] is ValueNode
&& ((ValueNode)node.CollectionItems[0]).Value is string valuestring) {
if (nodeType == typeof(SByte) && sbyte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var sbyteval))
return sbyteval;
if (nodeType == typeof(Int16) && short.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var int16val))
return int16val;
if (nodeType == typeof(Int32) && int.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var int32val))
return int32val;
if (nodeType == typeof(Int64) && long.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var int64val))
return int64val;
if (nodeType == typeof(Byte) && byte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var byteval))
return byteval;
if (nodeType == typeof(UInt16) && ushort.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var uint16val))
return uint16val;
if (nodeType == typeof(UInt32) && uint.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var uint32val))
return uint32val;
if (nodeType == typeof(UInt64) && ulong.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var uint64val))
return uint64val;
if (nodeType == typeof(Single) && float.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var singleval))
return singleval;
if (nodeType == typeof(Double) && double.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var doubleval))
return doubleval;
if (nodeType == typeof(Boolean) && bool.TryParse(valuestring, out var boolval))
return boolval;
if (nodeType == typeof(TimeSpan) && TimeSpan.TryParse(valuestring, CultureInfo.InvariantCulture, out TimeSpan timespanval))
return timespanval;
if (nodeType == typeof(char) && char.TryParse(valuestring, out var charval))
return charval;
if (nodeType == typeof (string))
return valuestring;
if (nodeType == typeof (decimal))
{
decimal retval;
if (decimal.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
return retval;
}
else if (nodeType == typeof (Uri))
{
Uri retval;
if (Uri.TryCreate(valuestring, UriKind.RelativeOrAbsolute, out retval))
return retval;
}
if (nodeType == typeof(decimal) && decimal.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out var decimalval))
return decimalval;
if (nodeType == typeof(Uri) && Uri.TryCreate(valuestring, UriKind.RelativeOrAbsolute, out Uri urival))
return urival;
}
return value;
}
}
}
}

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

@ -5,12 +5,11 @@ namespace Xamarin.Forms.Xaml
{
class NamescopingVisitor : IXamlNodeVisitor
{
readonly Dictionary<INode, INameScope> _scopes = new Dictionary<INode, INameScope>();
readonly Dictionary<INode, NameScopeRef> _scopes = new Dictionary<INode, NameScopeRef>();
public NamescopingVisitor(HydrationContext context)
=> Values = context.Values;
Dictionary<INode, object> Values { get; set; }
{
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => false;
@ -19,37 +18,29 @@ namespace Xamarin.Forms.Xaml
public bool SkipChildren(INode node, INode parentNode) => false;
public bool IsResourceDictionary(ElementNode node) => false;
public void Visit(ValueNode node, INode parentNode)
=> _scopes[node] = _scopes[parentNode];
public void Visit(MarkupNode node, INode parentNode)
=> _scopes[node] = _scopes[parentNode];
public void Visit(ValueNode node, INode parentNode) => _scopes[node] = _scopes[parentNode];
public void Visit(MarkupNode node, INode parentNode) => _scopes[node] = _scopes[parentNode];
public void Visit(ElementNode node, INode parentNode)
=> _scopes[node] = node.Namescope = (parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode) || IsVisualStateGroupList(node))
? new NameScope()
=> _scopes[node] = node.NameScopeRef = (parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode) || IsVisualStateGroupList(node))
? new NameScopeRef { NameScope = new NameScope() }
: _scopes[parentNode];
public void Visit(RootNode node, INode parentNode)
=> _scopes[node] = node.Namescope = new NameScope();
public void Visit(RootNode node, INode parentNode) => _scopes[node] = node.NameScopeRef = new NameScopeRef { NameScope = new NameScope() };
public void Visit(ListNode node, INode parentNode) =>
_scopes[node] = _scopes[parentNode];
static bool IsDataTemplate(INode node, INode parentNode)
{
var parentElement = parentNode as IElementNode;
if ( parentElement != null
&& parentElement.Properties.TryGetValue(XmlName._CreateContent, out var createContent)
&& createContent == node)
if ( parentNode is IElementNode parentElement
&& parentElement.Properties.TryGetValue(XmlName._CreateContent, out var createContent)
&& createContent == node)
return true;
return false;
}
static bool IsStyle(INode node, INode parentNode)
=> (parentNode as ElementNode)?.XmlType.Name == "Style";
static bool IsVisualStateGroupList(ElementNode node)
=> node?.XmlType.Name == "VisualStateGroup" && node?.Parent is IListNode;
static bool IsStyle(INode node, INode parentNode) => (parentNode as ElementNode)?.XmlType.Name == "Style";
static bool IsVisualStateGroupList(ElementNode node) => node?.XmlType.Name == "VisualStateGroup" && node?.Parent is IListNode;
}
}

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

@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Xml;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml.Internals;
namespace Xamarin.Forms.Xaml
{
@ -32,7 +27,7 @@ namespace Xamarin.Forms.Xaml
return;
try {
((IElementNode)parentNode).Namescope.RegisterName((string)node.Value, Values[parentNode]);
((IElementNode)parentNode).NameScopeRef.NameScope.RegisterName((string)node.Value, Values[parentNode]);
}
catch (ArgumentException ae) {
if (ae.ParamName != "name")
@ -73,12 +68,6 @@ namespace Xamarin.Forms.Xaml
}
static bool IsXNameProperty(ValueNode node, INode parentNode)
{
var parentElement = parentNode as IElementNode;
INode xNameNode;
if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
return true;
return false;
}
=> parentNode is IElementNode parentElement && parentElement.Properties.TryGetValue(XmlName.xName, out INode xNameNode) && xNameNode == node;
}
}

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

@ -24,7 +24,7 @@ namespace Xamarin.Forms.Xaml
{
Dictionary<XmlName, INode> Properties { get; }
List<XmlName> SkipProperties { get; }
INameScope Namescope { get; }
NameScopeRef NameScopeRef { get; }
XmlType XmlType { get; }
string NamespaceURI { get; }
}
@ -34,6 +34,11 @@ namespace Xamarin.Forms.Xaml
List<INode> CollectionItems { get; }
}
class NameScopeRef
{
public INameScope NameScope { get; set; }
}
[DebuggerDisplay("{NamespaceUri}:{Name}")]
class XmlType
{
@ -112,6 +117,7 @@ namespace Xamarin.Forms.Xaml
};
}
[DebuggerDisplay("{XmlType.Name}")]
class ElementNode : BaseNode, IValueNode, IElementNode
{
@ -131,7 +137,7 @@ namespace Xamarin.Forms.Xaml
public List<INode> CollectionItems { get; }
public XmlType XmlType { get; }
public string NamespaceURI { get; }
public INameScope Namescope { get; set; }
public NameScopeRef NameScopeRef { get; set; }
public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
{
@ -152,10 +158,8 @@ namespace Xamarin.Forms.Xaml
bool IsDataTemplate(INode parentNode)
{
var parentElement = parentNode as IElementNode;
INode createContent;
if (parentElement != null &&
parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
if (parentNode is IElementNode parentElement &&
parentElement.Properties.TryGetValue(XmlName._CreateContent, out INode createContent) &&
createContent == this)
return true;
return false;

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

@ -74,16 +74,9 @@ namespace Xamarin.Forms.Xaml.Internals
set { services[typeof (IValueConverterProvider)] = value; }
}
public object GetService(Type serviceType)
{
object service;
return services.TryGetValue(serviceType, out service) ? service : null;
}
public object GetService(Type serviceType) => services.TryGetValue(serviceType, out var service) ? service : null;
public void Add(Type type, object service)
{
services.Add(type, service);
}
public void Add(Type type, object service) => services.Add(type, service);
}
class XamlValueTargetProvider : IProvideParentValues, IProvideValueTarget
@ -104,21 +97,16 @@ namespace Xamarin.Forms.Xaml.Internals
IEnumerable<object> IProvideParentValues.ParentObjects
{
get
{
get {
if (Node == null || Context == null)
yield break;
var n = Node;
object obj = null;
var context = Context;
while (n.Parent != null && context != null)
{
if (n.Parent is IElementNode)
{
if (context.Values.TryGetValue(n.Parent, out obj))
while (n.Parent != null && context != null) {
if (n.Parent is IElementNode) {
if (context.Values.TryGetValue(n.Parent, out var obj))
yield return obj;
else
{
else {
context = context.ParentContext;
continue;
}
@ -159,14 +147,9 @@ namespace Xamarin.Forms.Xaml.Internals
this.scope = scope;
}
IEnumerable<object> IProvideParentValues.ParentObjects
=> objectAndParents;
object IProvideValueTarget.TargetObject
=> objectAndParents[0];
object IProvideValueTarget.TargetProperty
=> targetProperty;
IEnumerable<object> IProvideParentValues.ParentObjects => objectAndParents;
object IProvideValueTarget.TargetObject => objectAndParents[0];
object IProvideValueTarget.TargetProperty => targetProperty;
public object FindByName(string name)
{
@ -277,15 +260,14 @@ namespace Xamarin.Forms.Xaml.Internals
class ReferenceProvider : IReferenceProvider
{
readonly INode _node;
internal ReferenceProvider(INode node)
=> _node = node;
internal ReferenceProvider(INode node) => _node = node;
public object FindByName(string name)
{
var n = _node;
object value = null;
while (n != null) {
if ((value = (n as IElementNode)?.Namescope?.FindByName(name)) != null)
object value;
if ((value = (n as IElementNode)?.NameScopeRef.NameScope?.FindByName(name)) != null)
return value;
n = n.Parent;
}
@ -304,27 +286,16 @@ namespace Xamarin.Forms.Xaml.Internals
{
readonly Dictionary<string, string> namespaces = new Dictionary<string, string>();
public IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope)
{
throw new NotImplementedException();
}
public IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope) => throw new NotImplementedException();
public string LookupNamespace(string prefix)
{
string result;
if (namespaces.TryGetValue(prefix, out result))
if (namespaces.TryGetValue(prefix, out var result))
return result;
return null;
}
public string LookupPrefix(string namespaceName)
{
throw new NotImplementedException();
}
public void Add(string prefix, string ns)
{
namespaces.Add(prefix, ns);
}
public string LookupPrefix(string namespaceName) => throw new NotImplementedException();
public void Add(string prefix, string ns) => namespaces.Add(prefix, ns);
}
}