* [*] Support for CSS StyleSheets

 Parsing, loading, and applying of StyleSheets

 see https://github.com/xamarin/Xamarin.Forms/pull/1207#issue-266464280
 for complete description.

* use initial, not none

* fix tests
This commit is contained in:
Stephane Delcroix 2017-12-20 10:47:50 +01:00 коммит произвёл GitHub
Родитель 2eba087a75
Коммит 5ea86a266b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
88 изменённых файлов: 2619 добавлений и 126 удалений

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

@ -1,7 +1,10 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition="'$(EnableDefaultItems)'=='True' And '$(EnableDefaultXamlItems)'=='True' And '$(EnableDefaultEmbeddedResourceItems)'=='True'">
<EmbeddedResource Include="**\*.xaml" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
</ItemGroup>
<ItemGroup Condition="'$(EnableDefaultItems)'=='True' And '$(EnableDefaultXamlItems)'=='True' And '$(EnableDefaultEmbeddedResourceItems)'=='True'">
<EmbeddedResource Include="**\*.xaml" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
</ItemGroup>
</Project>
<ItemGroup Condition="'$(EnableDefaultItems)'=='True' And '$(EnableDefaultCssItems)'=='True' And '$(EnableDefaultEmbeddedResourceItems)'=='True'">
<EmbeddedResource Include="**\*.css" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
</Project>

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

@ -11,5 +11,8 @@
<Compile Update="**\*.xaml$(DefaultLanguageSourceExtension)" DependentUpon="%(Filename)" SubType="Code" />
<None Remove="**\*.xaml" Condition="'$(EnableDefaultNoneItems)'=='True'" />
</ItemGroup>
<ItemGroup Condition="'$(EnableDefaultItems)'=='True' And '$(EnableDefaultCssItems)'=='True' And '$(EnableDefaultEmbeddedResourceItems)'=='True'">
<None Remove="**\*.xaml" Condition="'$(EnableDefaultNoneItems)'=='True'" />
</ItemGroup>
</Project>

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

@ -1,12 +1,15 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.XamlGTask" AssemblyFile="$(MSBuildThisFileDirectory)Xamarin.Forms.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.CssGTask" AssemblyFile="$(MSBuildThisFileDirectory)Xamarin.Forms.Build.Tasks.dll"/>
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.XamlCTask" AssemblyFile="$(MSBuildThisFileDirectory)Xamarin.Forms.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Forms.Build.Tasks.GetTasksAbi" AssemblyFile="$(MSBuildThisFileDirectory)Xamarin.Forms.Build.Tasks.dll" />
<PropertyGroup>
<EnableDefaultXamlItems Condition="'$(EnableDefaultXamlItems)'==''">True</EnableDefaultXamlItems>
<_DefaultXamlItemsEnabled>False</_DefaultXamlItemsEnabled>
<EnableDefaultCssItems Condition="'$(EnableDefaultCssItems)'==''">True</EnableDefaultCssItems>
<_DefaultCssItemsEnabled>False</_DefaultCssItemsEnabled>
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)Xamarin.Forms.DefaultItems.targets" Condition="'$(MSBuildSDKsPath)'!=''" />
@ -34,7 +37,7 @@
</GetTasksAbi >
<PropertyGroup>
<_XFTasksExpectedAbi>3</_XFTasksExpectedAbi>
<_XFTasksExpectedAbi>4</_XFTasksExpectedAbi>
</PropertyGroup>
<Error
@ -96,4 +99,25 @@
DebugType = "$(DebugType)"
KeepXamlResources = "$(XFKeepXamlResources)" />
</Target>
<!-- CssG -->
<PropertyGroup>
<CoreCompileDependsOn>
CssG;
$(CoreCompileDependsOn);
</CoreCompileDependsOn>
</PropertyGroup>
<Target Name="CssG" BeforeTargets="BeforeCompile" Condition="'$(_CssGAlreadyExecuted)'!='true'">
<PropertyGroup>
<_CssGAlreadyExecuted>true</_CssGAlreadyExecuted>
</PropertyGroup>
<CssGTask
XamlFiles="@(EmbeddedResource)" Condition="'%(Extension)' == '.css' AND '$(DefaultLanguageSourceExtension)' == '.cs'"
Language = "$(Language)"
AssemblyName = "$(AssemblyName)"
OutputPath = "$(IntermediateOutputPath)">
<Output ItemName="FilesWrite" TaskParameter="GeneratedCodeFiles" />
<Output ItemName="Compile" TaskParameter="GeneratedCodeFiles" />
</CssGTask>
</Target>
</Project>

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

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@ -66,5 +65,17 @@ namespace Xamarin.Forms.Core.XamlC
//ldloc the stored uri as return value
yield return Create(Ldloc, uriVarDef);
}
internal static string GetPathForType(ModuleDefinition module, TypeReference type)
{
foreach (var ca in type.Module.GetCustomAttributes()) {
if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference(typeof(XamlResourceIdAttribute))))
continue;
if (!TypeRefComparer.Default.Equals(ca.ConstructorArguments[2].Value as TypeReference, type))
continue;
return ca.ConstructorArguments[1].Value as string;
}
return null;
}
}
}
}

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

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Xamarin.Forms.Build.Tasks;
using Xamarin.Forms.Xaml;
using static Mono.Cecil.Cil.Instruction;
using static Mono.Cecil.Cil.OpCodes;
namespace Xamarin.Forms.Core.XamlC
{
class StyleSheetProvider : ICompiledValueProvider
{
public IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context)
{
INode sourceNode = null;
((IElementNode)node).Properties.TryGetValue(new XmlName("", "Source"), out sourceNode);
if (sourceNode == null)
((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Source"), out sourceNode);
INode styleNode = null;
if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Style"), out styleNode) &&
!((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Style"), out styleNode) &&
((IElementNode)node).CollectionItems.Count == 1)
styleNode = ((IElementNode)node).CollectionItems[0];
if (sourceNode != null && styleNode != null)
throw new XamlParseException($"StyleSheet can not have both a Source and a content", node);
if (sourceNode == null && styleNode == null)
throw new XamlParseException($"StyleSheet require either a Source or a content", node);
if (styleNode != null && !(styleNode is ValueNode))
throw new XamlParseException($"Style property or Content is not a string literal", node);
if (sourceNode != null && !(sourceNode is ValueNode))
throw new XamlParseException($"Source property is not a string literal", node);
if (styleNode != null) {
var style = (styleNode as ValueNode).Value as string;
yield return Create(Ldstr, style);
var fromString = module.ImportReference(typeof(StyleSheets.StyleSheet).GetMethods().FirstOrDefault(mi => mi.Name == nameof(StyleSheets.StyleSheet.FromString) && mi.GetParameters().Length == 1));
yield return Create(Call, module.ImportReference(fromString));
}
else {
string source = (sourceNode as ValueNode)?.Value as string;
INode rootNode = node;
while (!(rootNode is ILRootNode))
rootNode = rootNode.Parent;
var rootTargetPath = RDSourceTypeConverter.GetPathForType(module, ((ILRootNode)rootNode).TypeReference);
var uri = new Uri(source, UriKind.Relative);
var resourcePath = ResourceDictionary.RDSourceTypeConverter.GetResourcePath(uri, rootTargetPath);
//fail early
var resourceId = XamlCTask.GetResourceIdForPath(module, resourcePath);
if (resourceId == null)
throw new XamlParseException($"Resource '{source}' not found.", node);
var getTypeFromHandle = module.ImportReference(typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle), new[] { typeof(RuntimeTypeHandle) }));
var getAssembly = module.ImportReference(typeof(Type).GetProperty(nameof(Type.Assembly)).GetGetMethod());
yield return Create(Ldtoken, module.ImportReference(((ILRootNode)rootNode).TypeReference));
yield return Create(Call, module.ImportReference(getTypeFromHandle));
yield return Create(Callvirt, module.ImportReference(getAssembly)); //assembly
yield return Create(Ldstr, resourceId); //resourceId
foreach (var instruction in node.PushXmlLineInfo(context))
yield return instruction; //lineinfo
var fromAssemblyResource = module.ImportReference(typeof(StyleSheets.StyleSheet).GetMethods().FirstOrDefault(mi => mi.Name == nameof(StyleSheets.StyleSheet.FromAssemblyResource) && mi.GetParameters().Length == 3));
yield return Create(Call, module.ImportReference(fromAssemblyResource));
}
//the variable is of type `object`. fix that
var vardef = new VariableDefinition(module.ImportReference(typeof(StyleSheets.StyleSheet)));
yield return Create(Stloc, vardef);
vardefref.VariableDefinition = vardef;
}
}
}

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

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Xamarin.Forms.Build.Tasks
{
public class CssGTask : Task
{
readonly List<ITaskItem> _generatedCodeFiles = new List<ITaskItem>();
[Required]
public ITaskItem[] XamlFiles { get; set; }
[Output]
public ITaskItem[] GeneratedCodeFiles => _generatedCodeFiles.ToArray();
public string Language { get; set; }
public string AssemblyName { get; set; }
public string OutputPath { get; set; }
public override bool Execute()
{
bool success = true;
if (XamlFiles == null) {
Log.LogMessage("Skipping CssG");
return true;
}
foreach (var xamlFile in XamlFiles) {
var outputFile = Path.Combine(OutputPath, $"{xamlFile.GetMetadata("TargetPath")}.g.cs");
var generator = new CssGenerator(xamlFile, Language, AssemblyName, outputFile, Log);
try {
if (generator.Execute())
_generatedCodeFiles.Add(new TaskItem(Microsoft.Build.Evaluation.ProjectCollection.Escape(outputFile)));
}
catch (XmlException xe) {
Log.LogError(null, null, null, xamlFile.ItemSpec, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
success = false;
}
catch (Exception e) {
Log.LogError(null, null, null, xamlFile.ItemSpec, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
success = false;
}
}
return success;
}
}
}

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

@ -0,0 +1,97 @@
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.CSharp;
using Xamarin.Forms.Xaml;
namespace Xamarin.Forms.Build.Tasks
{
class CssGenerator
{
internal CssGenerator()
{
}
public CssGenerator(
ITaskItem taskItem,
string language,
string assemblyName,
string outputFile,
TaskLoggingHelper logger)
: this(
taskItem.ItemSpec,
language,
taskItem.GetMetadata("ManifestResourceName"),
taskItem.GetMetadata("TargetPath"),
assemblyName,
outputFile,
logger)
{
}
internal static CodeDomProvider Provider = new CSharpCodeProvider();
public string CssFile { get; }
public string Language { get; }
public string ResourceId { get; }
public string TargetPath { get; }
public string AssemblyName { get; }
public string OutputFile { get; }
public TaskLoggingHelper Logger { get; }
public CssGenerator(
string cssFile,
string language,
string resourceId,
string targetPath,
string assemblyName,
string outputFile,
TaskLoggingHelper logger = null)
{
CssFile = cssFile;
Language = language;
ResourceId = resourceId;
TargetPath = targetPath;
AssemblyName = assemblyName;
OutputFile = outputFile;
Logger = logger;
}
//returns true if a file is generated
public bool Execute()
{
Logger?.LogMessage("Source: {0}", CssFile);
Logger?.LogMessage(" Language: {0}", Language);
Logger?.LogMessage(" ResourceID: {0}", ResourceId);
Logger?.LogMessage(" TargetPath: {0}", TargetPath);
Logger?.LogMessage(" AssemblyName: {0}", AssemblyName);
Logger?.LogMessage(" OutputFile {0}", OutputFile);
GenerateCode();
return true;
}
void GenerateCode()
{
//Create the target directory if required
Directory.CreateDirectory(Path.GetDirectoryName(OutputFile));
var ccu = new CodeCompileUnit();
ccu.AssemblyCustomAttributes.Add(
new CodeAttributeDeclaration(new CodeTypeReference($"global::{typeof(XamlResourceIdAttribute).FullName}"),
new CodeAttributeArgument(new CodePrimitiveExpression(ResourceId)),
new CodeAttributeArgument(new CodePrimitiveExpression(TargetPath.Replace('\\', '/'))),
new CodeAttributeArgument(new CodePrimitiveExpression(null))
));
//write the result
using (var writer = new StreamWriter(OutputFile))
Provider.GenerateCodeFromCompileUnit(ccu, writer, new CodeGeneratorOptions());
}
}
}

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

@ -6,7 +6,7 @@ namespace Xamarin.Forms.Build.Tasks
public class GetTasksAbi : Task
{
[Output]
public string AbiVersion { get; } = "3";
public string AbiVersion { get; } = "4";
public override bool Execute()
=> true;

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

@ -24,8 +24,10 @@ namespace Xamarin.Forms.Build.Tasks
public void Visit(ValueNode node, INode parentNode)
{
Context.Scopes[node] = Context.Scopes[parentNode];
if (IsXNameProperty(node, parentNode))
RegisterName((string)node.Value, Context.Scopes[node].Item1, Context.Scopes[node].Item2, Context.Variables[(IElementNode)parentNode], node);
if (!IsXNameProperty(node, parentNode))
return;
RegisterName((string)node.Value, Context.Scopes[node].Item1, Context.Scopes[node].Item2, Context.Variables[(IElementNode)parentNode], node);
SetStyleId((string)node.Value, Context.Variables[(IElementNode)parentNode]);
}
public void Visit(MarkupNode node, INode parentNode)
@ -123,7 +125,7 @@ namespace Xamarin.Forms.Build.Tasks
var module = Context.Body.Method.Module;
var nsRef = module.ImportReference(typeof (INameScope));
var nsDef = nsRef.Resolve();
var registerInfo = nsDef.Methods.First(md => md.Name == "RegisterName" && md.Parameters.Count == 2);
var registerInfo = nsDef.Methods.First(md => md.Name == nameof(INameScope.RegisterName) && md.Parameters.Count == 2);
var register = module.ImportReference(registerInfo);
Context.IL.Emit(OpCodes.Ldloc, namescopeVarDef);
@ -131,5 +133,26 @@ namespace Xamarin.Forms.Build.Tasks
Context.IL.Emit(OpCodes.Ldloc, element);
Context.IL.Emit(OpCodes.Callvirt, register);
}
void SetStyleId(string str, VariableDefinition element)
{
if (!element.VariableType.InheritsFromOrImplements(Context.Body.Method.Module.ImportReference(typeof(Element))))
return;
var module = Context.Body.Method.Module;
var eltDef = module.ImportReference(typeof(Element)).Resolve();
var styleIdInfo = eltDef.Properties.First(pd => pd.Name == nameof(Element.StyleId));
var getStyleId = module.ImportReference(styleIdInfo.GetMethod);
var setStyleId = module.ImportReference(styleIdInfo.SetMethod);
var nop = Instruction.Create(OpCodes.Nop);
Context.IL.Emit(OpCodes.Ldloc, element);
Context.IL.Emit(OpCodes.Callvirt, getStyleId);
Context.IL.Emit(OpCodes.Brtrue, nop);
Context.IL.Emit(OpCodes.Ldloc, element);
Context.IL.Emit(OpCodes.Ldstr, str);
Context.IL.Emit(OpCodes.Callvirt, setStyleId);
Context.IL.Append(nop);
}
}
}

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

@ -1144,16 +1144,20 @@ namespace Xamarin.Forms.Build.Tasks
static bool CanAddToResourceDictionary(TypeReference collectionType, IElementNode node, IXmlLineInfo lineInfo, ILContext context)
{
if ( collectionType.FullName != "Xamarin.Forms.ResourceDictionary"
&& collectionType.Resolve().BaseType?.FullName != "Xamarin.Forms.ResourceDictionary")
&& collectionType.Resolve().BaseType?.FullName != "Xamarin.Forms.ResourceDictionary")
return false;
if (node.Properties.ContainsKey(XmlName.xKey))
return true;
if (node.XmlType.Name == "Style")
return true;
if (node.XmlType.Name == "ResourceDictionary")
//is there a RD.Add() overrides that accepts this ?
var nodeTypeRef = context.Variables[node].VariableType;
var module = context.Body.Method.Module;
if (module.ImportReference(typeof(ResourceDictionary)).Resolve().Methods.Any(md =>
md.Name == "Add"
&& md.Parameters.Count == 1
&& TypeRefComparer.Default.Equals(md.Parameters[0].ParameterType, nodeTypeRef)))
return true;
throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
@ -1212,7 +1216,7 @@ namespace Xamarin.Forms.Build.Tasks
yield break;
}
var nodeTypeRef = node.XmlType.GetTypeReference(module, lineInfo);
var nodeTypeRef = context.Variables[node].VariableType;
yield return Create(Ldloc, context.Variables[node]);
yield return Create(Callvirt,
module.ImportReference(

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

@ -28,4 +28,4 @@
<Copy SourceFiles="@(_CopyItems)" DestinationFolder="..\.nuspec\" ContinueOnError="true" Retries="0" />
</Target>
</Project>
</Project>

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

@ -17,7 +17,7 @@ namespace Xamarin.Forms.Controls.Issues
{
Title = "Issue 181";
Content = new Frame {
OutlineColor = Color.Red,
BorderColor = Color.Red,
BackgroundColor = new Color (1.0, 1.0, 0.0),
Content = new Label {
Text = "I should have red text",

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

@ -23,7 +23,7 @@ namespace Xamarin.Forms.Controls
{
var bvBackground = new Frame {
Content = new Label { Text = "" },
OutlineColor = Color.FromRgb (0x06, 0x68, 0xCF),
BorderColor = Color.FromRgb (0x06, 0x68, 0xCF),
BackgroundColor = Color.FromRgba (0f, 0f, 0f, 0.4f),
HasShadow = true
};

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

@ -17,7 +17,7 @@ namespace Xamarin.Forms.Controls
{
Frame frPatientInfo = new Frame
{
OutlineColor = Color.Black,
BorderColor = Color.Black,
BackgroundColor = Color.White,
HasShadow = true,
HorizontalOptions = LayoutOptions.Center,

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

@ -14,7 +14,7 @@ namespace Xamarin.Forms.Controls
{
element.HeightRequest = 50;
element.WidthRequest = 100;
element.OutlineColor = Color.Olive;
element.BorderColor = Color.Olive;
}
protected override void Build (StackLayout stackLayout)
@ -22,9 +22,9 @@ namespace Xamarin.Forms.Controls
base.Build (stackLayout);
var hasShadowContainer = new StateViewContainer<Frame> (Test.Frame.HasShadow, new Frame { HasShadow = true });
var outlineColorContainer = new StateViewContainer<Frame> (Test.Frame.OutlineColor, new Frame { OutlineColor = Color.Teal, });
var outlineColorContainer = new StateViewContainer<Frame> (Test.Frame.OutlineColor, new Frame { BorderColor = Color.Teal, });
var viewContainer = new StateViewContainer<Frame> (Test.Frame.OutlineColor, new Frame {
OutlineColor = Color.Teal,
BorderColor = Color.Teal,
Content = new Label { Text = "I am a frame" }
});

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

@ -32,7 +32,7 @@ namespace Xamarin.Forms.Controls
var entry = new Entry { Placeholder = "Edit this text on entry", PlaceholderColor = Color.Pink, TextColor = Color.Yellow, BackgroundColor = Color.Green };
var frame = new Frame { HasShadow = true, BackgroundColor = Color.Maroon, OutlineColor = Color.Lime, MinimumHeightRequest = 100 };
var frame = new Frame { HasShadow = true, BackgroundColor = Color.Maroon, BorderColor = Color.Lime, MinimumHeightRequest = 100 };
var image = new Image { HeightRequest = 100, Source = "crimson.jpg" };

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

@ -189,8 +189,7 @@ namespace Xamarin.Forms.Core.UnitTests
public void ManuallySetFontSizeNotOverridenByStyle ()
{
var label = new Label ();
Assert.AreEqual (10.0, label.FontSize);
Assume.That (label.FontSize, Is.EqualTo(10.0));
label.SetValue (Label.FontSizeProperty, 2.0, false);
Assert.AreEqual (2.0, label.FontSize);
@ -199,6 +198,19 @@ namespace Xamarin.Forms.Core.UnitTests
Assert.AreEqual (2.0, label.FontSize);
}
[Test]
public void ManuallySetFontSizeNotOverridenByFontSetInStyle()
{
var label = new Label();
Assume.That(label.FontSize, Is.EqualTo(10.0));
label.SetValue(Label.FontSizeProperty, 2.0);
Assert.AreEqual(2.0, label.FontSize);
label.SetValue(Label.FontProperty, Font.SystemFontOfSize(1.0), fromStyle: true);
Assert.AreEqual(2.0, label.FontSize);
}
[Test]
public void ChangingHorizontalTextAlignmentFiresXAlignChanged ()
{

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

@ -0,0 +1,68 @@
using System;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.StyleSheets.UnitTests
{
[TestFixture]
public class IStylableTest
{
[SetUp]
public void SetUp()
{
Device.PlatformServices = new MockPlatformServices();
Internals.Registrar.RegisterAll(new Type[0]);
}
[TestCase]
public void GetPropertyDefinedOnParent()
{
var label = new Label();
var bp = ((IStylable)label).GetProperty("background-color");
Assert.AreSame(VisualElement.BackgroundColorProperty, bp);
}
[TestCase]
public void GetPropertyDefinedOnType()
{
var label = new Label();
var bp = ((IStylable)label).GetProperty("color");
Assert.AreSame(Label.TextColorProperty, bp);
}
[TestCase]
public void GetPropertyDefinedOnType2()
{
var entry = new Entry();
var bp = ((IStylable)entry).GetProperty("color");
Assert.AreSame(Entry.TextColorProperty, bp);
}
[TestCase]
public void GetInvalidPropertyForType()
{
var grid = new Grid();
var bp = ((IStylable)grid).GetProperty("color");
Assert.Null(bp);
}
[TestCase]
public void GetPropertyDefinedOnPropertyOwnerType()
{
var frame = new Frame();
var bp = ((IStylable)frame).GetProperty("padding-left");
Assert.That(bp, Is.SameAs(PaddingElement.PaddingLeftProperty));
}
[TestCase]
public void GetNonPublicProperty()
{
var label = new Label();
var bp = ((IStylable)label).GetProperty("margin-right");
Assert.That(bp, Is.SameAs(View.MarginRightProperty));
}
}
}

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

@ -0,0 +1,14 @@
using System.Collections.Generic;
using NUnit.Framework;
namespace Xamarin.Forms.StyleSheets.UnitTests
{
class MockStylable : IStyleSelectable
{
public IEnumerable<IStyleSelectable> Children { get; set; }
public IList<string> Classes { get; set; }
public string Id { get; set; }
public string[] NameAndBases { get; set; }
public IStyleSelectable Parent { get; set; }
}
}

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

@ -0,0 +1,114 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NUnit.Framework;
namespace Xamarin.Forms.StyleSheets.UnitTests
{
[TestFixture]
public class SelectorTests
{
IStyleSelectable Page;
IStyleSelectable StackLayout => Page.Children.First();
IStyleSelectable Label0 => StackLayout.Children.Skip(0).First();
IStyleSelectable Label1 => StackLayout.Children.Skip(1).First();
IStyleSelectable Label2 => ContentView0.Children.First();
IStyleSelectable Label3 => StackLayout.Children.Skip(3).First();
IStyleSelectable Label4 => StackLayout.Children.Skip(4).First();
IStyleSelectable ContentView0 => StackLayout.Children.Skip(2).First();
[SetUp]
public void SetUp()
{
Page = new MockStylable {
NameAndBases = new[] { "Page", "Layout", "VisualElement" },
Children = new List<IStyleSelectable> {
new MockStylable {
NameAndBases = new[] { "StackLayout", "Layout", "VisualElement" },
Children = new List<IStyleSelectable> {
new MockStylable {NameAndBases = new[] { "Label", "VisualElement" }, Classes = new[]{"test"}}, //Label0
new MockStylable {NameAndBases = new[] { "Label", "VisualElement" }}, //Label1
new MockStylable { //ContentView0
NameAndBases = new[] { "ContentView", "Layout", "VisualElement" },
Classes = new[]{"test"},
Children = new List<IStyleSelectable> {
new MockStylable {NameAndBases = new[] { "Label", "VisualElement" }, Classes = new[]{"test"}}, //Label2
}
},
new MockStylable {NameAndBases = new[] { "Label", "VisualElement" }, Id="foo"}, //Label3
new MockStylable {NameAndBases = new[] { "Label", "VisualElement" }}, //Label4
}
}
}
};
SetParents(Page);
}
void SetParents(IStyleSelectable stylable, IStyleSelectable parent = null)
{
((MockStylable)stylable).Parent = parent;
if (stylable.Children == null)
return;
foreach (var s in stylable.Children)
SetParents(s, stylable);
}
[TestCase("label", true, true, true, true, true, false)]
[TestCase(" label", true, true, true, true, true, false)]
[TestCase("label ", true, true, true, true, true, false)]
[TestCase(".test", true, false, true, false, false, true)]
[TestCase("label.test", true, false, true, false, false, false)]
[TestCase("stacklayout>label.test", true, false, false, false, false, false)]
[TestCase("stacklayout >label.test", true, false, false, false, false, false)]
[TestCase("stacklayout> label.test", true, false, false, false, false, false)]
[TestCase("stacklayout label.test", true, false, true, false, false, false)]
[TestCase("stacklayout label.test", true, false, true, false, false, false)]
[TestCase("stacklayout .test", true, false, true, false, false, true)]
[TestCase("stacklayout.test", false, false, false, false, false, false)]
[TestCase("*", true, true, true, true, true, true)]
[TestCase("#foo", false, false, false, true, false, false)]
[TestCase("label#foo", false, false, false, true, false, false)]
[TestCase("div#foo", false, false, false, false, false, false)]
[TestCase(".test,#foo", true, false, true, true, false, true)]
[TestCase(".test ,#foo", true, false, true, true, false, true)]
[TestCase(".test, #foo", true, false, true, true, false, true)]
[TestCase("#foo,.test", true, false, true, true, false, true)]
[TestCase("#foo ,.test", true, false, true, true, false, true)]
[TestCase("#foo, .test", true, false, true, true, false, true)]
[TestCase("contentview+label", false, false, false, true, false, false)]
[TestCase("contentview +label", false, false, false, true, false, false)]
[TestCase("contentview+ label", false, false, false, true, false, false)]
[TestCase("contentview~label", false, false, false, true, true, false)]
[TestCase("contentview ~label", false, false, false, true, true, false)]
[TestCase("contentview\r\n~label", false, false, false, true, true, false)]
[TestCase("contentview~ label", false, false, false, true, true, false)]
[TestCase("label~*", false, true, false, true, true, true)]
[TestCase("label~.test", false, false, false, false, false, true)]
[TestCase("label~#foo", false, false, false, true, false, false)]
[TestCase("page contentview stacklayout label", false, false, false, false, false, false)]
[TestCase("page stacklayout contentview label", false, false, true, false, false, false)]
[TestCase("page contentview label", false, false, true, false, false, false)]
[TestCase("page contentview>label", false, false, true, false, false, false)]
[TestCase("page>stacklayout contentview label", false, false, true, false, false, false)]
[TestCase("page stacklayout>contentview label", false, false, true, false, false, false)]
[TestCase("page stacklayout contentview>label", false, false, true, false, false, false)]
[TestCase("page>stacklayout>contentview label", false, false, true, false, false, false)]
[TestCase("page>stack/* comment * */layout>contentview label", false, false, true, false, false, false)]
[TestCase("page>stacklayout contentview>label", false, false, true, false, false, false)]
[TestCase("page stacklayout>contentview>label", false, false, true, false, false, false)]
[TestCase("page>stacklayout>contentview>label", false, false, true, false, false, false)]
[TestCase("visualelement", false, false, false, false, false, false)]
[TestCase("^visualelement", true, true, true, true, true, true)]
[TestCase("^layout", false, false, false, false, false, true)]
public void TestCase(string selectorString, bool label0match, bool label1match, bool label2match, bool label3match, bool label4match, bool content0match)
{
var selector = Selector.Parse(new CssReader(new StringReader(selectorString)));
Assert.AreEqual(label0match, selector.Matches(Label0));
Assert.AreEqual(label1match, selector.Matches(Label1));
Assert.AreEqual(label2match, selector.Matches(Label2));
Assert.AreEqual(label3match, selector.Matches(Label3));
Assert.AreEqual(label4match, selector.Matches(Label4));
Assert.AreEqual(content0match, selector.Matches(ContentView0));
}
}
}

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

@ -0,0 +1,82 @@
using System;
using System.IO;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.StyleSheets.UnitTests
{
[TestFixture]
public class StyleTests
{
[SetUp]
public void SetUp()
{
Device.PlatformServices = new MockPlatformServices();
Internals.Registrar.RegisterAll(new Type[0]);
}
[Test]
public void PropertiesAreApplied()
{
var styleString = @"background-color: #ff0000;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);
var ve = new VisualElement();
Assume.That(ve.BackgroundColor, Is.EqualTo(Color.Default));
style.Apply(ve);
Assert.That(ve.BackgroundColor, Is.EqualTo(Color.Red));
}
[Test]
public void PropertiesSetByStyleDoesNotOverrideManualOne()
{
var styleString = @"background-color: #ff0000;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);
var ve = new VisualElement() { BackgroundColor = Color.Pink };
Assume.That(ve.BackgroundColor, Is.EqualTo(Color.Pink));
style.Apply(ve);
Assert.That(ve.BackgroundColor, Is.EqualTo(Color.Pink));
}
[Test]
public void StylesAreCascading()
{
var styleString = @"background-color: #ff0000; color: #00ff00;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);
var label = new Label();
var layout = new StackLayout {
Children = {
label,
}
};
Assume.That(layout.BackgroundColor, Is.EqualTo(Color.Default));
Assume.That(label.BackgroundColor, Is.EqualTo(Color.Default));
Assume.That(label.TextColor, Is.EqualTo(Color.Default));
style.Apply(layout);
Assert.That(layout.BackgroundColor, Is.EqualTo(Color.Red));
Assert.That(label.BackgroundColor, Is.EqualTo(Color.Red));
Assert.That(label.TextColor, Is.EqualTo(Color.Lime));
}
[Test]
public void PropertiesAreOnlySetOnMatchingElements()
{
var styleString = @"background-color: #ff0000; color: #00ff00;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);
var layout = new StackLayout();
Assert.That(layout.GetValue(TextElement.TextColorProperty), Is.EqualTo(Color.Default));
}
}
}

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

@ -180,6 +180,10 @@
<Compile Include="NativeBindingTests.cs" />
<Compile Include="TypedBindingUnitTests.cs" />
<Compile Include="AnimationTests.cs" />
<Compile Include="StyleSheets\MockStylable.cs" />
<Compile Include="StyleSheets\SelectorTests.cs" />
<Compile Include="StyleSheets\IStylableTest.cs" />
<Compile Include="StyleSheets\StyleTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Xamarin.Forms.Core\Xamarin.Forms.Core.csproj">
@ -212,4 +216,7 @@
<LogicalName>Images/crimson.jpg</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>
<ItemGroup>
<Folder Include="StyleSheets\" />
</ItemGroup>
</Project>

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

@ -34,9 +34,14 @@ namespace Xamarin.Forms
public event EventHandler BindingContextChanged;
internal void ClearValue(BindableProperty property, bool fromStyle)
{
ClearValue(property, fromStyle: fromStyle, checkAccess: true);
}
public void ClearValue(BindableProperty property)
{
ClearValue(property, true);
ClearValue(property, fromStyle: false, checkAccess: true);
}
public void ClearValue(BindablePropertyKey propertyKey)
@ -44,7 +49,7 @@ namespace Xamarin.Forms
if (propertyKey == null)
throw new ArgumentNullException("propertyKey");
ClearValue(propertyKey.BindableProperty, false);
ClearValue(propertyKey.BindableProperty, fromStyle:false, checkAccess: false);
}
public object GetValue(BindableProperty property)
@ -442,18 +447,23 @@ namespace Xamarin.Forms
bindable.OnBindingContextChanged();
}
void ClearValue(BindableProperty property, bool checkaccess)
void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
{
if (property == null)
throw new ArgumentNullException("property");
throw new ArgumentNullException(nameof(property));
if (checkaccess && property.IsReadOnly)
if (checkAccess && property.IsReadOnly)
throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
BindablePropertyContext bpcontext = GetContext(property);
if (bpcontext == null)
return;
if ( fromStyle && bpcontext != null
&& (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) != 0
&& (bpcontext.Attributes & BindableContextAttributes.IsSetFromStyle) == 0)
return;
object original = bpcontext.Value;
object newValue = property.GetDefaultValue(this);
@ -461,8 +471,7 @@ namespace Xamarin.Forms
bool same = Equals(original, newValue);
if (!same)
{
if (property.PropertyChanging != null)
property.PropertyChanging(this, original, newValue);
property.PropertyChanging?.Invoke(this, original, newValue);
OnPropertyChanging(property.PropertyName);
}
@ -474,8 +483,7 @@ namespace Xamarin.Forms
if (!same)
{
OnPropertyChanged(property.PropertyName);
if (property.PropertyChanged != null)
property.PropertyChanged(this, original, newValue);
property.PropertyChanged?.Invoke(this, original, newValue);
}
}

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

@ -0,0 +1,14 @@
namespace Xamarin.Forms
{
static class BorderElement
{
public static readonly BindableProperty BorderColorProperty =
BindableProperty.Create("BorderColor", typeof(Color), typeof(IBorderElement), Color.Default,
propertyChanged: OnBorderColorPropertyChanged);
static void OnBorderColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
((IBorderElement)bindable).OnBorderColorPropertyChanged((Color)oldValue, (Color)newValue);
}
}
}

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

@ -8,7 +8,7 @@ using Xamarin.Forms.Platform;
namespace Xamarin.Forms
{
[RenderWith(typeof(_ButtonRenderer))]
public class Button : View, IFontElement, ITextElement, IButtonController, IElementConfiguration<Button>
public class Button : View, IFontElement, ITextElement, IBorderElement, IButtonController, IElementConfiguration<Button>
{
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(Button), null, propertyChanged: (bo, o, n) => ((Button)bo).OnCommandChanged());
@ -33,7 +33,7 @@ namespace Xamarin.Forms
public static readonly BindableProperty BorderWidthProperty = BindableProperty.Create("BorderWidth", typeof(double), typeof(Button), -1d);
public static readonly BindableProperty BorderColorProperty = BindableProperty.Create("BorderColor", typeof(Color), typeof(Button), Color.Default);
public static readonly BindableProperty BorderColorProperty = BorderElement.BorderColorProperty;
public static readonly BindableProperty BorderRadiusProperty = BindableProperty.Create("BorderRadius", typeof(int), typeof(Button), 5);
@ -47,8 +47,8 @@ namespace Xamarin.Forms
public Color BorderColor
{
get { return (Color)GetValue(BorderColorProperty); }
set { SetValue(BorderColorProperty, value); }
get { return (Color)GetValue(BorderElement.BorderColorProperty); }
set { SetValue(BorderElement.BorderColorProperty, value); }
}
public int BorderRadius
@ -245,6 +245,10 @@ namespace Xamarin.Forms
{
}
void IBorderElement.OnBorderColorPropertyChanged(Color oldValue, Color newValue)
{
}
[DebuggerDisplay("Image Position = {Position}, Spacing = {Spacing}")]
[TypeConverter(typeof(ButtonContentTypeConverter))]
public sealed class ButtonContentLayout

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

@ -9,7 +9,7 @@ using Xamarin.Forms.Internals;
namespace Xamarin.Forms
{
public abstract class Element : BindableObject, IElement, INameScope, IElementController
public abstract partial class Element : BindableObject, IElement, INameScope, IElementController
{
public static readonly BindableProperty MenuProperty = BindableProperty.CreateAttached(nameof(Menu), typeof(Menu), typeof(Element), null);
@ -428,7 +428,7 @@ namespace Xamarin.Forms
}
}
internal void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
internal virtual void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
{
OnParentResourcesChanged(e.Values);
}
@ -447,7 +447,7 @@ namespace Xamarin.Forms
base.OnRemoveDynamicResource(property);
}
internal void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
internal virtual void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
{
OnResourcesChanged(e.Values);
}

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

@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Xamarin.Forms.Internals;
using Xamarin.Forms.StyleSheets;
namespace Xamarin.Forms
{
public partial class Element : IStyleSelectable
{
IEnumerable<IStyleSelectable> IStyleSelectable.Children => LogicalChildrenInternal;
IList<string> IStyleSelectable.Classes => null;
string IStyleSelectable.Id => StyleId;
string[] _styleSelectableNameAndBaseNames;
string[] IStyleSelectable.NameAndBases {
get {
if (_styleSelectableNameAndBaseNames == null) {
var list = new List<string>();
var t = GetType();
while (t != typeof(BindableObject)) {
list.Add(t.Name);
t = t.GetTypeInfo().BaseType;
}
_styleSelectableNameAndBaseNames = list.ToArray();
}
return _styleSelectableNameAndBaseNames;
}
}
IStyleSelectable IStyleSelectable.Parent => Parent;
}
}

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

@ -1,9 +1,32 @@
using System;
namespace Xamarin.Forms
{
[TypeConverter(typeof(FlowDirectionConverter))]
public enum FlowDirection
{
MatchParent = 0,
LeftToRight = 1,
RightToLeft = 2,
}
[Xaml.TypeConversion(typeof(FlowDirection))]
public class FlowDirectionConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (value != null) {
if (Enum.TryParse(value, out FlowDirection direction))
return direction;
if (value.Equals("ltr", StringComparison.OrdinalIgnoreCase))
return FlowDirection.LeftToRight;
if (value.Equals("rtl", StringComparison.OrdinalIgnoreCase))
return FlowDirection.RightToLeft;
if (value.Equals("inherit", StringComparison.OrdinalIgnoreCase))
return FlowDirection.MatchParent;
}
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(FlowDirection)));
}
}
}

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

@ -20,8 +20,9 @@ namespace Xamarin.Forms
double size;
if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out size))
return size;
var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
NamedSize namedSize;
if (Enum.TryParse(value, out namedSize))
if (Enum.TryParse(value, ignoreCase, out namedSize))
{
Type type;
var valueTargetProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

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

@ -5,9 +5,12 @@ namespace Xamarin.Forms
{
[ContentProperty("Content")]
[RenderWith(typeof(_FrameRenderer))]
public class Frame : ContentView, IElementConfiguration<Frame>, IPaddingElement
public class Frame : ContentView, IElementConfiguration<Frame>, IPaddingElement, IBorderElement
{
public static readonly BindableProperty OutlineColorProperty = BindableProperty.Create("OutlineColor", typeof(Color), typeof(Frame), Color.Default);
[Obsolete("OutlineColorProperty is obsolete as of version 3.0.0. Please use BorderColorProperty instead.")]
public static readonly BindableProperty OutlineColorProperty = BorderElement.BorderColorProperty;
public static readonly BindableProperty BorderColorProperty = BorderElement.BorderColorProperty;
public static readonly BindableProperty HasShadowProperty = BindableProperty.Create("HasShadow", typeof(bool), typeof(Frame), true);
@ -32,12 +35,19 @@ namespace Xamarin.Forms
set { SetValue(HasShadowProperty, value); }
}
[Obsolete("OutlineColor is obsolete as of version 3.0.0. Please use BorderColor instead.")]
public Color OutlineColor
{
get { return (Color)GetValue(OutlineColorProperty); }
set { SetValue(OutlineColorProperty, value); }
}
public Color BorderColor
{
get { return (Color)GetValue(BorderElement.BorderColorProperty); }
set { SetValue(BorderElement.BorderColorProperty, value); }
}
public float CornerRadius
{
get { return (float)GetValue(CornerRadiusProperty); }
@ -48,5 +58,12 @@ namespace Xamarin.Forms
{
return _platformConfigurationRegistry.Value.On<T>();
}
void IBorderElement.OnBorderColorPropertyChanged(Color oldValue, Color newValue)
{
#pragma warning disable 0618 // retain until OutlineColor removed
OnPropertyChanged(nameof(OutlineColor));
#pragma warning restore
}
}
}

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

@ -0,0 +1,11 @@
namespace Xamarin.Forms
{
interface IBorderElement
{
//note to implementor: implement this property publicly
Color BorderColor { get; }
//note to implementor: but implement the methods explicitly
void OnBorderColorPropertyChanged(Color oldValue, Color newValue);
}
}

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

@ -0,0 +1,7 @@
namespace Xamarin.Forms.Xaml
{
interface IConverterOptions
{
bool IgnoreCase { get; }
}
}

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

@ -5,14 +5,14 @@ namespace Xamarin.Forms.Internals
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IFontElement
{
//note to implementor: implement the properties publicly
//note to implementor: implement these properties publicly
FontAttributes FontAttributes { get; }
string FontFamily { get; }
[TypeConverter(typeof(FontSizeConverter))]
double FontSize { get; }
//note to implementor: but implement the methods explicitly
//note to implementor: but implement these methods explicitly
void OnFontFamilyChanged(string oldValue, string newValue);
void OnFontSizeChanged(double oldValue, double newValue);
double FontSizeDefaultValueCreator();

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

@ -2,7 +2,7 @@ using System;
namespace Xamarin.Forms
{
internal interface IStyle
interface IStyle
{
Type TargetType { get; }

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

@ -4,10 +4,10 @@ namespace Xamarin.Forms
{
interface ITextElement
{
//note to implementor: implement the properties publicly
//note to implementor: implement this property publicly
Color TextColor { get; }
//note to implementor: but implement the methods explicitly
//note to implementor: but implement this method explicitly
void OnTextColorPropertyChanged(Color oldValue, Color newValue);
}
}

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

@ -467,4 +467,4 @@ namespace Xamarin.Forms
return true;
}
}
}
}

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

@ -1,5 +1,7 @@
using System.Runtime.CompilerServices;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
using Xamarin.Forms.StyleSheets;
[assembly: InternalsVisibleTo("iOSUnitTests")]
[assembly: InternalsVisibleTo("Xamarin.Forms.Controls")]
@ -30,4 +32,31 @@ using Xamarin.Forms.Internals;
[assembly: InternalsVisibleTo("Xamarin.Forms.CarouselView")]
[assembly: Preserve]
[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")]
[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")]
[assembly: StyleProperty("background-color", typeof(VisualElement), nameof(VisualElement.BackgroundColorProperty))]
[assembly: StyleProperty("background-image", typeof(Page), nameof(Page.BackgroundImageProperty))]
[assembly: StyleProperty("border-color", typeof(Button), nameof(BorderElement.BorderColorProperty))]
[assembly: StyleProperty("border-width", typeof(Button), nameof(Button.BorderWidthProperty))]
[assembly: StyleProperty("color", typeof(ITextElement), nameof(TextElement.TextColorProperty))]
[assembly: StyleProperty("direction", typeof(VisualElement), nameof(VisualElement.FlowDirectionProperty))]
[assembly: StyleProperty("font-family", typeof(IFontElement), nameof(FontElement.FontFamilyProperty))]
[assembly: StyleProperty("font-size", typeof(IFontElement), nameof(FontElement.FontSizeProperty))]
[assembly: StyleProperty("font-style", typeof(IFontElement), nameof(FontElement.FontAttributesProperty))]
[assembly: StyleProperty("height", typeof(VisualElement), nameof(VisualElement.HeightRequestProperty))]
[assembly: StyleProperty("margin", typeof(View), nameof(View.MarginProperty))]
[assembly: StyleProperty("margin-left", typeof(View), nameof(View.MarginLeftProperty))]
[assembly: StyleProperty("margin-top", typeof(View), nameof(View.MarginTopProperty))]
[assembly: StyleProperty("margin-right", typeof(View), nameof(View.MarginRightProperty))]
[assembly: StyleProperty("margin-bottom", typeof(View), nameof(View.MarginBottomProperty))]
[assembly: StyleProperty("min-height", typeof(VisualElement), nameof(VisualElement.MinimumHeightRequestProperty))]
[assembly: StyleProperty("min-width", typeof(VisualElement), nameof(VisualElement.MinimumWidthRequestProperty))]
[assembly: StyleProperty("opacity", typeof(VisualElement), nameof(VisualElement.OpacityProperty))]
[assembly: StyleProperty("padding", typeof(IPaddingElement), nameof(PaddingElement.PaddingProperty))]
[assembly: StyleProperty("padding-left", typeof(IPaddingElement), nameof(PaddingElement.PaddingLeftProperty), PropertyOwnerType=typeof(PaddingElement))]
[assembly: StyleProperty("padding-top", typeof(IPaddingElement), nameof(PaddingElement.PaddingTopProperty), PropertyOwnerType = typeof(PaddingElement))]
[assembly: StyleProperty("padding-right", typeof(IPaddingElement), nameof(PaddingElement.PaddingRightProperty), PropertyOwnerType = typeof(PaddingElement))]
[assembly: StyleProperty("padding-bottom", typeof(IPaddingElement), nameof(PaddingElement.PaddingBottomProperty), PropertyOwnerType = typeof(PaddingElement))]
[assembly: StyleProperty("text-align", typeof(ITextAlignmentElement), nameof(TextAlignmentElement.HorizontalTextAlignmentProperty))]
[assembly: StyleProperty("visibility", typeof(VisualElement), nameof(VisualElement.IsVisibleProperty))]
[assembly: StyleProperty("width", typeof(VisualElement), nameof(VisualElement.WidthRequestProperty))]

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

@ -97,14 +97,14 @@ namespace Xamarin.Forms.Internals
type = attribute.Type;
if (type.Name.StartsWith("_"))
if (type.Name.StartsWith("_", StringComparison.Ordinal))
{
// TODO: Remove attribute2 once renderer names have been unified across all platforms
var attribute2 = type.GetTypeInfo().GetCustomAttribute<RenderWithAttribute>();
if (attribute2 != null)
type = attribute2.Type;
if (type.Name.StartsWith("_"))
if (type.Name.StartsWith("_", StringComparison.Ordinal))
{
Register(viewType, null); // Cache this result so we don't work through this chain again
return null;
@ -156,6 +156,7 @@ namespace Xamarin.Forms.Internals
}
internal static Dictionary<string, Type> Effects { get; } = new Dictionary<string, Type>();
internal static Dictionary<string, StyleSheets.StylePropertyAttribute> StyleProperties { get; } = new Dictionary<string, StyleSheets.StylePropertyAttribute>();
public static IEnumerable<Assembly> ExtraAssemblies { get; set; }
@ -165,9 +166,7 @@ namespace Xamarin.Forms.Internals
{
Assembly[] assemblies = Device.GetAssemblies();
if (ExtraAssemblies != null)
{
assemblies = assemblies.Union(ExtraAssemblies).ToArray();
}
Assembly defaultRendererAssembly = Device.PlatformServices.GetType().GetTypeInfo().Assembly;
int indexOfExecuting = Array.IndexOf(assemblies, defaultRendererAssembly);
@ -185,36 +184,38 @@ namespace Xamarin.Forms.Internals
foreach (Type attrType in attrTypes)
{
Attribute[] attributes = assembly.GetCustomAttributes(attrType).ToArray();
if (attributes.Length == 0)
continue;
foreach (HandlerAttribute attribute in attributes)
var length = attributes.Length;
for (var i = 0; i < length;i++)
{
var attribute = (HandlerAttribute)attributes[i];
if (attribute.ShouldRegister())
Registered.Register(attribute.HandlerType, attribute.TargetType);
}
}
string resolutionName = assembly.FullName;
var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
if (resolutionNameAttribute != null)
resolutionName = resolutionNameAttribute.ShortName;
Attribute[] effectAttributes = assembly.GetCustomAttributes(typeof(ExportEffectAttribute)).ToArray();
if (effectAttributes.Length > 0)
var exportEffectsLength = effectAttributes.Length;
for (var i = 0; i < exportEffectsLength;i++)
{
var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
if (resolutionNameAttribute != null)
{
resolutionName = resolutionNameAttribute.ShortName;
}
var effect = (ExportEffectAttribute)effectAttributes[i];
Effects [resolutionName + "." + effect.Id] = effect.Type;
}
foreach (Attribute attribute in effectAttributes)
{
var effect = (ExportEffectAttribute)attribute;
Effects[resolutionName + "." + effect.Id] = effect.Type;
}
Attribute[] styleAttributes = assembly.GetCustomAttributes(typeof(StyleSheets.StylePropertyAttribute)).ToArray();
var stylePropertiesLength = styleAttributes.Length;
for (var i = 0; i < stylePropertiesLength; i++)
{
var attribute = (StyleSheets.StylePropertyAttribute)styleAttributes[i];
StyleProperties[attribute.CssPropertyName] = attribute;
}
}
DependencyService.Initialize(assemblies);
}
}
}
}

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

@ -68,7 +68,7 @@ namespace Xamarin.Forms
if (type != null)
_mergedInstance = s_instances.GetValue(type, (key) => (ResourceDictionary)Activator.CreateInstance(key));
else
_mergedInstance = DependencyService.Get<IResourcesLoader>().CreateResourceDictionary(resourcePath, assembly, lineInfo);
_mergedInstance = DependencyService.Get<IResourcesLoader>().CreateFromResource<ResourceDictionary>(resourcePath, assembly, lineInfo);
OnValuesChanged(_mergedInstance.ToArray());
}
@ -84,6 +84,16 @@ namespace Xamarin.Forms
}
}
internal IList<StyleSheets.StyleSheet> StyleSheets { get; set; }
void StyleSheetsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
ValuesChanged?.Invoke(this, ResourcesChangedEventArgs.StyleSheets);
break;
}
}
IList<ResourceDictionary> _collectionTrack;
void MergedDictionaries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
@ -284,6 +294,13 @@ namespace Xamarin.Forms
MergedDictionaries.Add(mergedResourceDictionary);
}
public void Add(StyleSheets.StyleSheet styleSheet)
{
StyleSheets = StyleSheets ?? new List<StyleSheets.StyleSheet>(2);
StyleSheets.Add(styleSheet);
ValuesChanged?.Invoke(this, ResourcesChangedEventArgs.StyleSheets);
}
void OnValueChanged(string key, object value)
{
OnValuesChanged(new KeyValuePair<string, object>(key, value));

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

@ -7,6 +7,8 @@ namespace Xamarin.Forms.Internals
[EditorBrowsable(EditorBrowsableState.Never)]
public class ResourcesChangedEventArgs : EventArgs
{
public static readonly ResourcesChangedEventArgs StyleSheets = new ResourcesChangedEventArgs(null);
public ResourcesChangedEventArgs(IEnumerable<KeyValuePair<string, object>> values)
{
Values = values;

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

@ -0,0 +1,41 @@
using System.Runtime.CompilerServices;
namespace Xamarin.Forms.StyleSheets
{
static class CharExtensions
{
//w [ \t\r\n\f]*
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsW(this char c)
{
return c == ' '
|| c == '\t'
|| c == '\r'
|| c == '\n'
|| c == '\f';
}
//nmstart [_a-z]|{nonascii}|{escape}
//escape {unicode}|\\[^\n\r\f0-9a-f]
//nonascii [^\0-\237]
// TODO support escape and nonascii
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNmStart(this char c)
{
return c == '_' || char.IsLetter(c);
}
//nmchar [_a-z0-9-]|{nonascii}|{escape}
//unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
//escape {unicode}|\\[^\n\r\f0-9a-f]
//nonascii [^\0-\237]
//TODO support escape, nonascii and unicode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNmChar(this char c)
{
return c == '_'
|| c == '-'
|| char.IsLetterOrDigit(c);
}
}
}

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

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Xamarin.Forms.StyleSheets
{
sealed class CssReader : TextReader
{
readonly TextReader _reader;
public CssReader(TextReader reader)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
_reader = reader;
}
readonly Queue<char> _cache = new Queue<char>();
//skip comments
//TODO unescape escaped sequences
public override int Peek()
{
if (_cache.Count > 0)
return _cache.Peek();
int p = _reader.Peek();
if (p <= 0)
return p;
if (unchecked((char)p) != '/')
return p;
_cache.Enqueue(unchecked((char)_reader.Read()));
p = _reader.Peek();
if (p <= 0)
return _cache.Peek();
if (unchecked((char)p) != '*')
return _cache.Peek();
_cache.Clear();
_reader.Read(); //consume the '*'
bool hasStar = false;
while (true) {
var next = _reader.Read();
if (next <= 0)
return next;
if (unchecked((char)next) == '*')
hasStar = true;
else if (hasStar && unchecked((char)next) == '/')
return Peek(); //recursively call self for comments following comments
else
hasStar = false;
}
}
//skip comments
//TODO unescape escaped sequences
public override int Read()
{
if (_cache.Count > 0)
return _cache.Dequeue();
int p = _reader.Read();
if (p <= 0)
return p;
var c = unchecked((char)p);
if (c != '/')
return p;
_cache.Enqueue(c);
p = _reader.Read();
if (p <= 0)
return _cache.Dequeue();
c = unchecked((char)p);
if (c != '*')
return _cache.Dequeue();
_cache.Clear();
_reader.Read(); //consume the '*'
bool hasStar = false;
while (true) {
var next = _reader.Read();
if (next <= 0)
return next;
if (unchecked((char)next) == '*')
hasStar = true;
else if (hasStar && unchecked((char)next) == '/')
return Read(); //recursively call self for comments following comments
else
hasStar = false;
}
}
}
}

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

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
namespace Xamarin.Forms.StyleSheets
{
interface IStyleSelectable
{
string[] NameAndBases { get; }
string Id { get; }
IStyleSelectable Parent { get; }
IList<string> Classes { get; }
IEnumerable<IStyleSelectable> Children { get; }
}
interface IStylable
{
BindableProperty GetProperty(string key);
}
}

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

@ -0,0 +1,306 @@
using System;
namespace Xamarin.Forms.StyleSheets
{
abstract class Selector
{
Selector()
{
}
public static Selector Parse(CssReader reader, char stopChar = '\0')
{
Selector root = All, workingRoot = All;
Operator workingRootParent = null;
Action<Operator, Selector> setCurrentSelector = (op, sel) => SetCurrentSelector(ref root, ref workingRoot, ref workingRootParent, op, sel);
int p;
reader.SkipWhiteSpaces();
while ((p = reader.Peek()) > 0) {
switch (unchecked((char)p)) {
case '*':
setCurrentSelector(new And(), All);
reader.Read();
break;
case '.':
reader.Read();
var className = reader.ReadIdent();
if (className == null)
return Invalid;
setCurrentSelector(new And(), new Class(className));
break;
case '#':
reader.Read();
var id = reader.ReadName();
if (id == null)
return Invalid;
setCurrentSelector(new And(), new Id(id));
break;
case '[':
throw new NotImplementedException("Attributes not implemented");
case ',':
reader.Read();
setCurrentSelector(new Or(), All);
reader.SkipWhiteSpaces();
break;
case '+':
reader.Read();
setCurrentSelector(new Adjacent(), All);
reader.SkipWhiteSpaces();
break;
case '~':
reader.Read();
setCurrentSelector(new Sibling(), All);
reader.SkipWhiteSpaces();
break;
case '>':
reader.Read();
setCurrentSelector(new Child(), All);
reader.SkipWhiteSpaces();
break;
case '^': //not in CSS spec
reader.Read();
var element = reader.ReadIdent();
if (element == null)
return Invalid;
setCurrentSelector(new And(), new Base(element));
break;
case ' ':
case '\t':
case '\n':
case '\r':
case '\f':
reader.Read();
bool processWs = false;
while ((p = reader.Peek()) > 0) {
var c = unchecked((char)p);
if (char.IsWhiteSpace(c)) {
reader.Read();
continue;
}
processWs = (c != '+'
&& c != '>'
&& c != ','
&& c != '~'
&& c != '^'
&& c != stopChar);
break;
}
if (!processWs)
break;
setCurrentSelector(new Descendent(), All);
reader.SkipWhiteSpaces();
break;
default:
if (unchecked((char)p) == stopChar)
return root;
var elementName = reader.ReadIdent();
if (elementName == null)
return Invalid;
setCurrentSelector(new And(), new Element(elementName));
break;
}
}
return root;
}
static void SetCurrentSelector(ref Selector root, ref Selector workingRoot, ref Operator workingRootParent, Operator op, Selector sel)
{
var updateRoot = root == workingRoot;
op.Left = workingRoot;
op.Right = sel;
workingRoot = op;
if (workingRootParent != null)
workingRootParent.Right = workingRoot;
if (updateRoot)
root = workingRoot;
if (workingRoot is Or) {
workingRootParent = (Operator)workingRoot;
workingRoot = sel;
}
}
public abstract bool Matches(IStyleSelectable styleable);
internal static Selector Invalid = new Generic(s => false);
internal static Selector All = new Generic(s => true);
abstract class UnarySelector : Selector
{
}
abstract class Operator : Selector
{
public Selector Left { get; set; } = Invalid;
public Selector Right { get; set; } = Invalid;
}
sealed class Generic : UnarySelector
{
readonly Func<IStyleSelectable, bool> func;
public Generic(Func<IStyleSelectable, bool> func)
{
this.func = func;
}
public override bool Matches(IStyleSelectable styleable) => func(styleable);
}
sealed class Class : UnarySelector
{
public Class(string className)
{
ClassName = className;
}
public string ClassName { get; }
public override bool Matches(IStyleSelectable styleable)
=> styleable.Classes != null && styleable.Classes.Contains(ClassName);
}
sealed class Id : UnarySelector
{
public Id(string id)
{
IdName = id;
}
public string IdName { get; }
public override bool Matches(IStyleSelectable styleable) => styleable.Id == IdName;
}
sealed class Or : Operator
{
public override bool Matches(IStyleSelectable styleable) => Right.Matches(styleable) || Left.Matches(styleable);
}
sealed class And : Operator
{
public override bool Matches(IStyleSelectable styleable) => Right.Matches(styleable) && Left.Matches(styleable);
}
sealed class Element : UnarySelector
{
public Element(string elementName)
{
ElementName = elementName;
}
public string ElementName { get; }
public override bool Matches(IStyleSelectable styleable) =>
string.Equals(styleable.NameAndBases[0], ElementName, StringComparison.OrdinalIgnoreCase);
}
sealed class Base : UnarySelector
{
public Base(string elementName)
{
ElementName = elementName;
}
public string ElementName { get; }
public override bool Matches(IStyleSelectable styleable) {
for (var i = 0; i < styleable.NameAndBases.Length; i++)
if (string.Equals(styleable.NameAndBases[i], ElementName, StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
}
sealed class Child : Operator
{
public override bool Matches(IStyleSelectable styleable) =>
Right.Matches(styleable) && styleable.Parent != null && Left.Matches(styleable.Parent);
}
sealed class Descendent : Operator
{
public override bool Matches(IStyleSelectable styleable)
{
if (!Right.Matches(styleable))
return false;
var parent = styleable.Parent;
while (parent != null) {
if (Left.Matches(parent))
return true;
parent = parent.Parent;
}
return false;
}
}
sealed class Adjacent : Operator
{
public override bool Matches(IStyleSelectable styleable)
{
if (!Right.Matches(styleable))
return false;
if (styleable.Parent == null)
return false;
IStyleSelectable prev = null;
foreach (var elem in styleable.Parent.Children) {
if (elem == styleable && prev != null)
return Left.Matches(prev);
prev = elem;
}
return false;
//var index = styleable.Parent.Children.IndexOf(styleable);
//if (index == 0)
// return false;
//var adjacent = styleable.Parent.Children[index - 1];
//return Left.Matches(adjacent);
}
}
sealed class Sibling : Operator
{
public override bool Matches(IStyleSelectable styleable)
{
if (!Right.Matches(styleable))
return false;
if (styleable.Parent == null)
return false;
int selfIndex = 0;
bool foundSelfInParent = false;
foreach (var elem in styleable.Parent.Children) {
if (elem == styleable) {
foundSelfInParent = true;
break;
}
++selfIndex;
}
if (!foundSelfInParent)
return false;
int index = 0;
foreach (var elem in styleable.Parent.Children) {
if (index >= selfIndex)
return false;
if (Left.Matches(elem))
return true;
++index;
}
return false;
//var index = styleable.Parent.Children.IndexOf(styleable);
//if (index == 0)
// return false;
//int siblingIndex = -1;
//for (var i = 0; i < index; i++)
// if (Left.Matches(styleable.Parent.Children[i])) {
// siblingIndex = i;
// break;
// }
//return siblingIndex != -1;
}
}
}
}

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

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Runtime.CompilerServices;
using Xamarin.Forms.Xaml;
namespace Xamarin.Forms.StyleSheets
{
sealed class Style
{
Style()
{
}
public IDictionary<string, string> Declarations { get; set; } = new Dictionary<string, string>();
Dictionary<KeyValuePair<string, string>, object> convertedValues = new Dictionary<KeyValuePair<string, string>, object>();
public static Style Parse(CssReader reader, char stopChar = '\0')
{
Style style = new Style();
string propertyName = null, propertyValue = null;
int p;
reader.SkipWhiteSpaces();
bool readingName = true;
while ((p = reader.Peek()) > 0) {
switch (unchecked((char)p)) {
case ':':
reader.Read();
readingName = false;
reader.SkipWhiteSpaces();
break;
case ';':
reader.Read();
if (!string.IsNullOrEmpty(propertyName) && !string.IsNullOrEmpty(propertyValue))
style.Declarations.Add(propertyName, propertyValue);
propertyName = propertyValue = null;
readingName = true;
reader.SkipWhiteSpaces();
break;
default:
if ((char)p == stopChar)
return style;
if (readingName) {
propertyName = reader.ReadIdent();
if (propertyName == null)
throw new Exception();
} else
propertyValue = reader.ReadUntil(stopChar, ';', ':');
break;
}
}
return style;
}
public void Apply(VisualElement styleable)
{
if (styleable == null)
throw new ArgumentNullException(nameof(styleable));
foreach (var decl in Declarations) {
var property = ((IStylable)styleable).GetProperty(decl.Key);
if (property == null)
continue;
if (string.Equals(decl.Value, "initial", StringComparison.OrdinalIgnoreCase))
styleable.ClearValue(property, fromStyle: true);
else {
object value;
if (!convertedValues.TryGetValue(decl, out value))
convertedValues[decl] = (value = Convert(styleable, decl.Value, property));
styleable.SetValue(property, value, fromStyle: true);
}
}
foreach (var child in styleable.LogicalChildrenInternal) {
var ve = child as VisualElement;
if (ve == null)
continue;
Apply(ve);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static object Convert(object target, object value, BindableProperty property)
{
Func<MemberInfo> minforetriever = () => property.DeclaringType.GetRuntimeProperty(property.PropertyName) as MemberInfo
?? property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new[] { typeof(BindableObject) }) as MemberInfo;
var serviceProvider = new StyleSheetServiceProvider(target, property);
return value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);
}
public void UnApply(IStylable styleable)
{
throw new NotImplementedException();
}
}
}

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

@ -0,0 +1,22 @@
using System;
namespace Xamarin.Forms.StyleSheets
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)]
sealed class StylePropertyAttribute : Attribute
{
public string CssPropertyName { get; }
public string BindablePropertyName { get; }
public Type TargetType { get; }
public Type PropertyOwnerType { get; set; }
public BindableProperty BindableProperty { get; set; }
public StylePropertyAttribute(string cssPropertyName, Type targetType, string bindablePropertyName)
{
CssPropertyName = cssPropertyName;
BindablePropertyName = bindablePropertyName;
TargetType = targetType;
}
}
}

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

@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Xml;
using Xamarin.Forms.Xaml;
namespace Xamarin.Forms.StyleSheets
{
public sealed class StyleSheet : IStyle
{
StyleSheet()
{
}
internal IDictionary<Selector, Style> Styles { get; set; } = new Dictionary<Selector, Style>();
public static StyleSheet FromAssemblyResource(Assembly assembly, string resourceId, IXmlLineInfo lineInfo = null)
{
using (var stream = assembly.GetManifestResourceStream(resourceId)) {
if (stream == null)
throw new XamlParseException($"No resource found for '{resourceId}'.", lineInfo);
using (var reader = new StreamReader(stream)) {
return FromReader(reader);
}
}
}
//used by code generated by XamlC. Has to stay public
[EditorBrowsable(EditorBrowsableState.Never)]
public static StyleSheet FromString(string stylesheet)
{
if (stylesheet == null)
throw new ArgumentNullException(nameof(stylesheet));
using (var reader = new StringReader(stylesheet))
return FromReader(reader);
}
public static StyleSheet FromReader(TextReader reader)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
return Parse(new CssReader(reader));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static StyleSheet Parse(CssReader reader)
{
var sheet = new StyleSheet();
Style style = null;
var selector = Selector.All;
int p;
bool inStyle = false;
reader.SkipWhiteSpaces();
while ((p = reader.Peek()) > 0) {
switch ((char)p) {
case '@':
throw new NotSupportedException("AT-rules not supported");
case '{':
reader.Read();
style = Style.Parse(reader, '}');
inStyle = true;
break;
case '}':
reader.Read();
if (!inStyle)
throw new Exception();
inStyle = false;
sheet.Styles.Add(selector, style);
style = null;
selector = Selector.All;
break;
default:
selector = Selector.Parse(reader, '{');
break;
}
}
return sheet;
}
Type IStyle.TargetType
=> typeof(VisualElement);
void IStyle.Apply(BindableObject bindable)
{
var styleable = bindable as VisualElement;
if (styleable == null)
return;
Apply(styleable);
}
void Apply(VisualElement styleable)
{
ApplyCore(styleable);
foreach (var child in styleable.LogicalChildrenInternal)
((IStyle)this).Apply(child);
}
void ApplyCore(VisualElement styleable)
{
foreach (var kvp in Styles) {
var selector = kvp.Key;
var style = kvp.Value;
if (!selector.Matches(styleable))
continue;
style.Apply(styleable);
}
}
void IStyle.UnApply(BindableObject bindable)
{
throw new NotImplementedException();
}
}
}

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

@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace Xamarin.Forms.StyleSheets
{
static class StyleSheetExtensions
{
public static IEnumerable<StyleSheet> GetStyleSheets(this IResourcesProvider resourcesProvider)
{
if (!resourcesProvider.IsResourcesCreated)
yield break;
if (resourcesProvider.Resources.StyleSheets == null)
yield break;
foreach (var styleSheet in resourcesProvider.Resources.StyleSheets)
yield return styleSheet;
}
}
}

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

@ -0,0 +1,39 @@
using System;
using Xamarin.Forms.Xaml;
namespace Xamarin.Forms.StyleSheets
{
class StyleSheetServiceProvider : IServiceProvider
{
IProvideValueTarget vtProvider;
IConverterOptions convOptions => new ConverterOptions();
public StyleSheetServiceProvider(object targetObject, object targetProperty)
{
vtProvider = new ValueTargetProvider {
TargetObject = targetObject,
TargetProperty = targetProperty
};
}
public object GetService(Type serviceType)
{
if (serviceType == typeof(IProvideValueTarget))
return vtProvider;
if (serviceType == typeof(IConverterOptions))
return convOptions;
return null;
}
class ValueTargetProvider : IProvideValueTarget
{
public object TargetObject { get; set; }
public object TargetProperty { get; set; }
}
class ConverterOptions : IConverterOptions
{
public bool IgnoreCase => true;
}
}
}

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

@ -0,0 +1,76 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace Xamarin.Forms.StyleSheets
{
static class TextReaderExtensions
{
//ident [-]?{nmstart}{nmchar}*
public static string ReadIdent(this TextReader reader)
{
var sb = new StringBuilder();
bool first = true;
bool hasLeadingDash = false;
int p;
while ((p = reader.Peek()) > 0) {
var c = unchecked((char)p);
if (first && !hasLeadingDash && c == '-') {
sb.Append((char)reader.Read());
hasLeadingDash = true;
} else if (first && c.IsNmStart()) {
sb.Append((char)reader.Read());
first = false;
} else if (first) { //a nmstart is expected
throw new Exception();
} else if (c.IsNmChar())
sb.Append((char)reader.Read());
else
break;
}
return sb.ToString();
}
//name {nmchar}+
public static string ReadName(this TextReader reader)
{
var sb = new StringBuilder();
int p;
while ((p = reader.Peek()) > 0) {
var c = unchecked((char)p);
if (c.IsNmChar())
sb.Append((char)reader.Read());
else
break;
}
return sb.ToString();
}
public static string ReadUntil(this TextReader reader, params char[] limit)
{
var sb = new StringBuilder();
int p;
while ((p = reader.Peek()) > 0) {
var c = unchecked((char)p);
if (limit != null && limit.Contains(c))
break;
reader.Read();
sb.Append(c);
}
return sb.ToString();
}
//w [ \t\r\n\f]*
public static void SkipWhiteSpaces(this TextReader reader)
{
int p;
while ((p = reader.Peek()) > 0) {
var c = unchecked((char)p);
if (!c.IsW())
break;
reader.Read();
}
}
}
}

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

@ -1,9 +1,32 @@
using System;
namespace Xamarin.Forms
{
[TypeConverter(typeof(TextAlignmentConverter))]
public enum TextAlignment
{
Start,
Center,
End
}
[Xaml.TypeConversion(typeof(TextAlignment))]
public class TextAlignmentConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (value != null) {
if (Enum.TryParse(value, out TextAlignment direction))
return direction;
if (value.Equals("left", StringComparison.OrdinalIgnoreCase))
return TextAlignment.Start;
if (value.Equals("right", StringComparison.OrdinalIgnoreCase))
return TextAlignment.End;
if (value.Equals("center", StringComparison.OrdinalIgnoreCase))
return TextAlignment.Center;
}
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(TextAlignment)));
}
}
}

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

@ -3,7 +3,7 @@ namespace Xamarin.Forms
static class TextElement
{
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create("TextColor", typeof(Color), typeof(ITextElement), Color.Default,
BindableProperty.Create(nameof(ITextElement.TextColor), typeof(Color), typeof(ITextElement), Color.Default,
propertyChanged: OnTextColorPropertyChanged);
static void OnTextColorPropertyChanged(BindableObject bindable, object oldValue, object newValue)

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

@ -9,25 +9,51 @@ namespace Xamarin.Forms
{
public override object ConvertFromInvariantString(string value)
{
if (value != null)
{
double l, t, r, b;
string[] thickness = value.Split(',');
switch (thickness.Length)
{
case 1:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l))
return new Thickness(l);
break;
if (value != null) {
value = value.Trim();
if (value.Contains(",")) { //Xaml
var thickness = value.Split(',');
switch (thickness.Length) {
case 2:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l) && double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out t))
return new Thickness(l, t);
if ( double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double h)
&& double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out double v))
return new Thickness(h, v);
break;
case 4:
if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l) && double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out t) &&
double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out r) && double.TryParse(thickness[3], NumberStyles.Number, CultureInfo.InvariantCulture, out b))
if ( double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double l)
&& double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out double t)
&& double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out double r)
&& double.TryParse(thickness[3], NumberStyles.Number, CultureInfo.InvariantCulture, out double b))
return new Thickness(l, t, r, b);
break;
}
}
else if (value.Contains(" ")) { //CSS
var thickness = value.Split(' ');
switch (thickness.Length) {
case 2:
if ( double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double v)
&& double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out double h))
return new Thickness(h, v);
break;
case 3:
if ( double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double t)
&& double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out h)
&& double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out double b))
return new Thickness(h, t, h, b);
break;
case 4:
if ( double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out t)
&& double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out double r)
&& double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out b)
&& double.TryParse(thickness[3], NumberStyles.Number, CultureInfo.InvariantCulture, out double l))
return new Thickness(l, t, r, b);
break;
}
}
else { //single uniform thickness
if (double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out double l))
return new Thickness(l);
}
}

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

@ -216,6 +216,7 @@ namespace Xamarin.Forms
get { return (bool)GetValue(IsFocusedProperty); }
}
[TypeConverter(typeof(VisibilityConverter))]
public bool IsVisible
{
get { return (bool)GetValue(IsVisibleProperty); }
@ -650,6 +651,7 @@ namespace Xamarin.Forms
#pragma warning restore 0618
FlowController.NotifyFlowDirectionChanged();
ApplyStyleSheetsOnParentSet();
}
protected virtual void OnSizeAllocated(double width, double height)
@ -727,6 +729,22 @@ namespace Xamarin.Forms
InvalidateMeasureInternal(InvalidationTrigger.Undefined);
}
internal override void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
{
if (e == ResourcesChangedEventArgs.StyleSheets)
ApplyStyleSheetsOnParentSet();
else
base.OnParentResourcesChanged(sender, e);
}
internal override void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
{
if (e == ResourcesChangedEventArgs.StyleSheets)
ApplyStyleSheets();
else
base.OnResourcesChanged(sender, e);
}
internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
{
if (values == null)
@ -854,5 +872,26 @@ namespace Xamarin.Forms
public bool Result { get; set; }
}
public class VisibilityConverter : TypeConverter
{
public override object ConvertFromInvariantString(string value)
{
if (value != null) {
if (value.Equals("true", StringComparison.OrdinalIgnoreCase))
return true;
if (value.Equals("visible", StringComparison.OrdinalIgnoreCase))
return true;
if (value.Equals("false", StringComparison.OrdinalIgnoreCase))
return false;
if (value.Equals("hidden", StringComparison.OrdinalIgnoreCase))
return false;
if (value.Equals("collapse", StringComparison.OrdinalIgnoreCase))
return false;
}
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(bool)));
}
}
}
}
}

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

@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Reflection;
using Xamarin.Forms.Internals;
using Xamarin.Forms.StyleSheets;
namespace Xamarin.Forms
{
public partial class VisualElement : IStyleSelectable, IStylable
{
IList<string> IStyleSelectable.Classes
=> StyleClass;
BindableProperty IStylable.GetProperty(string key)
{
StylePropertyAttribute styleAttribute;
if (!Internals.Registrar.StyleProperties.TryGetValue(key, out styleAttribute))
return null;
if (!styleAttribute.TargetType.GetTypeInfo().IsAssignableFrom(GetType().GetTypeInfo()))
return null;
if (styleAttribute.BindableProperty != null)
return styleAttribute.BindableProperty;
var propertyOwnerType = styleAttribute.PropertyOwnerType ?? GetType();
var bpField = propertyOwnerType.GetField(styleAttribute.BindablePropertyName,
BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.FlattenHierarchy);
if (bpField == null)
return null;
return (styleAttribute.BindableProperty = bpField.GetValue(null) as BindableProperty);
}
void ApplyStyleSheets()
{
foreach (var styleSheet in this.GetStyleSheets())
((IStyle)styleSheet).Apply(this);
}
//on parent set, or on parent stylesheet changed, reapply all
void ApplyStyleSheetsOnParentSet()
{
var parent = Parent;
if (parent == null)
return;
var sheets = new List<StyleSheet>();
while (parent != null) {
var visualParent = parent as VisualElement;
var vpSheets = visualParent?.GetStyleSheets();
if (vpSheets != null)
sheets.AddRange(vpSheets);
parent = parent.Parent;
}
for (var i = sheets.Count - 1; i >= 0; i--)
((IStyle)sheets[i]).Apply(this);
}
}
}

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

@ -1,11 +1,13 @@
using System;
using System.Reflection;
using System.Xml;
using System.IO;
namespace Xamarin.Forms
{
interface IResourcesLoader
{
ResourceDictionary CreateResourceDictionary(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo);
T CreateFromResource<T>(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo) where T : new();
string GetResource(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo);
}
}

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

@ -124,6 +124,7 @@ namespace Xamarin.Forms.Xaml
if (convertFromStringInvariant != null)
return value = convertFromStringInvariant.Invoke(converter, new object[] { str });
}
var ignoreCase = (serviceProvider?.GetService(typeof(IConverterOptions)) as IConverterOptions)?.IgnoreCase ?? false;
//If the type is nullable, as the value is not null, it's safe to assume we want the built-in conversion
if (toType.GetTypeInfo().IsGenericType && toType.GetGenericTypeDefinition() == typeof (Nullable<>))
@ -131,7 +132,7 @@ namespace Xamarin.Forms.Xaml
//Obvious Built-in conversions
if (toType.GetTypeInfo().IsEnum)
return Enum.Parse(toType, str);
return Enum.Parse(toType, str, ignoreCase);
if (toType == typeof(SByte))
return SByte.Parse(str, CultureInfo.InvariantCulture);
if (toType == typeof(Int16))

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

@ -201,7 +201,7 @@ namespace Xamarin.Forms.Platform.Android
paint.StrokeWidth = 1;
paint.SetStyle(style);
paint.Color = _frame.OutlineColor.ToAndroid();
paint.Color = _frame.BorderColor.ToAndroid();
canvas.DrawPath(path, paint);
}
@ -209,9 +209,9 @@ namespace Xamarin.Forms.Platform.Android
void FrameOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName ||
e.PropertyName == Frame.OutlineColorProperty.PropertyName ||
e.PropertyName == Frame.CornerRadiusProperty.PropertyName)
if ( e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName
|| e.PropertyName == Frame.BorderColorProperty.PropertyName
|| e.PropertyName == Frame.CornerRadiusProperty.PropertyName)
{
if(_normalBitmap == null)
return;

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

@ -19,7 +19,7 @@ namespace Xamarin.Forms.Platform.MacOS
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Frame.OutlineColorProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Frame.BorderColorProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Frame.HasShadowProperty.PropertyName)
SetupLayer();
}
@ -42,11 +42,11 @@ namespace Xamarin.Forms.Platform.MacOS
else
Layer.ShadowOpacity = 0;
if (Element.OutlineColor == Color.Default)
if (Element.BorderColor == Color.Default)
Layer.BorderColor = NSColor.Clear.CGColor;
else
{
Layer.BorderColor = Element.OutlineColor.ToCGColor();
Layer.BorderColor = Element.BorderColor.ToCGColor();
Layer.BorderWidth = 1;
}

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

@ -46,7 +46,7 @@ namespace Xamarin.Forms.Platform.UWP
{
PackChild();
}
else if (e.PropertyName == Frame.OutlineColorProperty.PropertyName || e.PropertyName == Frame.HasShadowProperty.PropertyName)
else if (e.PropertyName == Frame.BorderColorProperty.PropertyName || e.PropertyName == Frame.HasShadowProperty.PropertyName)
{
UpdateBorder();
}
@ -67,9 +67,9 @@ namespace Xamarin.Forms.Platform.UWP
void UpdateBorder()
{
if (Element.OutlineColor != Color.Default)
if (Element.BorderColor != Color.Default)
{
Control.BorderBrush = Element.OutlineColor.ToBrush();
Control.BorderBrush = Element.BorderColor.ToBrush();
Control.BorderThickness = new Windows.UI.Xaml.Thickness(1);
}
else

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

@ -19,7 +19,7 @@ namespace Xamarin.Forms.Platform.iOS
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Frame.OutlineColorProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Frame.BorderColorProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Frame.HasShadowProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Frame.CornerRadiusProperty.PropertyName)
SetupLayer();
@ -49,11 +49,11 @@ namespace Xamarin.Forms.Platform.iOS
else
Layer.ShadowOpacity = 0;
if (Element.OutlineColor == Color.Default)
if (Element.BorderColor == Color.Default)
Layer.BorderColor = UIColor.Clear.CGColor;
else
{
Layer.BorderColor = Element.OutlineColor.ToCGColor();
Layer.BorderColor = Element.BorderColor.ToCGColor();
Layer.BorderWidth = 1;
}

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

@ -0,0 +1,23 @@
<?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.InlineCSS">
<ContentPage.Resources>
<StyleSheet>
<![CDATA[
* {
background-color: green;
}
label {
color: pink;
background-color: initial;
}
]]>
</StyleSheet>
</ContentPage.Resources>
<StackLayout x:Name="stack">
<Label x:Name="label"/>
<Button x:Name="button"/>
</StackLayout>
</ContentPage>

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

@ -0,0 +1,53 @@
using System;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class InlineCSS : ContentPage
{
public InlineCSS()
{
InitializeComponent();
}
public InlineCSS(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
public class Tests
{
[SetUp]
public void SetUp()
{
Device.PlatformServices = new MockPlatformServices();
Xamarin.Forms.Internals.Registrar.RegisterAll(new Type[0]);
}
[TearDown]
public void TearDown()
{
Device.PlatformServices = null;
}
[TestCase(false), TestCase(true)]
public void InlineCSSParsed(bool useCompiledXaml)
{
var layout = new InlineCSS(useCompiledXaml);
Assert.That(layout.label.TextColor, Is.EqualTo(Color.Pink));
}
[TestCase(false), TestCase(true)]
public void InitialValue(bool useCompiledXaml)
{
var layout = new InlineCSS(useCompiledXaml);
Assert.That(layout.BackgroundColor, Is.EqualTo(Color.Green));
Assert.That(layout.stack.BackgroundColor, Is.EqualTo(Color.Green));
Assert.That(layout.button.BackgroundColor, Is.EqualTo(Color.Green));
Assert.That(layout.label.BackgroundColor, Is.EqualTo(VisualElement.BackgroundColorProperty.DefaultValue));
}
}
}
}

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

@ -0,0 +1,11 @@
<?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.SetStyleIdFromXName">
<StackLayout>
<Label x:Name="label0" />
<Label x:Name="label1" StyleId="foo" />
<Label StyleId="bar" x:Name="label2" />
</StackLayout>
</ContentPage>

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

@ -0,0 +1,44 @@
using System;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class SetStyleIdFromXName : ContentPage
{
public SetStyleIdFromXName()
{
InitializeComponent();
}
public SetStyleIdFromXName(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
public class Tests
{
[SetUp]
public void Setup()
{
Device.PlatformServices = new MockPlatformServices();
}
[TearDown]
public void TearDown()
{
Device.PlatformServices = null;
}
[TestCase(false), TestCase(true)]
public void SetStyleId(bool useCompiledXaml)
{
var layout = new SetStyleIdFromXName(useCompiledXaml);
Assert.That(layout.label0.StyleId, Is.EqualTo("label0"));
Assert.That(layout.label1.StyleId, Is.EqualTo("foo"));
Assert.That(layout.label2.StyleId, Is.EqualTo("bar"));
}
}
}
}

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

@ -0,0 +1,12 @@
<?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.StyleSheet">
<ContentPage.Resources>
<StyleSheet Source="css/foo.css" />
</ContentPage.Resources>
<StackLayout>
<Label x:Name="label0" />
</StackLayout>
</ContentPage>

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

@ -0,0 +1,47 @@
using System;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
using NUnit.Framework.Constraints;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class StyleSheet : ContentPage
{
public StyleSheet()
{
InitializeComponent();
}
public StyleSheet(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
public class Tests
{
[SetUp]
public void SetUp()
{
Device.PlatformServices = new MockPlatformServices();
Xamarin.Forms.Internals.Registrar.RegisterAll(new Type[0]);
}
[TestCase(false), TestCase(true)]
public void EmbeddedStyleSheetsAreLoaded(bool useCompiledXaml)
{
var layout = new StyleSheet(useCompiledXaml);
Assert.That(layout.Resources.StyleSheets[0].Styles.Count, Is.GreaterThanOrEqualTo(1));
}
[TestCase(false), TestCase(true)]
public void StyleSheetsAreApplied(bool useCompiledXaml)
{
var layout = new StyleSheet(useCompiledXaml);
Assert.That(layout.label0.TextColor, Is.EqualTo(Color.Azure));
Assert.That(layout.label0.BackgroundColor, Is.EqualTo(Color.AliceBlue));
}
}
}
}

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

@ -463,7 +463,6 @@
</Compile>
<Compile Include="Issues\Bz44216.xaml.cs">
<DependentUpon>Bz44216.xaml</DependentUpon>
<DependentUpon>AcceptEmptyServiceProvider.xaml</DependentUpon>
</Compile>
<Compile Include="AcceptEmptyServiceProvider.xaml.cs">
<DependentUpon>AcceptEmptyServiceProvider.xaml</DependentUpon>
@ -553,6 +552,15 @@
<Compile Include="Issues\Gh1346.xaml.cs">
<DependentUpon>Gh1346.xaml</DependentUpon>
</Compile>
<Compile Include="StyleSheet.xaml.cs">
<DependentUpon>StyleSheet.xaml</DependentUpon>
</Compile>
<Compile Include="SetStyleIdFromXName.xaml.cs">
<DependentUpon>SetStyleIdFromXName.xaml</DependentUpon>
</Compile>
<Compile Include="InlineCSS.xaml.cs">
<DependentUpon>InlineCSS.xaml</DependentUpon>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
@ -582,15 +590,6 @@
<Name>Xamarin.Forms.Maps</Name>
</ProjectReference>
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>
<Properties>
<Policies>
<StandardHeader Text="" IncludeInNewFiles="True" />
</Policies>
</Properties>
</MonoDevelop>
</ProjectExtensions>
<ItemGroup>
<EmbeddedResource Include="CustomXamlView.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
@ -1011,24 +1010,39 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="css\foo.css" />
<EmbeddedResource Include="css\bar.css" />
<EmbeddedResource Include="StyleSheet.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="Issues\Bz41296.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="PlatformSpecifics.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Issues\Bz43450.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="AutomationProperties.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="SetStyleIdFromXName.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="InlineCSS.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="css\" />
</ItemGroup>
<ItemGroup />
</Project>
</Project>

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

@ -0,0 +1 @@


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

@ -0,0 +1,4 @@
label {
color: azure;
background-color: aliceblue;
}

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

@ -602,6 +602,8 @@ namespace Xamarin.Forms.Xaml
resourceDictionary.Add((Style)value);
else if (value is ResourceDictionary)
resourceDictionary.Add((ResourceDictionary)value);
else if (value is StyleSheets.StyleSheet)
resourceDictionary.Add((StyleSheets.StyleSheet)value);
else {
exception = new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
return false;

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

@ -0,0 +1,48 @@
using System;
using System.Xml;
using Xamarin.Forms.StyleSheets;
using System.Reflection;
using System.IO;
namespace Xamarin.Forms.Xaml
{
[ContentProperty(nameof(Style))]
[ProvideCompiled("Xamarin.Forms.Core.XamlC.StyleSheetProvider")]
public sealed class StyleSheetExtension : IValueProvider
{
public string Style { get; set; }
public Uri Source { get; set; }
object IValueProvider.ProvideValue(IServiceProvider serviceProvider)
{
IXmlLineInfo lineInfo;
if (!string.IsNullOrEmpty(Style) && Source != null) {
lineInfo = (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider)?.XmlLineInfo;
throw new XamlParseException($"StyleSheet can not have both a Source and a content", lineInfo);
}
if (Source != null) {
lineInfo = (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider)?.XmlLineInfo;
if (Source.IsAbsoluteUri)
throw new XamlParseException($"Source only accepts Relative URIs", lineInfo);
var rootObjectType = (serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider)?.RootObject.GetType();
if (rootObjectType == null)
return null;
var rootTargetPath = XamlResourceIdAttribute.GetPathForType(rootObjectType);
var resourcePath = ResourceDictionary.RDSourceTypeConverter.GetResourcePath(Source, rootTargetPath);
var resString = DependencyService.Get<IResourcesLoader>().GetResource(resourcePath, rootObjectType.GetTypeInfo().Assembly, lineInfo);
return StyleSheet.FromString(resString);
}
if (!string.IsNullOrEmpty(Style)) {
using (var reader = new StringReader(Style))
return StyleSheet.FromReader(reader);
}
lineInfo = (serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider)?.XmlLineInfo;
throw new XamlParseException($"StyleSheet require either a Source or a content", lineInfo);
}
}
}

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

@ -31,6 +31,9 @@ namespace Xamarin.Forms.Xaml
throw ae;
throw new XamlParseException($"An element with the name \"{(string)node.Value}\" already exists in this NameScope", node);
}
var element = Values[parentNode] as Element;
if (element != null)
element.StyleId = element.StyleId ?? (string)node.Value;
}
public void Visit(MarkupNode node, INode parentNode)

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

@ -9,7 +9,7 @@ namespace Xamarin.Forms.Xaml
{
class ResourcesLoader : IResourcesLoader
{
public ResourceDictionary CreateResourceDictionary(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo)
public T CreateFromResource<T>(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo) where T: new()
{
var resourceId = XamlResourceIdAttribute.GetResourceIdForPath(assembly, resourcePath);
if (resourceId == null)
@ -17,7 +17,7 @@ namespace Xamarin.Forms.Xaml
var alternateResource = Xamarin.Forms.Internals.ResourceLoader.ResourceProvider?.Invoke(resourcePath);
if (alternateResource != null) {
var rd = new ResourceDictionary();
var rd = new T();
rd.LoadFromXaml(alternateResource);
return rd;
}
@ -26,11 +26,29 @@ namespace Xamarin.Forms.Xaml
if (stream == null)
throw new XamlParseException($"No resource found for '{resourceId}'.", lineInfo);
using (var reader = new StreamReader(stream)) {
var rd = new ResourceDictionary();
var rd = new T();
rd.LoadFromXaml(reader.ReadToEnd());
return rd;
}
}
}
public string GetResource(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo)
{
var resourceId = XamlResourceIdAttribute.GetResourceIdForPath(assembly, resourcePath);
if (resourceId == null)
throw new XamlParseException($"Resource '{resourcePath}' not found.", lineInfo);
var alternateResource = Xamarin.Forms.Internals.ResourceLoader.ResourceProvider?.Invoke(resourcePath);
if (alternateResource != null)
return alternateResource;
using (var stream = assembly.GetManifestResourceStream(resourceId)) {
if (stream == null)
throw new XamlParseException($"No resource found for '{resourceId}'.", lineInfo);
using (var reader = new StreamReader(stream))
return reader.ReadToEnd();
}
}
}
}

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

@ -35,6 +35,21 @@
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="StyleSheets">
<MemberSignature Language="C#" Value="public static readonly Xamarin.Forms.Internals.ResourcesChangedEventArgs StyleSheets;" />
<MemberSignature Language="ILAsm" Value=".field public static initonly class Xamarin.Forms.Internals.ResourcesChangedEventArgs StyleSheets" />
<MemberType>Field</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Forms.Internals.ResourcesChangedEventArgs</ReturnType>
</ReturnValue>
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="Values">
<MemberSignature Language="C#" Value="public System.Collections.Generic.IEnumerable&lt;System.Collections.Generic.KeyValuePair&lt;string,object&gt;&gt; Values { get; }" />
<MemberSignature Language="ILAsm" Value=".property instance class System.Collections.Generic.IEnumerable`1&lt;valuetype System.Collections.Generic.KeyValuePair`2&lt;string, object&gt;&gt; Values" />

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

@ -0,0 +1,87 @@
<Type Name="StyleSheet" FullName="Xamarin.Forms.StyleSheets.StyleSheet">
<TypeSignature Language="C#" Value="public sealed class StyleSheet" />
<TypeSignature Language="ILAsm" Value=".class public auto ansi sealed beforefieldinit StyleSheet extends System.Object" />
<AssemblyInfo>
<AssemblyName>Xamarin.Forms.Core</AssemblyName>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>System.Object</BaseTypeName>
</Base>
<Interfaces />
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
<Members>
<Member MemberName="FromAssemblyResource">
<MemberSignature Language="C#" Value="public static Xamarin.Forms.StyleSheets.StyleSheet FromAssemblyResource (System.Reflection.Assembly assembly, string resourceId, System.Xml.IXmlLineInfo lineInfo = null);" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig class Xamarin.Forms.StyleSheets.StyleSheet FromAssemblyResource(class System.Reflection.Assembly assembly, string resourceId, class System.Xml.IXmlLineInfo lineInfo) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Forms.StyleSheets.StyleSheet</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="assembly" Type="System.Reflection.Assembly" />
<Parameter Name="resourceId" Type="System.String" />
<Parameter Name="lineInfo" Type="System.Xml.IXmlLineInfo" />
</Parameters>
<Docs>
<param name="assembly">To be added.</param>
<param name="resourceId">To be added.</param>
<param name="lineInfo">To be added.</param>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="FromReader">
<MemberSignature Language="C#" Value="public static Xamarin.Forms.StyleSheets.StyleSheet FromReader (System.IO.TextReader reader);" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig class Xamarin.Forms.StyleSheets.StyleSheet FromReader(class System.IO.TextReader reader) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Forms.StyleSheets.StyleSheet</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="reader" Type="System.IO.TextReader" />
</Parameters>
<Docs>
<param name="reader">To be added.</param>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="FromString">
<MemberSignature Language="C#" Value="public static Xamarin.Forms.StyleSheets.StyleSheet FromString (string stylesheet);" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig class Xamarin.Forms.StyleSheets.StyleSheet FromString(string stylesheet) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Attributes>
<Attribute>
<AttributeName>System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)</AttributeName>
</Attribute>
</Attributes>
<ReturnValue>
<ReturnType>Xamarin.Forms.StyleSheets.StyleSheet</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="stylesheet" Type="System.String" />
</Parameters>
<Docs>
<param name="stylesheet">To be added.</param>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
</Docs>
</Member>
</Members>
</Type>

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

@ -8,6 +8,11 @@
<Base>
<BaseTypeName>System.Enum</BaseTypeName>
</Base>
<Attributes>
<Attribute>
<AttributeName>Xamarin.Forms.TypeConverter(typeof(Xamarin.Forms.FlowDirectionConverter))</AttributeName>
</Attribute>
</Attributes>
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>

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

@ -0,0 +1,56 @@
<Type Name="FlowDirectionConverter" FullName="Xamarin.Forms.FlowDirectionConverter">
<TypeSignature Language="C#" Value="public class FlowDirectionConverter : Xamarin.Forms.TypeConverter" />
<TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit FlowDirectionConverter extends Xamarin.Forms.TypeConverter" />
<AssemblyInfo>
<AssemblyName>Xamarin.Forms.Core</AssemblyName>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>Xamarin.Forms.TypeConverter</BaseTypeName>
</Base>
<Interfaces />
<Attributes>
<Attribute>
<AttributeName>Xamarin.Forms.Xaml.TypeConversion(typeof(Xamarin.Forms.FlowDirection))</AttributeName>
</Attribute>
</Attributes>
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
<Members>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public FlowDirectionConverter ();" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
<MemberType>Constructor</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Parameters />
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="ConvertFromInvariantString">
<MemberSignature Language="C#" Value="public override object ConvertFromInvariantString (string value);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig virtual instance object ConvertFromInvariantString(string value) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Object</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="value" Type="System.String" />
</Parameters>
<Docs>
<param name="value">To be added.</param>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
</Docs>
</Member>
</Members>
</Type>

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

@ -91,6 +91,37 @@ MainPage = new ContentPage () {
<remarks>A Frame has a default <see cref="P:Xamarin.Forms.Layout.Padding" /> of 20.</remarks>
</Docs>
</Member>
<Member MemberName="BorderColor">
<MemberSignature Language="C#" Value="public Xamarin.Forms.Color BorderColor { get; set; }" />
<MemberSignature Language="ILAsm" Value=".property instance valuetype Xamarin.Forms.Color BorderColor" />
<MemberType>Property</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Forms.Color</ReturnType>
</ReturnValue>
<Docs>
<summary>To be added.</summary>
<value>To be added.</value>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="BorderColorProperty">
<MemberSignature Language="C#" Value="public static readonly Xamarin.Forms.BindableProperty BorderColorProperty;" />
<MemberSignature Language="ILAsm" Value=".field public static initonly class Xamarin.Forms.BindableProperty BorderColorProperty" />
<MemberType>Field</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Forms.BindableProperty</ReturnType>
</ReturnValue>
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="CornerRadius">
<MemberSignature Language="C#" Value="public float CornerRadius { get; set; }" />
<MemberSignature Language="ILAsm" Value=".property instance float32 CornerRadius" />
@ -205,6 +236,11 @@ MainPage = new ContentPage () {
<AssemblyVersion>1.5.0.0</AssemblyVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Attributes>
<Attribute>
<AttributeName>System.Obsolete("OutlineColor is obsolete as of version 3.0.0. Please use BorderColor instead.")</AttributeName>
</Attribute>
</Attributes>
<ReturnValue>
<ReturnType>Xamarin.Forms.Color</ReturnType>
</ReturnValue>
@ -228,6 +264,11 @@ MainPage = new ContentPage () {
<AssemblyVersion>1.5.0.0</AssemblyVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Attributes>
<Attribute>
<AttributeName>System.Obsolete("OutlineColorProperty is obsolete as of version 3.0.0. Please use BorderColorProperty instead.")</AttributeName>
</Attribute>
</Attributes>
<ReturnValue>
<ReturnType>Xamarin.Forms.BindableProperty</ReturnType>
</ReturnValue>

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

@ -97,6 +97,25 @@
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="Add">
<MemberSignature Language="C#" Value="public void Add (Xamarin.Forms.StyleSheets.StyleSheet styleSheet);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig instance void Add(class Xamarin.Forms.StyleSheets.StyleSheet styleSheet) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Void</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="styleSheet" Type="Xamarin.Forms.StyleSheets.StyleSheet" />
</Parameters>
<Docs>
<param name="styleSheet">To be added.</param>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="Add">
<MemberSignature Language="C#" Value="public void Add (string key, object value);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig newslot virtual instance void Add(string key, object value) cil managed" />

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

@ -14,6 +14,11 @@
<Base>
<BaseTypeName>System.Enum</BaseTypeName>
</Base>
<Attributes>
<Attribute>
<AttributeName>Xamarin.Forms.TypeConverter(typeof(Xamarin.Forms.TextAlignmentConverter))</AttributeName>
</Attribute>
</Attributes>
<Docs>
<summary>Enumerates values that control text alignment.</summary>
<remarks>To be added.</remarks>

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

@ -0,0 +1,56 @@
<Type Name="TextAlignmentConverter" FullName="Xamarin.Forms.TextAlignmentConverter">
<TypeSignature Language="C#" Value="public class TextAlignmentConverter : Xamarin.Forms.TypeConverter" />
<TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit TextAlignmentConverter extends Xamarin.Forms.TypeConverter" />
<AssemblyInfo>
<AssemblyName>Xamarin.Forms.Core</AssemblyName>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>Xamarin.Forms.TypeConverter</BaseTypeName>
</Base>
<Interfaces />
<Attributes>
<Attribute>
<AttributeName>Xamarin.Forms.Xaml.TypeConversion(typeof(Xamarin.Forms.TextAlignment))</AttributeName>
</Attribute>
</Attributes>
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
<Members>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public TextAlignmentConverter ();" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
<MemberType>Constructor</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Parameters />
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="ConvertFromInvariantString">
<MemberSignature Language="C#" Value="public override object ConvertFromInvariantString (string value);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig virtual instance object ConvertFromInvariantString(string value) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Object</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="value" Type="System.String" />
</Parameters>
<Docs>
<param name="value">To be added.</param>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
</Docs>
</Member>
</Members>
</Type>

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

@ -0,0 +1,51 @@
<Type Name="VisualElement+VisibilityConverter" FullName="Xamarin.Forms.VisualElement+VisibilityConverter">
<TypeSignature Language="C#" Value="public class VisualElement.VisibilityConverter : Xamarin.Forms.TypeConverter" />
<TypeSignature Language="ILAsm" Value=".class nested public auto ansi beforefieldinit VisualElement/VisibilityConverter extends Xamarin.Forms.TypeConverter" />
<AssemblyInfo>
<AssemblyName>Xamarin.Forms.Core</AssemblyName>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>Xamarin.Forms.TypeConverter</BaseTypeName>
</Base>
<Interfaces />
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
<Members>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public VisibilityConverter ();" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
<MemberType>Constructor</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Parameters />
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="ConvertFromInvariantString">
<MemberSignature Language="C#" Value="public override object ConvertFromInvariantString (string value);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig virtual instance object ConvertFromInvariantString(string value) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Object</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="value" Type="System.String" />
</Parameters>
<Docs>
<param name="value">To be added.</param>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
</Docs>
</Member>
</Members>
</Type>

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

@ -880,6 +880,11 @@
<AssemblyVersion>1.5.0.0</AssemblyVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Attributes>
<Attribute>
<AttributeName>Xamarin.Forms.TypeConverter(typeof(Xamarin.Forms.VisualElement/VisibilityConverter))</AttributeName>
</Attribute>
</Attributes>
<ReturnValue>
<ReturnType>System.Boolean</ReturnType>
</ReturnValue>

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

@ -213,6 +213,7 @@
<Type Name="FileImageSource" Kind="Class" />
<Type Name="FileImageSourceConverter" Kind="Class" />
<Type Name="FlowDirection" Kind="Enumeration" />
<Type Name="FlowDirectionConverter" Kind="Class" />
<Type Name="FocusEventArgs" Kind="Class" />
<Type Name="Font" Kind="Structure" />
<Type Name="FontAttributes" Kind="Enumeration" />
@ -397,6 +398,7 @@
<Type Name="TemplatedView" Kind="Class" />
<Type Name="TemplateExtensions" Kind="Class" />
<Type Name="TextAlignment" Kind="Enumeration" />
<Type Name="TextAlignmentConverter" Kind="Class" />
<Type Name="TextCell" Kind="Class" />
<Type Name="TextChangedEventArgs" Kind="Class" />
<Type Name="Thickness" Kind="Structure" />
@ -424,6 +426,7 @@
<Type Name="ViewState" Kind="Enumeration" />
<Type Name="VisualElement" Kind="Class" />
<Type Name="VisualElement+FocusRequestArgs" Kind="Class" />
<Type Name="VisualElement+VisibilityConverter" Kind="Class" />
<Type Name="WebNavigatedEventArgs" Kind="Class" />
<Type Name="WebNavigatingEventArgs" Kind="Class" />
<Type Name="WebNavigationEvent" Kind="Enumeration" />
@ -555,6 +558,9 @@
<Type Name="Page" Kind="Class" />
<Type Name="ToolbarPlacement" Kind="Enumeration" />
</Namespace>
<Namespace Name="Xamarin.Forms.StyleSheets">
<Type Name="StyleSheet" Kind="Class" />
</Namespace>
<Namespace Name="Xamarin.Forms.Xaml">
<Type Name="AcceptEmptyServiceProviderAttribute" Kind="Class" />
<Type Name="IMarkupExtension" Kind="Interface" />

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

@ -0,0 +1,6 @@
<Namespace Name="Xamarin.Forms.StyleSheets">
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Namespace>

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

@ -0,0 +1,95 @@
<Type Name="StyleSheetExtension" FullName="Xamarin.Forms.Xaml.StyleSheetExtension">
<TypeSignature Language="C#" Value="public sealed class StyleSheetExtension : Xamarin.Forms.Xaml.IValueProvider" />
<TypeSignature Language="ILAsm" Value=".class public auto ansi sealed beforefieldinit StyleSheetExtension extends System.Object implements class Xamarin.Forms.Xaml.IValueProvider" />
<AssemblyInfo>
<AssemblyName>Xamarin.Forms.Xaml</AssemblyName>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>System.Object</BaseTypeName>
</Base>
<Interfaces>
<Interface>
<InterfaceName>Xamarin.Forms.Xaml.IValueProvider</InterfaceName>
</Interface>
</Interfaces>
<Attributes>
<Attribute>
<AttributeName>Xamarin.Forms.ContentProperty("Style")</AttributeName>
</Attribute>
<Attribute>
<AttributeName>Xamarin.Forms.Xaml.ProvideCompiled("Xamarin.Forms.Core.XamlC.StyleSheetProvider")</AttributeName>
</Attribute>
</Attributes>
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
<Members>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public StyleSheetExtension ();" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
<MemberType>Constructor</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Parameters />
<Docs>
<summary>To be added.</summary>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="Source">
<MemberSignature Language="C#" Value="public Uri Source { get; set; }" />
<MemberSignature Language="ILAsm" Value=".property instance class System.Uri Source" />
<MemberType>Property</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Uri</ReturnType>
</ReturnValue>
<Docs>
<summary>To be added.</summary>
<value>To be added.</value>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="Style">
<MemberSignature Language="C#" Value="public string Style { get; set; }" />
<MemberSignature Language="ILAsm" Value=".property instance string Style" />
<MemberType>Property</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.String</ReturnType>
</ReturnValue>
<Docs>
<summary>To be added.</summary>
<value>To be added.</value>
<remarks>To be added.</remarks>
</Docs>
</Member>
<Member MemberName="Xamarin.Forms.Xaml.IValueProvider.ProvideValue">
<MemberSignature Language="C#" Value="object IValueProvider.ProvideValue (IServiceProvider serviceProvider);" />
<MemberSignature Language="ILAsm" Value=".method hidebysig newslot virtual instance object Xamarin.Forms.Xaml.IValueProvider.ProvideValue(class System.IServiceProvider serviceProvider) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Object</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="serviceProvider" Type="System.IServiceProvider" />
</Parameters>
<Docs>
<param name="serviceProvider">To be added.</param>
<summary>To be added.</summary>
<returns>To be added.</returns>
<remarks>To be added.</remarks>
</Docs>
</Member>
</Members>
</Type>

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

@ -80,6 +80,7 @@
<Type Name="ReferenceExtension" Kind="Class" />
<Type Name="StaticExtension" Kind="Class" />
<Type Name="StaticResourceExtension" Kind="Class" />
<Type Name="StyleSheetExtension" Kind="Class" />
<Type Name="TemplateBindingExtension" Kind="Class" />
<Type Name="TypeExtension" Kind="Class" />
<Type Name="XamlCompilationAttribute" Kind="Class" />