Reverts "[Xaml] require escaping curly braces (#4723)" and "[X] only require escaping if starts with '{' (#5169)" (#5424)

* Revert "[X] only require escaping if starts with '{' (#5169)"

This reverts commit cd73391c3a.

* Revert "[Xaml] require escaping curly braces (#4723)"

This reverts commit 6753ace40e.

* Make sure parsing doesn't fail when there *are* curly braces now
This commit is contained in:
Samantha Houts 2019-03-01 09:59:21 -08:00 коммит произвёл GitHub
Родитель a101758f71
Коммит d8f0c308a7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 70 добавлений и 106 удалений

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

@ -20,7 +20,7 @@
<StackLayout>
<Label FontAttributes="Bold" FontSize="18" Margin="10,25,10,10"
HorizontalOptions="Fill" HorizontalTextAlignment="Center"
Text="{Binding Filter, StringFormat='{}Your filter term of {0} did not match any records'}"></Label>
Text="{Binding Filter, StringFormat='Your filter term of {0} did not match any records'}"></Label>
</StackLayout>
</DataTemplate>
</CollectionView.EmptyViewTemplate>

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

@ -1,10 +0,0 @@
<?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.Gh2756">
<StackLayout>
<Label Text="{Binding Color.R, StringFormat='R = {0:F2}'}"/> <!-- should parse -->
<Label Text="{Binding Path=StartTime, StringFormat='{0:yy-MM-dd}'}"/> <!-- should throw -->
</StackLayout>
</ContentPage>

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

@ -1,34 +0,0 @@
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
using Xamarin.Forms;
namespace Xamarin.Forms.Xaml.UnitTests
{
[XamlCompilation(XamlCompilationOptions.Skip)]
public partial class Gh2756 : ContentPage
{
public Gh2756() => InitializeComponent();
public Gh2756(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
class Tests
{
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
[TearDown] public void TearDown() => Device.PlatformServices = null;
[Test]
public void UnescapedBraces([Values(false, true)]bool useCompiledXaml)
{
if (useCompiledXaml)
Assert.Throws(new XamlParseExceptionConstraint(8, 16), () => MockCompiler.Compile(typeof(Gh2756)));
else
Assert.Throws(new XamlParseExceptionConstraint(8, 16), () => new Gh2756(useCompiledXaml));
}
}
}
}

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

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?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.Issue1438">

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

@ -82,7 +82,7 @@ xmlns=""http://xamarin.com/schemas/2014/forms""
<local:SeverityColorConverter x:Key=""SeverityColorConverter"" />
</ResourceDictionary>
</ContentPage.Resources>
<Label Text=""{Binding value, StringFormat='{}{0}'}""
<Label Text=""{Binding value, StringFormat='{0}'}""
WidthRequest=""50""
TextColor=""Black""
x:Name=""label""
@ -97,6 +97,35 @@ xmlns=""http://xamarin.com/schemas/2014/forms""
Assert.AreEqual (1, SeverityColorConverter.count);
}
[Test]
public void ConverterIsInvoked_Escaped()
{
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"">
<ContentPage.Resources>
<ResourceDictionary>
<local:SeverityColorConverter x:Key=""SeverityColorConverter"" />
</ResourceDictionary>
</ContentPage.Resources>
<Label Text=""{Binding value, StringFormat='{}{0}'}""
WidthRequest=""50""
TextColor=""Black""
x:Name=""label""
BackgroundColor=""{Binding Severity, Converter={StaticResource SeverityColorConverter}}""
XAlign=""Center"" YAlign=""Center""/>
</ContentPage>";
var layout = new ContentPage().LoadFromXaml(xaml);
layout.BindingContext = new { Value = "Foo", Severity = "Bar" };
var label = layout.FindByName<Label>("label");
Assert.AreEqual(Color.Blue, label.BackgroundColor);
Assert.AreEqual(1, SeverityColorConverter.count);
}
[Test]
public void ResourcesInNonXFBaseClassesAreFound ()
{

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

@ -248,25 +248,17 @@ namespace Xamarin.Forms.Xaml.UnitTests
}
[Test]
public void NonStartingBracesDoNotNeedToBeEscaped()
public void BindingStringFormatWithoutEscaping ()
{
var bindingString = "{Binding Foo, StringFormat='Hello {0}'}";
var bindingString = "{Binding Foo, StringFormat='{0,20}'}";
Assert.DoesNotThrow(() => new MarkupExtensionParser().ParseExpression(ref bindingString, new Internals.XamlServiceProvider(null, null)
{
var binding = (new MarkupExtensionParser ()).ParseExpression (ref bindingString, new Internals.XamlServiceProvider (null, null) {
IXamlTypeResolver = typeResolver,
}));
}
});
[Test]
public void BracesNeedsToBeEscaped2()
{
var bindingString = "{Binding Foo, StringFormat='{0}'}";
Assert.Throws<XamlParseException>(() => new MarkupExtensionParser().ParseExpression(ref bindingString, new Internals.XamlServiceProvider(null, null)
{
IXamlTypeResolver = typeResolver,
}));
Assert.That (binding, Is.InstanceOf<Binding> ());
Assert.AreEqual ("Foo", ((Binding)binding).Path);
Assert.AreEqual ("{0,20}", ((Binding)binding).StringFormat);
}
[Test]

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

@ -46,10 +46,7 @@ namespace Xamarin.Forms.Xaml
return expression.Substring(2);
if (expression[expression.Length - 1] != '}')
{
var lineInfo = (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider != null) ? (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider).XmlLineInfo : new XmlLineInfo();
throw new XamlParseException("Expression must end with '}'", lineInfo);
}
throw new Exception("Expression must end with '}'");
int len;
string match;
@ -117,6 +114,7 @@ namespace Xamarin.Forms.Xaml
protected void HandleProperty(string prop, IServiceProvider serviceProvider, ref string remaining, bool isImplicit)
{
char next;
object value = null;
string str_value;
@ -139,13 +137,7 @@ namespace Xamarin.Forms.Xaml
str_value = value as string;
}
else
str_value = GetNextPiece(ref remaining, out var next);
if (str_value != null && !str_value.StartsWith("{}", StringComparison.Ordinal) && str_value.Length > 2 && str_value.StartsWith("{", StringComparison.Ordinal))
{
var lineInfo = (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider != null) ? (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider).XmlLineInfo : new XmlLineInfo();
throw new XamlParseException("Strings starting with `{` needs to be escaped. Start the string with `{}`", lineInfo);
}
str_value = GetNextPiece(ref remaining, out next);
SetPropertyValue(prop, str_value, value, serviceProvider);
}

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

@ -5,31 +5,27 @@ namespace Xamarin.Forms.Xaml
{
internal sealed class MarkupExtensionParser : MarkupExpressionParser, IExpressionParser<object>
{
IMarkupExtension _markupExtension;
IMarkupExtension markupExtension;
public object Parse(string match, ref string remaining, IServiceProvider serviceProvider)
{
var typeResolver = serviceProvider.GetService(typeof (IXamlTypeResolver)) as IXamlTypeResolver;
switch (match) {
case "Binding":
_markupExtension = new BindingExtension();
break;
case "TemplateBinding":
_markupExtension = new TemplateBindingExtension();
break;
case "StaticResource":
_markupExtension = new StaticResourceExtension();
break;
case "OnPlatform":
_markupExtension = new OnPlatformExtension();
break;
case "OnIdiom":
_markupExtension = new OnIdiomExtension();
break;
case "DataTemplate":
_markupExtension = new DataTemplateExtension();
break;
default:
//shortcut for Binding and StaticResource, to avoid too many reflection calls.
if (match == "Binding")
markupExtension = new BindingExtension();
else if (match == "TemplateBinding")
markupExtension = new TemplateBindingExtension();
else if (match == "StaticResource")
markupExtension = new StaticResourceExtension();
else if (match == "OnPlatform")
markupExtension = new OnPlatformExtension();
else if (match == "OnIdiom")
markupExtension = new OnIdiomExtension();
else if (match == "DataTemplate")
markupExtension = new DataTemplateExtension();
else
{
if (typeResolver == null)
return null;
Type type;
@ -37,21 +33,20 @@ namespace Xamarin.Forms.Xaml
//The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
if (!typeResolver.TryResolve(match + "Extension", out type) && !typeResolver.TryResolve(match, out type))
throw new XamlParseException($"MarkupExtension not found for {match}", serviceProvider);
_markupExtension = Activator.CreateInstance(type) as IMarkupExtension;
break;
markupExtension = Activator.CreateInstance(type) as IMarkupExtension;
}
if (_markupExtension == null)
if (markupExtension == null)
throw new XamlParseException($"Missing public default constructor for MarkupExtension {match}", serviceProvider);
if (remaining == "}")
return _markupExtension.ProvideValue(serviceProvider);
return markupExtension.ProvideValue(serviceProvider);
string piece;
while ((piece = GetNextPiece(ref remaining, out char next)) != null)
HandleProperty(piece, serviceProvider, ref remaining, next != '=');
return _markupExtension.ProvideValue(serviceProvider);
return markupExtension.ProvideValue(serviceProvider);
}
protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
@ -59,7 +54,7 @@ namespace Xamarin.Forms.Xaml
MethodInfo setter;
if (prop == null) {
//implicit property
var t = _markupExtension.GetType();
var t = markupExtension.GetType();
prop = ApplyPropertiesVisitor.GetContentPropertyName(t.GetTypeInfo());
if (prop == null)
return;
@ -72,26 +67,26 @@ namespace Xamarin.Forms.Xaml
}
else {
try {
setter = _markupExtension.GetType().GetRuntimeProperty(prop).SetMethod;
setter = markupExtension.GetType().GetRuntimeProperty(prop).SetMethod;
}
catch (AmbiguousMatchException e) {
throw new XamlParseException($"Multiple properties with name '{_markupExtension.GetType()}.{prop}' found.", serviceProvider, innerException: e);
throw new XamlParseException($"Multiple properties with name '{markupExtension.GetType()}.{prop}' found.", serviceProvider, innerException: e);
}
}
if (value == null && strValue != null) {
try {
value = strValue.ConvertTo(_markupExtension.GetType().GetRuntimeProperty(prop).PropertyType,
value = strValue.ConvertTo(markupExtension.GetType().GetRuntimeProperty(prop).PropertyType,
(Func<TypeConverter>)null, serviceProvider, out Exception converterException);
if (converterException != null)
throw converterException;
}
catch (AmbiguousMatchException e) {
throw new XamlParseException($"Multiple properties with name '{_markupExtension.GetType()}.{prop}' found.", serviceProvider, innerException: e);
throw new XamlParseException($"Multiple properties with name '{markupExtension.GetType()}.{prop}' found.", serviceProvider, innerException: e);
}
}
setter.Invoke(_markupExtension, new[] { value });
setter.Invoke(markupExtension, new[] { value });
}
}
}
}