echo "Commands:"
echo " build [module] Build a specific module"
echo " full Build all modules in src/ directory"
+ echo " design Build NUI Design module"
+ echo " xamlbuild Build NUI XamlBuild module"
echo " dummy Generate dummy assemblies of all modules"
echo " pack [version] Make a NuGet package with build artifacts"
echo " install [target] Install assemblies to the target device"
else
dotnet sln $SLN_FILE remove $SCRIPT_DIR/src/*/*.Design.csproj
fi
+ if [ "$target" == "xamlbuild" ]; then
+ dotnet sln $SLN_FILE add $SCRIPT_DIR/src/*/*.XamlBuild.csproj
+ else
+ dotnet sln $SLN_FILE remove $SCRIPT_DIR/src/*/*.XamlBuild.csproj
+ fi
}
cleanup_solution() {
cleanup_solution
}
+cmd_xamlbuild_build() {
+ prepare_solution xamlbuild
+ restore $SLN_FILE
+ build $SLN_FILE $@
+ projects=$(dirname $(ls -1 $SCRIPT_DIR/src/*/*.XamlBuild.csproj))
+ for proj in $projects; do
+ if [ -d $proj/bin/$CONFIGURATION ]; then
+ cp -f $proj/bin/$CONFIGURATION/*/*.XamlBuild.dll $SCRIPT_DIR/pkg/Tizen.NET.API*/xamlbuild/
+ fi
+ done
+ cleanup_solution
+}
+
cmd_dummy_build() {
if [ ! -d $OUTDIR/bin/public/ref ]; then
echo "No assemblies to read. Build TizenFX first."
build|--build|-b) cmd_module_build $@ ;;
full |--full |-f) cmd_full_build $@ ;;
design|--design) cmd_design_build $@ ;;
+ xamlbuild|--xamlbuild) cmd_xamlbuild_build $@ ;;
dummy|--dummy|-d) cmd_dummy_build $@ ;;
pack |--pack |-p) cmd_pack $@ ;;
install |--install |-i) cmd_install $@ ;;
<files>
<file src="pkg\Tizen.NET.API10\build\**" target="build" />
<file src="pkg\Tizen.NET.API10\design\*.dll" target="ref\netstandard2.0\Design" />
+ <file src="pkg\Tizen.NET.API10\xamlbuild\**" target="buildTransitive" />
<file src="Artifacts\bin\dummy\*.dll" target="ref\netstandard2.0" />
<file src="Artifacts\bin\public\*.xml" target="ref\netstandard2.0" />
</files>
--- /dev/null
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <PropertyGroup>
+ <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageConflictPlatformManifests Include="$(MSBuildThisFileDirectory)tizen10.0\PlatformManifest.txt" />
+ </ItemGroup>
+
+ <ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
+ <Import Project="$(MSBuildThisFileDirectory)..\buildTransitive\Tizen.NUI.XamlBuild.props" Condition="Exists('$(MSBuildThisFileDirectory)..\buildTransitive\Tizen.NUI.XamlBuild.props')" />
+ </ImportGroup>
+</Project>
</PropertyGroup>
<ItemGroup>
- <Reference Include="$(MSBuildThisFileDirectory)\ref\*.dll">
+ <Reference Include="$(MSBuildThisFileDirectory)tizen10.0\ref\*.dll">
<Private>false</Private>
<Visible>false</Visible>
<NuGetPackageId>Microsoft.NETCore.App.Ref</NuGetPackageId>
</Reference>
</ItemGroup>
+ <ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
+ <Import Project="$(MSBuildThisFileDirectory)..\buildTransitive\Tizen.NUI.XamlBuild.targets" Condition="Exists('$(MSBuildThisFileDirectory)..\buildTransitive\Tizen.NUI.XamlBuild.targets')" />
+ </ImportGroup>
</Project>
\ No newline at end of file
+++ /dev/null
-<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-
- <PropertyGroup>
- <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageConflictPlatformManifests Include="$(MSBuildThisFileDirectory)PlatformManifest.txt" />
- </ItemGroup>
-
-</Project>
--- /dev/null
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <!--
+ When using Sdk-style projects and default embedded resource items are enabled, automatically
+ add the XAML files and fix up item metadata to pair them with code files.
+ This is in the props file, not the targets file, so that projects can remove/update these items.
+ The default value for EnableDefaultXamlItems is set in the targets, which works because
+ the property evaluation pass comes before the item evaluation pass.
+
+ The actual item groups are in a separate conditionally-imported file as they use constructs that
+ are not compatible with older MSBuild versions.
+ -->
+</Project>
--- /dev/null
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <UsingTask TaskName="Tizen.NUI.Xaml.Build.Tasks.XamlGTask" AssemblyFile="$(MSBuildThisFileDirectory)Tizen.NUI.XamlBuild.dll" />
+ <UsingTask TaskName="Tizen.NUI.Xaml.Build.Tasks.XamlCTask" AssemblyFile="$(MSBuildThisFileDirectory)Tizen.NUI.XamlBuild.dll" />
+
+ <!-- XamlG -->
+ <Target Name="UpdateDesignTimeXaml" DependsOnTargets="XamlG"/>
+
+ <PropertyGroup>
+ <CoreCompileDependsOn>
+ XamlG;
+ $(CoreCompileDependsOn);
+ </CoreCompileDependsOn>
+ </PropertyGroup>
+
+ <Target Name="_FindXamlGFiles" DependsOnTargets="PrepareResourceNames">
+ <ItemGroup>
+ <_XamlGInputs Include="@(EmbeddedResource)" Condition="'%(Extension)' == '.xaml' AND '$(DefaultLanguageSourceExtension)' == '.cs' AND '%(TargetPath)' != ''" />
+ <_XamlGOutputs Include="@(_XamlGInputs->'$(IntermediateOutputPath)%(TargetPath).g.cs')" />
+ </ItemGroup>
+ </Target>
+
+ <Target Name="XamlG" BeforeTargets="BeforeCompile" DependsOnTargets="_FindXamlGFiles; PrepareResourceNames; AfterResolveReferences" Inputs="@(_XamlGInputs)" Outputs="@(_XamlGOutputs)">
+ <XamlGTask
+ XamlFiles="@(_XamlGInputs)"
+ OutputFiles="@(_XamlGOutputs)"
+ Language="$(Language)"
+ AssemblyName="$(AssemblyName)"
+ ReferencePath="@(ReferencePath)"
+ AddXamlCompilationAttribute="True" />
+ <ItemGroup>
+ <FileWrites Include="@(_XamlGOutputs)" />
+ <Compile Include="@(_XamlGOutputs)" />
+ </ItemGroup>
+ </Target>
+
+ <!-- XamlC -->
+ <PropertyGroup>
+ <CompileDependsOn>
+ $(CompileDependsOn);
+ XamlC;
+ </CompileDependsOn>
+ </PropertyGroup>
+
+ <Target Name="XamlC" AfterTargets="AfterCompile" Inputs="$(IntermediateOutputPath)$(TargetFileName)" Outputs="$(IntermediateOutputPath)XamlC.stamp" >
+ <XamlCTask
+ Assembly = "$(IntermediateOutputPath)$(TargetFileName)"
+ ReferencePath = "@(ReferencePath)"
+ OptimizeIL = "true"
+ DebugSymbols = "$(DebugSymbols)"
+ DebugType = "$(DebugType)"
+ UseInjection = "$(NeedInjection)"
+ KeepXamlResources = "$(XFKeepXamlResources)" />
+ <Touch Files="$(IntermediateOutputPath)XamlC.stamp" AlwaysCreate="True" />
+ <ItemGroup>
+ <FileWrites Include="$(IntermediateOutputPath)XamlC.stamp" />
+ </ItemGroup>
+ </Target>
+</Project>
--- /dev/null
+# Tizen.NUI.XamlBuild
\ No newline at end of file
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <Version>1.0.6</Version>
+ <NoPackageAnalysis>true</NoPackageAnalysis>
+ <IncludeBuildOutput>false</IncludeBuildOutput>
+ <NuspecFile>.nuspec\Tizen.NUI.XamlBuild.nuspec</NuspecFile>
+ <NuspecProperties>configuration=$(Configuration);version=$(Version)</NuspecProperties>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
+ <PackageReference Include="System.Reflection" Version="4.3.0" />
+ <PackageReference Include="System.Reflection.TypeExtensions" Version="4.3.0" />
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="1.1.0" />
+ <PackageReference Include="Mono.Cecil" Version="0.11.0" />
+ <PackageReference Include="System.CodeDom" Version="4.4.0" />
+ <PackageReference Include="Microsoft.Build" Version="15.1.1012" />
+ <PackageReference Include="Microsoft.Build.Framework" Version="15.1.1012" />
+ <PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.1.1012" />
+ <PackageReference Include="Microsoft.Build.Tasks.Core" Version="15.1.1012" />
+ </ItemGroup>
+
+</Project>
\ No newline at end of file
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26430.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.XamlBuild", "Tizen.NUI.XamlBuild.csproj", "{473C3BEC-2F67-4285-85FC-BF4E96BFFF1C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {473C3BEC-2F67-4285-85FC-BF4E96BFFF1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {473C3BEC-2F67-4285-85FC-BF4E96BFFF1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {473C3BEC-2F67-4285-85FC-BF4E96BFFF1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {473C3BEC-2F67-4285-85FC-BF4E96BFFF1C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B7C41CDB-2CC7-4005-8E06-61BCAB3482A7}
+ EndGlobalSection
+EndGlobal
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Xml;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Binding;
+using Tizen.NUI.StyleSheets;
+
+using static System.String;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class ApplyPropertiesVisitor : IXamlNodeVisitor
+ {
+ public static readonly IList<XmlName> Skips = new List<XmlName> {
+ XmlName.xKey,
+ XmlName.xTypeArguments,
+ XmlName.xArguments,
+ XmlName.xFactoryMethod,
+ XmlName.xName,
+ XmlName.xDataType
+ };
+
+ public ApplyPropertiesVisitor(HydrationContext context, bool stopOnResourceDictionary = false)
+ {
+ Context = context;
+ StopOnResourceDictionary = stopOnResourceDictionary;
+ }
+
+ Dictionary<INode, object> Values => Context.Values;
+ HydrationContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary { get; }
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+ public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ var value = Values [node];
+ var source = Values [parentNode];
+ XmlName propertyName;
+
+ if (TryGetPropertyName(node, parentNode, out propertyName)) {
+ if (TrySetRuntimeName(propertyName, source, value, node))
+ return;
+ if (Skips.Contains(propertyName))
+ return;
+ if (parentElement.SkipProperties.Contains(propertyName))
+ return;
+ if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
+ return;
+ SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
+ } else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
+ // Collection element, implicit content, or implicit collection element.
+ var contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo());
+ if (contentProperty != null) {
+ var name = new XmlName(((ElementNode)parentNode).NamespaceURI, contentProperty);
+ if (Skips.Contains(name))
+ return;
+ if (parentElement.SkipProperties.Contains(propertyName))
+ return;
+ SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
+ }
+ }
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ XmlName propertyName;
+ if (TryGetPropertyName(node, parentNode, out propertyName) && propertyName == XmlName._CreateContent) {
+ var s0 = Values[parentNode];
+ if (s0 is ElementTemplate) {
+ SetTemplate(s0 as ElementTemplate, node);
+ return;
+ }
+ }
+
+ var parentElement = parentNode as IElementNode;
+ propertyName = XmlName.Empty;
+
+ //Simplify ListNodes with single elements
+ var pList = parentNode as ListNode;
+ if (pList != null && pList.CollectionItems.Count == 1) {
+ propertyName = pList.XmlName;
+ parentNode = parentNode.Parent;
+ parentElement = parentNode as IElementNode;
+ }
+
+ var value = Values[node];
+
+ if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) {
+ if (Skips.Contains(propertyName))
+ return;
+ if (parentElement == null)
+ return;
+ if (parentElement.SkipProperties.Contains(propertyName))
+ return;
+
+ var source = Values[parentNode];
+ ProvideValue(ref value, node, source, propertyName);
+ SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
+ var source = Values[parentNode];
+ ProvideValue(ref value, node, source, XmlName.Empty);
+ string contentProperty;
+ Exception xpe = null;
+ var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
+
+ //ResourceDictionary
+ if (xpe == null && TryAddToResourceDictionary(source as ResourceDictionary, value, xKey, node, out xpe))
+ return;
+
+ // Collection element, implicit content, or implicit collection element.
+ if (xpe == null && typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) {
+ var addMethod =
+ Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
+
+ addMethod.Invoke(source, new[] { value });
+ return;
+ }
+ if (xpe == null && (contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null) {
+ var name = new XmlName(node.NamespaceURI, contentProperty);
+ if (Skips.Contains(name))
+ return;
+ if (parentElement.SkipProperties.Contains(propertyName))
+ return;
+
+ SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
+ return;
+ }
+ if (xpe == null && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1))
+ {
+ //if there are similar parameters in the function, this will exist issue.
+ var addMethod = Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
+ if(addMethod != null) addMethod.Invoke(source, new[] { value });
+ return;
+ }
+ xpe = xpe ?? new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
+ if (Context.ExceptionHandler != null)
+ Context.ExceptionHandler(xpe);
+ throw xpe;
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is ListNode) {
+ var source = Values[parentNode.Parent];
+ ProvideValue(ref value, node, source, XmlName.Empty);
+ var parentList = (ListNode)parentNode;
+ if (Skips.Contains(parentList.XmlName))
+ return;
+ Exception xpe = null;
+ var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
+
+ object _;
+ var collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _) as IEnumerable;
+ if (collection == null)
+ xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
+
+ if (xpe == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, node, out xpe))
+ return;
+
+ MethodInfo addMethod;
+ if (xpe == null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null) {
+ addMethod.Invoke(collection, new[] { Values[node] });
+ return;
+ }
+ xpe = xpe ?? new XamlParseException($"Value of {parentList.XmlName.LocalName} does not have a Add() method", node);
+ if (Context.ExceptionHandler != null)
+ Context.ExceptionHandler(xpe);
+ else
+ throw xpe;
+ }
+ }
+
+
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
+ {
+ name = default(XmlName);
+ var parentElement = parentNode as IElementNode;
+ if (parentElement == null)
+ return false;
+ foreach (var kvp in parentElement.Properties) {
+ if (kvp.Value != node)
+ continue;
+ name = kvp.Key;
+ return true;
+ }
+ return false;
+ }
+
+ internal static bool IsCollectionItem(INode node, INode parentNode)
+ {
+ var parentList = parentNode as IListNode;
+ if (parentList == null)
+ return false;
+ return parentList.CollectionItems.Contains(node);
+ }
+
+ internal static string GetContentPropertyName(System.Reflection.TypeInfo typeInfo)
+ {
+ while (typeInfo != null) {
+ var propName = GetContentPropertyName(typeInfo.CustomAttributes);
+ if (propName != null)
+ return propName;
+ typeInfo = typeInfo?.BaseType?.GetTypeInfo();
+ }
+ return null;
+ }
+
+ void ProvideValue(ref object value, ElementNode node, object source, XmlName propertyName)
+ {
+ var markupExtension = value as IMarkupExtension;
+ var valueProvider = value as IValueProvider;
+
+ if (markupExtension == null && valueProvider == null)
+ return;
+
+ XamlServiceProvider serviceProvider = null;
+ if (value.GetType().GetTypeInfo().GetCustomAttribute<AcceptEmptyServiceProviderAttribute>() == null)
+ serviceProvider = new XamlServiceProvider(node, Context);
+
+ if (serviceProvider != null && serviceProvider.IProvideValueTarget != null && propertyName != XmlName.Empty)
+ ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = GetTargetProperty(source, propertyName, Context, node);
+
+ if (markupExtension != null)
+ value = markupExtension.ProvideValue(serviceProvider);
+ else if (valueProvider != null)
+ value = valueProvider.ProvideValue(serviceProvider);
+ }
+
+ static string GetContentPropertyName(IEnumerable<CustomAttributeData> attributes)
+ {
+ var contentAttribute =
+ attributes.FirstOrDefault(cad => ContentPropertyAttribute.ContentPropertyTypes.Contains(cad.AttributeType.FullName));
+ if (contentAttribute == null || contentAttribute.ConstructorArguments.Count != 1)
+ return null;
+ if (contentAttribute.ConstructorArguments [0].ArgumentType == typeof(string))
+ return (string)contentAttribute.ConstructorArguments [0].Value;
+ return null;
+ }
+
+ static bool GetRealNameAndType(ref Type elementType, string namespaceURI, ref string localname,
+ HydrationContext context, IXmlLineInfo lineInfo)
+ {
+ var dotIdx = localname.IndexOf('.');
+ if (dotIdx > 0) {
+ var typename = localname.Substring(0, dotIdx);
+ localname = localname.Substring(dotIdx + 1);
+ XamlParseException xpe;
+ elementType = XamlParser.GetElementType(new XmlType(namespaceURI, typename, null), lineInfo,
+ context.RootElement.GetType().GetTypeInfo().Assembly, out xpe);
+
+ if (xpe != null)
+ throw xpe;
+ return true;
+ }
+ return false;
+ }
+
+ static BindableProperty GetBindableProperty(Type elementType, string localName, IXmlLineInfo lineInfo,
+ bool throwOnError = false)
+ {
+#if NETSTANDARD1_0
+ var bindableFieldInfo = elementType.GetFields().FirstOrDefault(fi => fi.Name == localName + "Property");
+#else
+ var bindableFieldInfo = elementType.GetFields(BindingFlags.Static | BindingFlags.NonPublic|BindingFlags.FlattenHierarchy).FirstOrDefault(fi => fi.Name == localName + "Property");
+
+ if (null == bindableFieldInfo)
+ {
+ bindableFieldInfo = elementType.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy).FirstOrDefault(fi => fi.Name == localName + "Property");
+ }
+#endif
+ Exception exception = null;
+ if (exception == null && bindableFieldInfo == null) {
+ exception =
+ new XamlParseException(
+ Format("BindableProperty {0} not found on {1}", localName + "Property", elementType.Name), lineInfo);
+ }
+
+ if (exception == null)
+ return bindableFieldInfo.GetValue(null) as BindableProperty;
+ if (throwOnError)
+ throw exception;
+ return null;
+ }
+
+ static object GetTargetProperty(object xamlelement, XmlName propertyName, HydrationContext context, IXmlLineInfo lineInfo)
+ {
+ var localName = propertyName.LocalName;
+ //If it's an attached BP, update elementType and propertyName
+ var bpOwnerType = xamlelement.GetType();
+ GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo);
+ var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false);
+
+ if (property != null)
+ return property;
+
+ var elementType = xamlelement.GetType();
+ var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName);
+ return propertyInfo;
+ }
+
+ public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement, INode node, HydrationContext context, IXmlLineInfo lineInfo)
+ {
+ var localName = propertyName.LocalName;
+ var serviceProvider = new XamlServiceProvider(node, context);
+ Exception xpe = null;
+ var xKey = node is IElementNode && ((IElementNode)node).Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)((IElementNode)node).Properties[XmlName.xKey]).Value as string : null;
+
+ //If it's an attached BP, update elementType and propertyName
+ var bpOwnerType = xamlelement.GetType();
+ var attached = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo);
+ var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false);
+
+ //If the target is an event, connect
+ if (xpe == null && TryConnectEvent(xamlelement, localName, attached, value, rootElement, lineInfo, out xpe))
+ return;
+
+ //If Value is DynamicResource and it's a BP, SetDynamicResource
+ if (xpe == null && TrySetDynamicResource(xamlelement, property, value, lineInfo, out xpe))
+ return;
+
+ //If value is BindingBase, SetBinding
+ if (xpe == null && TrySetBinding(xamlelement, property, localName, value, lineInfo, out xpe))
+ return;
+
+ //If it's a BindableProberty, SetValue
+ if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe))
+ return;
+
+ //If we can assign that value to a normal property, let's do it
+ if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, context, out xpe))
+ return;
+
+ //If it's an already initialized property, add to it
+ if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe))
+ return;
+
+ xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exist, or is not assignable, or mismatching type between value and property", lineInfo);
+ if (context.ExceptionHandler != null)
+ context.ExceptionHandler(xpe);
+ else
+ throw xpe;
+ }
+
+ public static object GetPropertyValue(object xamlElement, XmlName propertyName, HydrationContext context, IXmlLineInfo lineInfo, out object targetProperty)
+ {
+ var localName = propertyName.LocalName;
+ Exception xpe = null;
+ object value;
+ targetProperty = null;
+
+ //If it's an attached BP, update elementType and propertyName
+ var bpOwnerType = xamlElement.GetType();
+ var attached = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo);
+ var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false);
+
+ //If it's a BindableProberty, GetValue
+ if (xpe == null && TryGetValue(xamlElement, property, attached, out value, lineInfo, out xpe, out targetProperty))
+ return value;
+
+ //If it's a normal property, get it
+ if (xpe == null && TryGetProperty(xamlElement, localName, out value, lineInfo, context, out xpe, out targetProperty))
+ return value;
+
+ xpe = xpe ?? new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
+ if (context.ExceptionHandler != null)
+ context.ExceptionHandler(xpe);
+ else
+ throw xpe;
+
+ return null;
+ }
+
+ static bool TryConnectEvent(object element, string localName, bool attached, object value, object rootElement, IXmlLineInfo lineInfo, out Exception exception)
+ {
+ exception = null;
+
+ if (attached)
+ return false;
+
+ var elementType = element.GetType();
+ var eventInfo = elementType.GetRuntimeEvent(localName);
+ var stringValue = value as string;
+
+ if (eventInfo == null || IsNullOrEmpty(stringValue))
+ return false;
+
+ var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value);
+ if (methodInfo == null) {
+ exception = new XamlParseException($"No method {value} found on type {rootElement.GetType()}", lineInfo);
+ return false;
+ }
+
+ try {
+ eventInfo.AddEventHandler(element, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement));
+ return true;
+ } catch (ArgumentException ae) {
+ exception = new XamlParseException($"Method {stringValue} does not have the correct signature", lineInfo, ae);
+ }
+ return false;
+ }
+
+ static bool TrySetDynamicResource(object element, BindableProperty property, object value, IXmlLineInfo lineInfo, out Exception exception)
+ {
+ exception = null;
+
+ var elementType = element.GetType();
+ var dynamicResource = value as DynamicResource;
+ var bindable = element as BindableObject;
+
+ if (dynamicResource == null || property == null)
+ return false;
+
+ if (bindable == null) {
+ exception = new XamlParseException($"{elementType.Name} is not a BindableObject", lineInfo);
+ return false;
+ }
+
+ bindable.SetDynamicResource(property, dynamicResource.Key);
+ return true;
+ }
+
+ static bool TrySetBinding(object element, BindableProperty property, string localName, object value, IXmlLineInfo lineInfo, out Exception exception)
+ {
+ exception = null;
+
+ var elementType = element.GetType();
+ var binding = value.ConvertTo(typeof(BindingBase),pinfoRetriever:null,serviceProvider:null) as BindingBase;
+ var bindable = element as BindableObject;
+ var nativeBindingService = DependencyService.Get<INativeBindingService>();
+
+ if (binding == null)
+ return false;
+
+ if (bindable != null && property != null) {
+ bindable.SetBinding(property, binding);
+ return true;
+ }
+
+ if (nativeBindingService != null && property != null && nativeBindingService.TrySetBinding(element, property, binding))
+ return true;
+
+ if (nativeBindingService != null && nativeBindingService.TrySetBinding(element, localName, binding))
+ return true;
+
+ if (property != null)
+ exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support native bindings", lineInfo);
+
+ return false;
+ }
+
+ static bool TrySetValue(object element, BindableProperty property, bool attached, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, out Exception exception)
+ {
+ exception = null;
+
+ var elementType = element.GetType();
+ var bindable = element as BindableObject;
+ var nativeBindingService = DependencyService.Get<INativeBindingService>();
+
+ if (property == null)
+ return false;
+
+ if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
+ ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = property;
+
+ Func<MemberInfo> minforetriever;
+ if (attached)
+ minforetriever = () => property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new [] { typeof(BindableObject) });
+ else
+ {
+ minforetriever = () => property.DeclaringType.GetRuntimeProperties().LastOrDefault(p => p.Name == property.PropertyName);
+ }
+ //minforetriever = () => property.DeclaringType.GetRuntimeProperty(property.PropertyName);
+ var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);
+
+ if (bindable != null) {
+ //SetValue doesn't throw on mismatching type, so check before to get a chance to try the property setting or the collection adding
+ var nullable = property.ReturnTypeInfo.IsGenericType &&
+ property.ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
+ if ((convertedValue == null && (!property.ReturnTypeInfo.IsValueType || nullable)) ||
+ (property.ReturnType.IsInstanceOfType(convertedValue))) {
+ bindable.SetValue(property, convertedValue);
+ return true;
+ }
+
+ // This might be a collection; see if we can add to it
+ return TryAddValue(bindable, property, value, serviceProvider);
+ }
+
+ if (nativeBindingService != null && nativeBindingService.TrySetValue(element, property, convertedValue))
+ return true;
+
+ exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support setting native BindableProperties", lineInfo);
+ return false;
+ }
+
+ static bool TryGetValue(object element, BindableProperty property, bool attached, out object value, IXmlLineInfo lineInfo, out Exception exception, out object targetProperty)
+ {
+ exception = null;
+ value = null;
+ targetProperty = property;
+ var elementType = element.GetType();
+ var bindable = element as BindableObject;
+
+ if (property == null)
+ return false;
+
+ if (bindable == null)
+ return false;
+
+ value = bindable.GetValue(property);
+ return true;
+ }
+
+ static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
+ {
+ exception = null;
+
+ var elementType = element.GetType();
+ var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName);
+ MethodInfo setter;
+ if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null)
+ return false;
+
+ if (!IsVisibleFrom(setter, context.RootElement))
+ return false;
+
+ if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
+ ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = propertyInfo;
+
+ object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider);
+ if (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue))
+ return false;
+
+ setter.Invoke(element, new object [] { convertedValue });
+ return true;
+ }
+
+ static bool TryGetProperty(object element, string localName, out object value, IXmlLineInfo lineInfo, HydrationContext context, out Exception exception, out object targetProperty)
+ {
+ exception = null;
+ value = null;
+ var elementType = element.GetType();
+ PropertyInfo propertyInfo = null;
+ try {
+ propertyInfo = elementType.GetRuntimeProperty(localName);
+ } catch (AmbiguousMatchException) {
+ // Get most derived instance of property
+ foreach (var property in elementType.GetRuntimeProperties().Where(prop => prop.Name == localName)) {
+ if (propertyInfo == null || propertyInfo.DeclaringType.IsAssignableFrom(property.DeclaringType))
+ propertyInfo = property;
+ }
+ }
+ MethodInfo getter;
+ targetProperty = propertyInfo;
+ if (propertyInfo == null || !propertyInfo.CanRead || (getter = propertyInfo.GetMethod) == null)
+ return false;
+
+ if (!IsVisibleFrom(getter, context.RootElement))
+ return false;
+
+ value = getter.Invoke(element, new object[] { });
+ return true;
+ }
+
+ static bool IsVisibleFrom(MethodInfo method, object rootElement)
+ {
+ if (method.IsPublic)
+ return true;
+ if (method.IsPrivate && method.DeclaringType == rootElement.GetType())
+ return true;
+ if ((method.IsAssembly || method.IsFamilyOrAssembly) && method.DeclaringType.AssemblyQualifiedName == rootElement.GetType().AssemblyQualifiedName)
+ return true;
+ if (method.IsFamily && method.DeclaringType.IsAssignableFrom(rootElement.GetType()))
+ return true;
+ return false;
+ }
+
+ static bool TryAddToProperty(object element, XmlName propertyName, object value, string xKey, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
+ {
+ exception = null;
+
+ object targetProperty;
+ var collection = GetPropertyValue(element, propertyName, context, lineInfo, out targetProperty) as IEnumerable;
+
+ if (collection == null)
+ return false;
+
+ if (exception == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, lineInfo, out exception))
+ return true;
+
+ if (exception != null)
+ return false;
+
+ var addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
+ if (addMethod == null)
+ return false;
+
+ if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
+ ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty;
+
+ addMethod.Invoke(collection, new [] { value.ConvertTo(addMethod.GetParameters() [0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
+ return true;
+ }
+
+ static bool TryAddToResourceDictionary(ResourceDictionary resourceDictionary, object value, string xKey, IXmlLineInfo lineInfo, out Exception exception)
+ {
+ exception = null;
+
+ if (resourceDictionary == null)
+ return false;
+
+ if (xKey != null)
+ resourceDictionary.Add(xKey, value);
+ else if (value is Tizen.NUI.Binding.Style)
+ resourceDictionary.Add((Tizen.NUI.Binding.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;
+ }
+ return true;
+ }
+
+ void SetTemplate(ElementTemplate dt, INode node)
+ {
+#pragma warning disable 0612
+ ((IDataTemplate)dt).LoadTemplate = () => {
+#pragma warning restore 0612
+ var cnode = node.Clone();
+ var context = new HydrationContext { ParentContext = Context, RootElement = Context.RootElement };
+ cnode.Accept(new XamlNodeVisitor((n, parent) => n.Parent = parent), node.Parent); //set parents for {StaticResource}
+ cnode.Accept(new ExpandMarkupsVisitor(context), null);
+ cnode.Accept(new NamescopingVisitor(context), null);
+ cnode.Accept(new CreateValuesVisitor(context), null);
+ cnode.Accept(new RegisterXNamesVisitor(context), null);
+ cnode.Accept(new FillResourceDictionariesVisitor(context), null);
+ cnode.Accept(new ApplyPropertiesVisitor(context, true), null);
+ return context.Values [cnode];
+ };
+ }
+
+ static bool TryAddValue(BindableObject bindable, BindableProperty property, object value, XamlServiceProvider serviceProvider)
+ {
+ if(property?.ReturnTypeInfo?.GenericTypeArguments == null){
+ return false;
+ }
+
+ if(property.ReturnType == null){
+ return false;
+ }
+
+ if (property.ReturnTypeInfo.GenericTypeArguments.Length != 1 ||
+ !property.ReturnTypeInfo.GenericTypeArguments[0].IsInstanceOfType(value))
+ return false;
+
+ // This might be a collection we can add to; see if we can find an Add method
+ var addMethod = GetAllRuntimeMethods(property.ReturnType)
+ .FirstOrDefault(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
+ if (addMethod == null)
+ return false;
+
+ // If there's an add method, get the collection
+ var collection = bindable.GetValue(property);
+
+ // And add the new value to it
+ addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
+ return true;
+ }
+
+ static IEnumerable<MethodInfo> GetAllRuntimeMethods(Type type)
+ {
+ return type.GetRuntimeMethods()
+ .Concat(type.GetTypeInfo().ImplementedInterfaces.SelectMany(t => t.GetRuntimeMethods()));
+ }
+
+ bool TrySetRuntimeName(XmlName propertyName, object source, object value, ValueNode node)
+ {
+ if (propertyName != XmlName.xName)
+ return false;
+
+ var runTimeName = source.GetType().GetTypeInfo().GetCustomAttribute<RuntimeNamePropertyAttribute>();
+ if (runTimeName == null)
+ return false;
+
+ SetPropertyValue(source, new XmlName("", runTimeName.Name), value, Context.RootElement, node, Context, node);
+ return true;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Xml;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Binding;
+
+
+namespace Tizen.NUI.Xaml
+{
+ internal class CreateValuesVisitor : IXamlNodeVisitor
+ {
+ public CreateValuesVisitor(HydrationContext context)
+ {
+ Context = context;
+ }
+
+ Dictionary<INode, object> Values
+ {
+ get { return Context.Values; }
+ }
+
+ HydrationContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+ public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ Values[node] = node.Value;
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ object value = null;
+
+ XamlParseException xpe;
+ var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement?.GetType().GetTypeInfo().Assembly,
+ out xpe);
+ if (xpe != null)
+ throw xpe;
+
+ Context.Types[node] = type;
+ string ctorargname;
+ if (IsXaml2009LanguagePrimitive(node))
+ value = CreateLanguagePrimitive(type, node);
+ else if (node.Properties.ContainsKey(XmlName.xArguments) || node.Properties.ContainsKey(XmlName.xFactoryMethod))
+ value = CreateFromFactory(type, node);
+ else if (
+ type.GetTypeInfo()
+ .DeclaredConstructors.Any(
+ ci =>
+ ci.IsPublic && ci.GetParameters().Length != 0 &&
+ ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof (ParameterAttribute)))) &&
+ ValidateCtorArguments(type, node, out ctorargname))
+ value = CreateFromParameterizedConstructor(type, node);
+ else if (!type.GetTypeInfo().DeclaredConstructors.Any(ci => ci.IsPublic && ci.GetParameters().Length == 0) &&
+ !ValidateCtorArguments(type, node, out ctorargname))
+ {
+ throw new XamlParseException($"The Property {ctorargname} is required to create a {type?.FullName} object.", node);
+ }
+ else
+ {
+ //this is a trick as the DataTemplate parameterless ctor is internal, and we can't CreateInstance(..., false) on WP7
+ try
+ {
+ if (type == typeof (DataTemplate))
+ value = new DataTemplate();
+ if (type == typeof (ControlTemplate))
+ value = new ControlTemplate();
+ if (value == null && node.CollectionItems.Any() && node.CollectionItems.First() is ValueNode)
+ {
+ var serviceProvider = new XamlServiceProvider(node, Context);
+ var converted = ((ValueNode)node.CollectionItems.First()).Value.ConvertTo(type, () => type.GetTypeInfo(),
+ serviceProvider);
+ if (converted != null && converted.GetType() == type)
+ value = converted;
+ }
+ if (value == null)
+ {
+ value = Activator.CreateInstance(type);
+ if (value is Element)
+ {
+ if (null != Application.Current)
+ {
+ Application.AddResourceChangedCallback(value, (value as Element).OnResourcesChanged);
+ }
+
+ if (value is BindableObject)
+ {
+ ((BindableObject)value).IsCreateByXaml = true;
+ }
+ }
+ }
+ }
+ catch (TargetInvocationException e)
+ {
+ if (e.InnerException is XamlParseException || e.InnerException is XmlException)
+ throw e.InnerException;
+ throw;
+ }
+ }
+
+ Values[node] = value;
+
+ var markup = value as IMarkupExtension;
+ if (markup != null && (value is TypeExtension || value is StaticExtension || value is ArrayExtension))
+ {
+ var serviceProvider = new XamlServiceProvider(node, Context);
+
+ var visitor = new ApplyPropertiesVisitor(Context);
+ foreach (var cnode in node.Properties.Values.ToList())
+ cnode.Accept(visitor, node);
+ foreach (var cnode in node.CollectionItems)
+ cnode.Accept(visitor, node);
+
+ value = markup.ProvideValue(serviceProvider);
+
+ INode xKey;
+ if (!node.Properties.TryGetValue(XmlName.xKey, out xKey))
+ xKey = null;
+
+ node.Properties.Clear();
+ node.CollectionItems.Clear();
+
+ if (xKey != null)
+ node.Properties.Add(XmlName.xKey, xKey);
+
+ Values[node] = value;
+ }
+
+ if (value is BindableObject)
+ NameScope.SetNameScope(value as BindableObject, node.Namescope);
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ var rnode = (XamlLoader.RuntimeRootNode)node;
+ Values[node] = rnode.Root;
+ Context.Types[node] = rnode.Root.GetType();
+ var bindableRoot = rnode.Root as BindableObject;
+ if (bindableRoot != null)
+ NameScope.SetNameScope(bindableRoot, node.Namescope);
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ //this is a gross hack to keep ListNode alive. ListNode must go in favor of Properties
+ XmlName name;
+ if (ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out name))
+ node.XmlName = name;
+ }
+
+ bool ValidateCtorArguments(Type nodeType, IElementNode node, out string missingArgName)
+ {
+ missingArgName = null;
+ var ctorInfo =
+ nodeType.GetTypeInfo()
+ .DeclaredConstructors.FirstOrDefault(
+ ci =>
+ ci.GetParameters().Length != 0 && ci.IsPublic &&
+ ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof (ParameterAttribute))));
+ if (ctorInfo == null)
+ return true;
+ foreach (var parameter in ctorInfo.GetParameters())
+ {
+ // Modify the namespace
+ var propname =
+ parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
+ .ConstructorArguments.First()
+ .Value as string;
+ if (!node.Properties.ContainsKey(new XmlName("", propname)))
+ {
+ missingArgName = propname;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public object CreateFromParameterizedConstructor(Type nodeType, IElementNode node)
+ {
+ var ctorInfo =
+ nodeType.GetTypeInfo()
+ .DeclaredConstructors.FirstOrDefault(
+ ci =>
+ ci.GetParameters().Length != 0 && ci.IsPublic &&
+ ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof (ParameterAttribute))));
+ object[] arguments = CreateArgumentsArray(node, ctorInfo);
+ return ctorInfo.Invoke(arguments);
+ }
+
+ public object CreateFromFactory(Type nodeType, IElementNode node)
+ {
+ object[] arguments = CreateArgumentsArray(node);
+
+ if (!node.Properties.ContainsKey(XmlName.xFactoryMethod))
+ {
+ //non-default ctor
+ object ret = Activator.CreateInstance(nodeType, arguments);
+ if (ret is Element)
+ {
+ if (null != Application.Current)
+ {
+ Application.AddResourceChangedCallback(ret, (ret as Element).OnResourcesChanged);
+ }
+
+ if (ret is BindableObject)
+ {
+ ((BindableObject)ret).IsCreateByXaml = true;
+ }
+ }
+ return ret;
+ }
+
+ var factoryMethod = ((string)((ValueNode)node.Properties[XmlName.xFactoryMethod]).Value);
+ Type[] types = arguments == null ? new Type[0] : arguments.Select(a => a.GetType()).ToArray();
+ Func<MethodInfo, bool> isMatch = m => {
+ if (m.Name != factoryMethod)
+ return false;
+ var p = m.GetParameters();
+ if (p.Length != types.Length)
+ return false;
+ if (!m.IsStatic)
+ return false;
+ for (var i = 0; i < p.Length; i++) {
+ if ((p [i].ParameterType.IsAssignableFrom(types [i])))
+ continue;
+ var op_impl = p[i].ParameterType.GetImplicitConversionOperator(fromType: types[i], toType: p[i].ParameterType)
+ ?? types[i].GetImplicitConversionOperator(fromType: types[i], toType: p[i].ParameterType);
+
+ if (op_impl == null)
+ return false;
+ arguments [i] = op_impl.Invoke(null, new [] { arguments [i]});
+ }
+ return true;
+ };
+ var mi = nodeType.GetRuntimeMethods().FirstOrDefault(isMatch);
+ if (mi == null)
+ throw new MissingMemberException($"No static method found for {nodeType.FullName}::{factoryMethod} ({string.Join(", ", types.Select(t => t.FullName))})");
+ return mi.Invoke(null, arguments);
+ }
+
+ public object[] CreateArgumentsArray(IElementNode enode)
+ {
+ if (!enode.Properties.ContainsKey(XmlName.xArguments))
+ return null;
+ var node = enode.Properties[XmlName.xArguments];
+ var elementNode = node as ElementNode;
+ if (elementNode != null)
+ {
+ var array = new object[1];
+ array[0] = Values[elementNode];
+ return array;
+ }
+
+ var listnode = node as ListNode;
+ if (listnode != null)
+ {
+ var array = new object[listnode.CollectionItems.Count];
+ for (var i = 0; i < listnode.CollectionItems.Count; i++)
+ array[i] = Values[(ElementNode)listnode.CollectionItems[i]];
+ return array;
+ }
+ return null;
+ }
+
+ public object[] CreateArgumentsArray(IElementNode enode, ConstructorInfo ctorInfo)
+ {
+ var n = ctorInfo.GetParameters().Length;
+ var array = new object[n];
+ for (var i = 0; i < n; i++)
+ {
+ var parameter = ctorInfo.GetParameters()[i];
+ var propname =
+ parameter.CustomAttributes.First(attr => attr.AttributeType == typeof (ParameterAttribute))
+ .ConstructorArguments.First()
+ .Value as string;
+ var name = new XmlName("", propname);
+ INode node;
+ if (!enode.Properties.TryGetValue(name, out node))
+ {
+ throw new XamlParseException(
+ String.Format("The Property {0} is required to create a {1} object.", propname, ctorInfo.DeclaringType.FullName),
+ enode as IXmlLineInfo);
+ }
+ if (!enode.SkipProperties.Contains(name))
+ enode.SkipProperties.Add(name);
+ var value = Context.Values[node];
+ var serviceProvider = new XamlServiceProvider(enode, Context);
+ var convertedValue = value.ConvertTo(parameter.ParameterType, () => parameter, serviceProvider);
+ array[i] = convertedValue;
+ }
+
+ return array;
+ }
+
+ static bool IsXaml2009LanguagePrimitive(IElementNode node)
+ {
+ return node.NamespaceURI == XamlParser.X2009Uri;
+ }
+
+ static object CreateLanguagePrimitive(Type nodeType, IElementNode node)
+ {
+ object value = null;
+ if (nodeType == typeof(string))
+ value = String.Empty;
+ else if (nodeType == typeof(Uri))
+ value = null;
+ else
+ {
+ value = Activator.CreateInstance(nodeType);
+ if (value is Element)
+ {
+ if (null != Application.Current)
+ {
+ Application.AddResourceChangedCallback(value, (value as Element).OnResourcesChanged);
+ }
+
+ if (value is BindableObject)
+ {
+ ((BindableObject)value).IsCreateByXaml = true;
+ }
+ }
+ }
+
+ if (node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode &&
+ ((ValueNode)node.CollectionItems[0]).Value is string)
+ {
+ var valuestring = ((ValueNode)node.CollectionItems[0]).Value as string;
+
+ if (nodeType == typeof(SByte)) {
+ sbyte retval;
+ if (sbyte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Int16)) {
+ short retval;
+ if (short.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Int32)) {
+ int retval;
+ if (int.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Int64)) {
+ long retval;
+ if (long.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Byte)) {
+ byte retval;
+ if (byte.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(UInt16)) {
+ ushort retval;
+ if (ushort.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(UInt32)) {
+ uint retval;
+ if (uint.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(UInt64)) {
+ ulong retval;
+ if (ulong.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Single)) {
+ float retval;
+ if (float.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof(Double)) {
+ double retval;
+ if (double.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof (Boolean))
+ {
+ bool outbool;
+ if (bool.TryParse(valuestring, out outbool))
+ return outbool;
+ }
+ if (nodeType == typeof(TimeSpan)) {
+ TimeSpan retval;
+ if (TimeSpan.TryParse(valuestring, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+ if (nodeType == typeof (char))
+ {
+ char retval;
+ if (char.TryParse(valuestring, out retval))
+ return retval;
+ }
+ if (nodeType == typeof (string))
+ return valuestring;
+ if (nodeType == typeof (decimal))
+ {
+ decimal retval;
+ if (decimal.TryParse(valuestring, NumberStyles.Number, CultureInfo.InvariantCulture, out retval))
+ return retval;
+ }
+
+ else if (nodeType == typeof (Uri))
+ {
+ Uri retval;
+ if (Uri.TryCreate(valuestring, UriKind.RelativeOrAbsolute, out retval))
+ return retval;
+ }
+ }
+ return value;
+ }
+ }
+}
--- /dev/null
+namespace Tizen.NUI.Xaml
+{
+ internal static class DesignMode
+ {
+ public static bool IsDesignModeEnabled { get; internal set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Xml;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class ExpandMarkupsVisitor : IXamlNodeVisitor
+ {
+ public ExpandMarkupsVisitor(HydrationContext context)
+ {
+ Context = context;
+ }
+
+ public static readonly IList<XmlName> Skips = new List<XmlName>
+ {
+ XmlName.xKey,
+ XmlName.xTypeArguments,
+ XmlName.xFactoryMethod,
+ XmlName.xName,
+ XmlName.xDataType
+ };
+
+ Dictionary<INode, object> Values
+ {
+ get { return Context.Values; }
+ }
+
+ HydrationContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => false;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+ public bool IsResourceDictionary(ElementNode node) => false;
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(MarkupNode markupnode, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ XmlName propertyName;
+ if (!ApplyPropertiesVisitor.TryGetPropertyName(markupnode, parentNode, out propertyName))
+ return;
+ if (Skips.Contains(propertyName))
+ return;
+ if (parentElement.SkipProperties.Contains(propertyName))
+ return;
+
+ var markupString = markupnode.MarkupString;
+ var node =
+ ParseExpression(ref markupString, markupnode.NamespaceResolver, markupnode, markupnode, parentNode) as IElementNode;
+ if (node != null)
+ {
+ ((IElementNode)parentNode).Properties[propertyName] = node;
+ node.Parent = parentNode;
+ }
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ INode ParseExpression(ref string expression, IXmlNamespaceResolver nsResolver, IXmlLineInfo xmlLineInfo, INode node,
+ INode parentNode)
+ {
+ if (expression.StartsWith("{}", StringComparison.Ordinal))
+ return new ValueNode(expression.Substring(2), null);
+
+ if (expression[expression.Length - 1] != '}')
+ throw new Exception("Expression must end with '}'");
+
+ int len;
+ string match;
+ if (!MarkupExpressionParser.MatchMarkup(out match, expression, out len))
+ throw new Exception();
+ expression = expression.Substring(len).TrimStart();
+ if (expression.Length == 0)
+ throw new Exception("Expression did not end in '}'");
+
+ var serviceProvider = new XamlServiceProvider(node, Context);
+ serviceProvider.Add(typeof (IXmlNamespaceResolver), nsResolver);
+
+ return new MarkupExpansionParser().Parse(match, ref expression, serviceProvider);
+ }
+
+ public class MarkupExpansionParser : MarkupExpressionParser, IExpressionParser<INode>
+ {
+ IElementNode node;
+
+ object IExpressionParser.Parse(string match, ref string remaining, IServiceProvider serviceProvider)
+ {
+ return Parse(match, ref remaining, serviceProvider);
+ }
+
+ public INode Parse(string match, ref string remaining, IServiceProvider serviceProvider)
+ {
+ var nsResolver = serviceProvider.GetService(typeof (IXmlNamespaceResolver)) as IXmlNamespaceResolver;
+ if (nsResolver == null)
+ throw new ArgumentException();
+ IXmlLineInfo xmlLineInfo = null;
+ var xmlLineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ if (xmlLineInfoProvider != null)
+ xmlLineInfo = xmlLineInfoProvider.XmlLineInfo;
+
+ var split = match.Split(':');
+ if (split.Length > 2)
+ throw new ArgumentException();
+
+ string prefix; //, name;
+ if (split.Length == 2)
+ {
+ prefix = split[0];
+ //name = split [1];
+ }
+ else
+ {
+ prefix = "";
+ //name = split [0];
+ }
+
+ Type type;
+ var typeResolver = serviceProvider.GetService(typeof (IXamlTypeResolver)) as IXamlTypeResolver;
+ if (typeResolver == null)
+ type = null;
+ // Add Binding and StaticResource support, The ordinal code can't find BindingExtension for Binding
+ //else if (match == "Binding")
+ //{
+ // type = typeof(BindingExtension);
+ //}
+ //else if (match == "StaticResource")
+ //{
+ // type = typeof(StaticResourceExtension);
+ //}
+ else
+ {
+ //The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
+ if (!typeResolver.TryResolve(match + "Extension", out type) && !typeResolver.TryResolve(match, out type))
+ {
+ var lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException(String.Format("MarkupExtension not found for {0}", match), lineInfo);
+ }
+ }
+
+ var namespaceuri = nsResolver.LookupNamespace(prefix) ?? "";
+ var xmltype = new XmlType(namespaceuri, type?.Name, null);
+
+ if (type == null)
+ throw new NotSupportedException();
+
+ node = xmlLineInfo == null
+ ? new ElementNode(xmltype, null, nsResolver)
+ : new ElementNode(xmltype, null, nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
+
+ if (remaining.StartsWith("}", StringComparison.Ordinal))
+ {
+ remaining = remaining.Substring(1);
+ return node;
+ }
+
+ char next;
+ string piece;
+ while ((piece = GetNextPiece(ref remaining, out next)) != null)
+ HandleProperty(piece, serviceProvider, ref remaining, next != '=');
+
+ return node;
+ }
+
+ protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
+ {
+ var nsResolver = serviceProvider.GetService(typeof (IXmlNamespaceResolver)) as IXmlNamespaceResolver;
+
+ var childnode = value as INode ?? new ValueNode(strValue, nsResolver);
+ childnode.Parent = node;
+ if (prop != null)
+ {
+ var name = new XmlName(node.NamespaceURI, prop);
+ node.Properties[name] = childnode;
+ }
+ else //ContentProperty
+ node.CollectionItems.Add(childnode);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class FillResourceDictionariesVisitor : IXamlNodeVisitor
+ {
+ public FillResourceDictionariesVisitor(HydrationContext context)
+ {
+ Context = context;
+ }
+
+ HydrationContext Context { get; }
+ Dictionary<INode, object> Values => Context.Values;
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+
+ public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ if (!typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)]))
+ return;
+
+ node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ var value = Values[node];
+ XmlName propertyName;
+ //Set RD to VE
+ if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName)) {
+ if ((propertyName.LocalName == "Resources" ||
+ propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) && value is ResourceDictionary) {
+ var source = Values[parentNode];
+ ApplyPropertiesVisitor.SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
+ return;
+ }
+ }
+
+ //Only proceed further if the node is a keyless RD
+ if ( parentNode is IElementNode
+ && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)])
+ && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
+ node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ else if ( parentNode is ListNode
+ && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode.Parent)])
+ && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
+ node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ public bool SkipChildren(INode node, INode parentNode)
+ {
+ var enode = node as ElementNode;
+ if (enode is null)
+ return false;
+ if ( parentNode is IElementNode
+ && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)])
+ && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
+ return true;
+ if ( parentNode is ListNode
+ && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode.Parent)])
+ && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
+ return true;
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class HydrationContext
+ {
+ public HydrationContext()
+ {
+ Values = new Dictionary<INode, object>();
+ Types = new Dictionary<IElementNode, Type>();
+ }
+
+ public Dictionary<INode, object> Values { get; }
+ public Dictionary<IElementNode, Type> Types { get; }
+ public HydrationContext ParentContext { get; set; }
+ public Action<Exception> ExceptionHandler { get; set; }
+ public object RootElement { get; set; }
+ }
+}
--- /dev/null
+namespace Tizen.NUI.Xaml
+{
+ internal interface IConverterOptions
+ {
+ bool IgnoreCase { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Xaml
+{
+ internal static class IDictionaryExtensions
+ {
+ public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
+ IEnumerable<KeyValuePair<TKey, TValue>> collection)
+ {
+ foreach (var kvp in collection)
+ dictionary.Add(kvp);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IExpressionParser
+ {
+ object Parse(string match, ref string expression, IServiceProvider serviceProvider);
+ }
+
+ internal interface IExpressionParser<out T> : IExpressionParser
+ where T : class
+ {
+ new T Parse(string match, ref string expression, IServiceProvider serviceProvider);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IMarkupExtension<out T> : IMarkupExtension
+ {
+ new T ProvideValue(IServiceProvider serviceProvider);
+ }
+
+ internal interface IMarkupExtension
+ {
+ object ProvideValue(IServiceProvider serviceProvider);
+ }
+
+ [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+ internal sealed class AcceptEmptyServiceProviderAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml.Internals
+{
+ internal interface INativeValueConverterService
+ {
+ bool ConvertTo(object value, Type toType, out object nativeValue);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IProvideParentValues : IProvideValueTarget
+ {
+ IEnumerable<object> ParentObjects { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Xaml
+{
+ internal interface IProvideValueTarget
+ {
+ object TargetObject { get; }
+ object TargetProperty { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Xaml
+{
+ internal interface IReferenceProvider
+ {
+ object FindByName(string name);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+using System.Xml;
+using System.IO;
+
+namespace Tizen.NUI
+{
+ internal interface IResourcesLoader
+ {
+ T CreateFromResource<T>(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo) where T : new();
+ string GetResource(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo);
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Xaml
+{
+ internal interface IRootObjectProvider
+ {
+ object RootObject { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IValueConverterProvider
+ {
+ object Convert(object value, Type toType, Func<MemberInfo> minfoRetriever, IServiceProvider serviceProvider);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IValueProvider
+ {
+ object ProvideValue(IServiceProvider serviceProvider);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IXamlTypeResolver
+ {
+ Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider = null);
+ bool TryResolve(string qualifiedTypeName, out Type type);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Xml;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IXmlLineInfoProvider
+ {
+ IXmlLineInfo XmlLineInfo { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// MarkupExpressionParser.cs
+//
+// This code is partly salvaged from moonlight. Following licence apply.
+//
+//
+// Author(s):
+// Moonlight List (moonlight-list@lists.ximian.com)
+// Stephane Delcroix (stephane@mi8.be)
+//
+// Copyright 2009 Novell, Inc.
+// Copyright 2013 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+
+namespace Tizen.NUI.Xaml
+{
+ internal abstract class MarkupExpressionParser
+ {
+ public object ParseExpression(ref string expression, IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ throw new ArgumentNullException(nameof(serviceProvider));
+ if (expression.StartsWith("{}", StringComparison.Ordinal))
+ return expression.Substring(2);
+
+ if (expression[expression.Length - 1] != '}')
+ throw new Exception("Expression must end with '}'");
+
+ int len;
+ string match;
+ if (!MatchMarkup(out match, expression, out len))
+ return false;
+ expression = expression.Substring(len).TrimStart();
+ if (expression.Length == 0)
+ throw new Exception("Expression did not end in '}'");
+
+ var parser = Activator.CreateInstance(GetType()) as IExpressionParser;
+ return parser.Parse(match, ref expression, serviceProvider);
+ }
+
+ internal static bool MatchMarkup(out string match, string expression, out int end)
+ {
+ if (expression.Length < 2)
+ {
+ end = 1;
+ match = null;
+ return false;
+ }
+
+ if (expression[0] != '{')
+ {
+ end = 2;
+ match = null;
+ return false;
+ }
+
+ int i;
+ bool found = false;
+ for (i = 1; i < expression.Length; i++)
+ {
+ if (expression[i] == ' ')
+ continue;
+ found = true;
+ break;
+ }
+
+ if (!found)
+ {
+ end = 3;
+ match = null;
+ return false;
+ }
+
+ int c;
+ for (c = 0; c + i < expression.Length; c++)
+ {
+ if (expression[i + c] == ' ' || expression[i + c] == '}')
+ break;
+ }
+
+ if (i + c == expression.Length)
+ {
+ end = 6;
+ match = null;
+ return false;
+ }
+
+ end = i + c;
+ match = expression.Substring(i, c);
+ return true;
+ }
+
+ protected void HandleProperty(string prop, IServiceProvider serviceProvider, ref string remaining, bool isImplicit)
+ {
+ char next;
+ object value = null;
+ string str_value;
+
+ if (isImplicit)
+ {
+ SetPropertyValue(null, prop, null, serviceProvider);
+ return;
+ }
+ remaining = remaining.TrimStart();
+ if (remaining.StartsWith("{", StringComparison.Ordinal))
+ {
+ value = ParseExpression(ref remaining, serviceProvider);
+ remaining = remaining.TrimStart();
+
+ if (remaining.Length > 0 && remaining[0] == ',')
+ remaining = remaining.Substring(1);
+ else if (remaining.Length > 0 && remaining[0] == '}')
+ remaining = remaining.Substring(1);
+
+ str_value = value as string;
+ }
+ else
+ str_value = GetNextPiece(ref remaining, out next);
+
+ SetPropertyValue(prop, str_value, value, serviceProvider);
+ }
+
+ protected abstract void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider);
+
+ protected string GetNextPiece(ref string remaining, out char next)
+ {
+ bool inString = false;
+ int end = 0;
+ char stringTerminator = '\0';
+ remaining = remaining.TrimStart();
+ if (remaining.Length == 0)
+ {
+ next = Char.MaxValue;
+ return null;
+ }
+
+ var piece = new StringBuilder();
+ // If we're inside a quoted string we append all chars to our piece until we hit the ending quote.
+ while (end < remaining.Length &&
+ (inString || (remaining[end] != '}' && remaining[end] != ',' && remaining[end] != '=')))
+ {
+ if (inString)
+ {
+ if (remaining[end] == stringTerminator)
+ {
+ inString = false;
+ end ++;
+ break;
+ }
+ }
+ else
+ {
+ if (remaining[end] == '\'' || remaining[end] == '"')
+ {
+ inString = true;
+ stringTerminator = remaining[end];
+ end ++;
+ continue;
+ }
+ }
+
+ // If this is an escape char, consume it and append the next char to our piece.
+ if (remaining[end] == '\\')
+ {
+ end ++;
+ if (end == remaining.Length)
+ break;
+ }
+ piece.Append(remaining[end]);
+ end++;
+ }
+
+ if (inString && end == remaining.Length)
+ throw new Exception("Unterminated quoted string");
+
+ if (end == remaining.Length && !remaining.EndsWith("}", StringComparison.Ordinal))
+ throw new Exception("Expression did not end with '}'");
+
+ if (end == 0)
+ {
+ next = Char.MaxValue;
+ return null;
+ }
+
+ next = remaining[end];
+ remaining = remaining.Substring(end + 1);
+
+ // Whitespace is trimmed from the end of the piece before stripping
+ // quote chars from the start/end of the string.
+ while (piece.Length > 0 && char.IsWhiteSpace(piece[piece.Length - 1]))
+ piece.Length --;
+
+ if (piece.Length >= 2)
+ {
+ char first = piece[0];
+ char last = piece[piece.Length - 1];
+ if ((first == '\'' && last == '\'') || (first == '"' && last == '"'))
+ {
+ piece.Remove(piece.Length - 1, 1);
+ piece.Remove(0, 1);
+ }
+ }
+
+ return piece.ToString();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ internal sealed class MarkupExtensionParser : MarkupExpressionParser, IExpressionParser<object>
+ {
+ IMarkupExtension markupExtension;
+
+ public object Parse(string match, ref string remaining, IServiceProvider serviceProvider)
+ {
+ var typeResolver = serviceProvider.GetService(typeof (IXamlTypeResolver)) as IXamlTypeResolver;
+
+ //shortcut for Binding and StaticResource, to avoid too many reflection calls.
+ if (match == "Binding")
+ markupExtension = new BindingExtension();
+ else if (match == "TemplateBinding")
+ markupExtension = new TemplateBindingExtension();
+ else if (match == "StaticResource")
+ markupExtension = new StaticResourceExtension();
+ else
+ {
+ if (typeResolver == null)
+ return null;
+ Type type;
+
+ //The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
+ if (!typeResolver.TryResolve(match + "Extension", out type) && !typeResolver.TryResolve(match, out type))
+ {
+ var lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException(String.Format("MarkupExtension not found for {0}", match), lineInfo);
+ }
+ markupExtension = Activator.CreateInstance(type) as IMarkupExtension;
+ }
+
+ if (markupExtension == null)
+ {
+ var lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException(String.Format("Missing public default constructor for MarkupExtension {0}", match),
+ lineInfo);
+ }
+
+ char next;
+ if (remaining == "}")
+ return markupExtension.ProvideValue(serviceProvider);
+
+ string piece;
+ while ((piece = GetNextPiece(ref remaining, out next)) != null)
+ HandleProperty(piece, serviceProvider, ref remaining, next != '=');
+
+ return markupExtension.ProvideValue(serviceProvider);
+ }
+
+ protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
+ {
+ MethodInfo setter;
+ if (prop == null)
+ {
+ //implicit property
+ var t = markupExtension.GetType();
+ prop = ApplyPropertiesVisitor.GetContentPropertyName(t.GetTypeInfo());
+ if (prop == null)
+ return;
+ setter = t.GetRuntimeProperty(prop).SetMethod;
+ }
+ else
+ setter = markupExtension.GetType().GetRuntimeProperty(prop).SetMethod;
+
+ if (value == null && strValue != null)
+ {
+ value = strValue.ConvertTo(markupExtension.GetType().GetRuntimeProperty(prop).PropertyType,
+ (Func<TypeConverter>)null, serviceProvider);
+ }
+
+ setter?.Invoke(markupExtension, new[] { value });
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty("Items")]
+ [AcceptEmptyServiceProvider]
+ internal class ArrayExtension : IMarkupExtension<Array>
+ {
+ public ArrayExtension()
+ {
+ Items = new List<object>();
+ }
+
+ public IList Items { get; }
+
+ public Type Type { get; set; }
+
+ public Array ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (Type == null)
+ throw new InvalidOperationException("Type argument mandatory for x:Array extension");
+
+ if (Items == null)
+ return null;
+
+ var array = Array.CreateInstance(Type, Items.Count);
+ for (var i = 0; i < Items.Count; i++)
+ ((IList)array)[i] = Items[i];
+
+ return array;
+ }
+
+ object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
+ {
+ return (this as IMarkupExtension<Array>).ProvideValue(serviceProvider);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml;
+using Mono.Cecil;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty("Path")]
+ [AcceptEmptyServiceProvider]
+ internal sealed class BindingExtension : IMarkupExtension<BindingBase>
+ {
+ public string Path { get; set; } = Tizen.NUI.Binding.Binding.SelfPath;
+ public BindingMode Mode { get; set; } = BindingMode.Default;
+
+ public EXamlCreateObject ModeInEXaml { get; set; } = null;
+
+ public object Converter { get; set; }
+
+ public object ConverterParameter { get; set; }
+
+ public string StringFormat { get; set; }
+
+ public object Source { get; set; }
+
+ public string UpdateSourceEventName { get; set; }
+
+ public object TargetNullValue { get; set; }
+
+ public object FallbackValue { get; set; }
+
+ public TypedBindingBase TypedBinding { get; set; }
+
+ public EXamlCreateObject ProvideValue(EXamlContext context, ModuleDefinition module)
+ {
+ if (TypedBinding == null)
+ {
+ var newTypeRef = module.ImportReference(typeof(Tizen.NUI.Binding.Binding));
+ return new EXamlCreateObject(context, null, newTypeRef, new object[] { Path, ModeInEXaml, Converter, ConverterParameter, StringFormat, Source });
+ }
+ else
+ {
+ throw new Exception("TypedBinding should not be not null");
+ //TypedBinding.Mode = Mode;
+ //TypedBinding.Converter = Converter;
+ //TypedBinding.ConverterParameter = ConverterParameter;
+ //TypedBinding.StringFormat = StringFormat;
+ //TypedBinding.Source = Source;
+ //TypedBinding.UpdateSourceEventName = UpdateSourceEventName;
+ //TypedBinding.FallbackValue = FallbackValue;
+ //TypedBinding.TargetNullValue = TargetNullValue;
+ //return TypedBinding;
+ }
+ }
+
+ BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (TypedBinding == null)
+ return new Tizen.NUI.Binding.Binding(Path, Mode, Converter as IValueConverter, ConverterParameter, StringFormat, Source)
+ {
+ UpdateSourceEventName = UpdateSourceEventName,
+ FallbackValue = FallbackValue,
+ TargetNullValue = TargetNullValue,
+ };
+
+ TypedBinding.Mode = Mode;
+ TypedBinding.Converter = Converter as IValueConverter;
+ TypedBinding.ConverterParameter = ConverterParameter;
+ TypedBinding.StringFormat = StringFormat;
+ TypedBinding.Source = Source;
+ TypedBinding.UpdateSourceEventName = UpdateSourceEventName;
+ TypedBinding.FallbackValue = FallbackValue;
+ TypedBinding.TargetNullValue = TargetNullValue;
+ return TypedBinding;
+ }
+
+ object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
+ {
+ return (this as IMarkupExtension<BindingBase>).ProvideValue(serviceProvider);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.EXaml;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty("Key")]
+ internal sealed class DynamicResourceExtension : IMarkupExtension<DynamicResource>
+ {
+ public string Key { get; set; }
+
+ public object ProvideValue()
+ {
+ if (null == Key)
+ {
+ return null;
+ }
+ else
+ {
+ return new DynamicResource(Key);
+ }
+ }
+
+ public object ProvideValue(IServiceProvider serviceProvider)
+ {
+ return ((IMarkupExtension<DynamicResource>)this).ProvideValue(serviceProvider);
+ }
+
+ DynamicResource IMarkupExtension<DynamicResource>.ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (Key == null)
+ {
+ var lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException("DynamicResource markup require a Key", lineInfo);
+ }
+ return new DynamicResource(Key);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ [ProvideCompiled("Tizen.NUI.Xaml.Build.Tasks.NullExtension")]
+ [AcceptEmptyServiceProvider]
+ internal class NullExtension : IMarkupExtension
+ {
+ public object ProvideValue(IServiceProvider serviceProvider)
+ {
+ return null;
+ }
+ }
+}
--- /dev/null
+using System;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty("Name")]
+ internal class ReferenceExtension : IMarkupExtension
+ {
+ public string Name { get; set; }
+
+ public object ProvideValue(EXamlContext context)
+ {
+ return context.GetObjectByXName(Name);
+ }
+
+ public object ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ throw new ArgumentNullException(nameof(serviceProvider));
+ var valueProvider = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideParentValues;
+ if (valueProvider == null)
+ throw new ArgumentException("serviceProvider does not provide an IProvideValueTarget");
+ var namescopeprovider = serviceProvider.GetService(typeof (INameScopeProvider)) as INameScopeProvider;
+ if (namescopeprovider != null && namescopeprovider.NameScope != null)
+ {
+ var value = namescopeprovider.NameScope.FindByName(Name);
+ if (value != null)
+ return value;
+ }
+
+ foreach (var target in valueProvider.ParentObjects)
+ {
+ var ns = target as INameScope;
+ if (ns == null)
+ continue;
+ var value = ns.FindByName(Name);
+ if (value != null)
+ return value;
+ }
+
+ var lineInfo = (serviceProvider?.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider)?.XmlLineInfo ?? new XmlLineInfo();
+ throw new XamlParseException($"Can not find the object referenced by `{Name}`", lineInfo);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Xml;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty(nameof(Member))]
+ [ProvideCompiled("Tizen.NUI.Xaml.Build.Tasks.StaticExtension")]
+ internal class StaticExtension : IMarkupExtension
+ {
+ public string Member { get; set; }
+
+ public object ProvideValue(IServiceProvider serviceProvider)
+ {
+ IXmlLineInfoProvider lineInfoProvider;
+ IXmlLineInfo lineInfo;
+
+ if (serviceProvider == null)
+ throw new ArgumentNullException(nameof(serviceProvider));
+ var typeResolver = serviceProvider.GetService(typeof (IXamlTypeResolver)) as IXamlTypeResolver;
+ if (typeResolver == null)
+ throw new ArgumentException("No IXamlTypeResolver in IServiceProvider");
+
+ if (string.IsNullOrEmpty(Member) || !Member.Contains("."))
+ {
+ lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException("Syntax for x:Static is [Member=][prefix:]typeName.staticMemberName", lineInfo);
+ }
+
+ var dotIdx = Member.LastIndexOf('.');
+ var typename = Member.Substring(0, dotIdx);
+ var membername = Member.Substring(dotIdx + 1);
+
+ var type = typeResolver.Resolve(typename, serviceProvider);
+
+ var pinfo = type.GetRuntimeProperties().FirstOrDefault(pi => pi.Name == membername && pi.GetMethod.IsStatic);
+ if (pinfo != null)
+ return pinfo.GetMethod.Invoke(null, new object[] { });
+
+ var finfo = type.GetRuntimeFields().FirstOrDefault(fi => fi.Name == membername && fi.IsStatic);
+ if (finfo != null)
+ return finfo.GetValue(null);
+
+ lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException($"No static member found for {Member}", lineInfo);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Xml;
+using System.Reflection;
+using System.Linq;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty("Key")]
+ internal sealed class StaticResourceExtension : IMarkupExtension
+ {
+ public string Key { get; set; }
+
+ public object ProvideValue(EXamlContext context)
+ {
+ object ret = null;
+ context.resourceDictionary.TryGetValue(Key, out ret);
+
+ if (null == ret)
+ {
+ throw new Exception(String.Format("Key {0} can't be found in Resource", Key));
+ }
+
+ return ret;
+ }
+
+ public object ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ throw new ArgumentNullException(nameof(serviceProvider));
+ if (Key == null) {
+ var lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException("you must specify a key in {StaticResource}", lineInfo);
+ }
+ var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideParentValues;
+ if (valueProvider == null)
+ throw new ArgumentException();
+ var xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ var xmlLineInfo = xmlLineInfoProvider != null ? xmlLineInfoProvider.XmlLineInfo : null;
+ object resource = null;
+
+ foreach (var p in valueProvider.ParentObjects) {
+ var irp = p as IResourcesProvider;
+ var resDict = irp != null && irp.IsResourcesCreated ? irp.Resources : p as ResourceDictionary;
+ if (resDict == null)
+ continue;
+ if (resDict.TryGetValue(Key, out resource))
+ break;
+ }
+ resource = resource ?? GetApplicationLevelResource(Key, xmlLineInfo);
+
+ var bp = valueProvider.TargetProperty as BindableProperty;
+ var pi = valueProvider.TargetProperty as PropertyInfo;
+ var propertyType = bp?.ReturnType ?? pi?.PropertyType;
+ if (propertyType == null) {
+ if (resource != null) {
+ if (resource.GetType().GetTypeInfo().IsGenericType && (resource.GetType().GetGenericTypeDefinition() == typeof(OnPlatform<>) || resource.GetType().GetGenericTypeDefinition() == typeof(OnIdiom<>))) {
+ // This is only there to support our backward compat story with pre 2.3.3 compiled Xaml project who was not providing TargetProperty
+ var method = resource.GetType().GetRuntimeMethod("op_Implicit", new[] { resource.GetType() });
+ if (method != null) {
+ resource = method.Invoke(null, new[] { resource });
+ }
+ }
+ }
+ return resource;
+ }
+ if (propertyType.IsAssignableFrom(resource?.GetType()))
+ return resource;
+ var implicit_op = resource?.GetType().GetImplicitConversionOperator(fromType: resource?.GetType(), toType: propertyType)
+ ?? propertyType.GetImplicitConversionOperator(fromType: resource?.GetType(), toType: propertyType);
+ if (implicit_op != null)
+ return implicit_op.Invoke(resource, new [] { resource });
+
+ if (resource != null) {
+ //Special case for https://bugzilla.xamarin.com/show_bug.cgi?id=59818
+ //On OnPlatform, check for an opImplicit from the targetType
+ if ( Device.Flags != null
+ && Device.Flags.Contains("xamlDoubleImplicitOpHack")
+ && resource.GetType().GetTypeInfo().IsGenericType
+ && (resource.GetType().GetGenericTypeDefinition() == typeof(OnPlatform<>))) {
+ var tType = resource.GetType().GenericTypeArguments[0];
+ var opImplicit = tType.GetImplicitConversionOperator(fromType: tType, toType: propertyType)
+ ?? propertyType.GetImplicitConversionOperator(fromType: tType, toType: propertyType);
+
+ if (opImplicit != null) {
+ //convert the OnPlatform<T> to T
+ var opPlatformImplicitConversionOperator = resource?.GetType().GetImplicitConversionOperator(fromType: resource?.GetType(), toType: tType);
+ resource = opPlatformImplicitConversionOperator?.Invoke(null, new[] { resource });
+
+ //and convert to toType
+ resource = opImplicit.Invoke(null, new[] { resource });
+ return resource;
+ }
+ }
+ }
+ return resource;
+ }
+
+ internal object GetApplicationLevelResource(string key, IXmlLineInfo xmlLineInfo)
+ {
+ object resource = null;
+ if (Application.Current == null || !((IResourcesProvider)Application.Current).IsResourcesCreated || !Application.Current.Resources.TryGetValue(Key, out resource))
+ throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
+ return resource;
+ }
+ }
+}
--- /dev/null
+using System;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty("Path")]
+ [AcceptEmptyServiceProvider]
+ internal sealed class TemplateBindingExtension : IMarkupExtension<BindingBase>
+ {
+ internal TemplateBindingExtension()
+ {
+ Mode = BindingMode.Default;
+ Path = Tizen.NUI.Binding.Binding.SelfPath;
+ }
+
+ public string Path { get; set; }
+
+ public BindingMode Mode { get; set; }
+
+ public IValueConverter Converter { get; set; }
+
+ public object ConverterParameter { get; set; }
+
+ public string StringFormat { get; set; }
+
+ BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceProvider)
+ {
+ return new TemplateBinding(Path, Mode, Converter, ConverterParameter, StringFormat);
+ }
+
+ object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
+ {
+ return (this as IMarkupExtension<BindingBase>).ProvideValue(serviceProvider);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ [ContentProperty(nameof(TypeName))]
+ [ProvideCompiled("Tizen.NUI.Xaml.Build.Tasks.TypeExtension")]
+ internal class TypeExtension : IMarkupExtension<Type>
+ {
+ public string TypeName { get; set; }
+
+ public Type ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (string.IsNullOrEmpty(TypeName))
+ throw new InvalidOperationException("TypeName isn't set.");
+ if (serviceProvider == null)
+ throw new ArgumentNullException(nameof(serviceProvider));
+ var typeResolver = serviceProvider.GetService(typeof (IXamlTypeResolver)) as IXamlTypeResolver;
+ if (typeResolver == null)
+ throw new ArgumentException("No IXamlTypeResolver in IServiceProvider");
+
+ return typeResolver.Resolve(TypeName, serviceProvider);
+ }
+
+ object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
+ {
+ return (this as IMarkupExtension<Type>).ProvideValue(serviceProvider);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class NamescopingVisitor : IXamlNodeVisitor
+ {
+ readonly Dictionary<INode, INameScope> scopes = new Dictionary<INode, INameScope>();
+
+ public NamescopingVisitor(HydrationContext context)
+ {
+ Values = context.Values;
+ }
+
+ Dictionary<INode, object> Values { get; set; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => false;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+ public bool IsResourceDictionary(ElementNode node) => false;
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ scopes[node] = scopes[parentNode];
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ scopes[node] = scopes[parentNode];
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ var ns = parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode) || IsVisualStateGroupList(node)
+ ? new NameScope()
+ : scopes[parentNode];
+ node.Namescope = ns;
+ scopes[node] = ns;
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ var ns = new NameScope();
+ node.Namescope = ns;
+ scopes[node] = ns;
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ scopes[node] = scopes[parentNode];
+ }
+
+ static bool IsDataTemplate(INode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode createContent;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
+ createContent == node)
+ return true;
+ return false;
+ }
+
+ static bool IsStyle(INode node, INode parentNode)
+ {
+ var pnode = parentNode as ElementNode;
+ return pnode != null && pnode.XmlType.Name == "Style";
+ }
+
+ static bool IsVisualStateGroupList(ElementNode node)
+ {
+ return node != null && node.XmlType.Name == "VisualStateGroup" && node.Parent is IListNode;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
+ internal sealed class ProvideCompiledAttribute : Attribute
+ {
+ public string CompiledVersion { get; }
+
+ public ProvideCompiledAttribute (string compiledVersion)
+ {
+ CompiledVersion = compiledVersion;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class PruneIgnoredNodesVisitor : IXamlNodeVisitor
+ {
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => false;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+ public bool IsResourceDictionary(ElementNode node) => false;
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ foreach (var propertyKvp in node.Properties)
+ {
+ var propertyName = propertyKvp.Key;
+ var propertyValue = (propertyKvp.Value as ValueNode)?.Value as string;
+ if (propertyValue == null)
+ continue;
+ if (!propertyName.Equals(XamlParser.McUri, "Ignorable"))
+ continue;
+ (parentNode.IgnorablePrefixes ?? (parentNode.IgnorablePrefixes = new List<string>())).AddRange(propertyValue.Split(','));
+ }
+
+ foreach (var propertyKvp in node.Properties.ToList())
+ {
+ // skip d:foo="bar"
+ var prefix = node.NamespaceResolver.LookupPrefix(propertyKvp.Key.NamespaceURI);
+ if (node.SkipPrefix(prefix))
+ node.Properties.Remove(propertyKvp.Key);
+ var propNs = (propertyKvp.Value as IElementNode)?.NamespaceURI ?? "";
+ var propPrefix = node.NamespaceResolver.LookupPrefix(propNs);
+ if (node.SkipPrefix(propPrefix))
+ node.Properties.Remove(propertyKvp.Key);
+ }
+
+ foreach (var prop in node.CollectionItems.ToList())
+ {
+ var propNs = (prop as IElementNode)?.NamespaceURI ?? "";
+ var propPrefix = node.NamespaceResolver.LookupPrefix(propNs);
+ if (node.SkipPrefix(propPrefix))
+ node.CollectionItems.Remove(prop);
+ }
+
+ if (node.SkipPrefix(node.NamespaceResolver.LookupPrefix(node.NamespaceURI)))
+ {
+ node.Properties.Clear();
+ node.CollectionItems.Clear();
+ }
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ Visit((ElementNode)node, node);
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ foreach (var prop in node.CollectionItems.ToList())
+ {
+ var propNs = (prop as IElementNode)?.NamespaceURI ?? "";
+ var propPrefix = node.NamespaceResolver.LookupPrefix(propNs);
+ if (node.SkipPrefix(propPrefix))
+ node.CollectionItems.Remove(prop);
+ }
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class ReflectionExtensions
+ {
+ public static FieldInfo GetField(this Type type, Func<FieldInfo, bool> predicate)
+ {
+ return GetFields(type).FirstOrDefault(predicate);
+ }
+
+ public static FieldInfo GetField(this Type type, string name)
+ {
+ return type.GetField(fi => fi.Name == name);
+ }
+
+ public static IEnumerable<FieldInfo> GetFields(this Type type)
+ {
+ return GetParts(type, i => i.DeclaredFields);
+ }
+
+ public static IEnumerable<PropertyInfo> GetProperties(this Type type)
+ {
+ return GetParts(type, ti => ti.DeclaredProperties);
+ }
+
+ public static PropertyInfo GetProperty(this Type type, string name)
+ {
+ Type t = type;
+ while (t != null)
+ {
+ System.Reflection.TypeInfo ti = t.GetTypeInfo();
+ PropertyInfo property = ti.GetDeclaredProperty(name);
+ if (property != null)
+ return property;
+
+ t = ti.BaseType;
+ }
+
+ return null;
+ }
+
+ public static bool IsAssignableFrom(this Type self, Type c)
+ {
+ return self.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo());
+ }
+
+ public static bool IsInstanceOfType(this Type self, object o)
+ {
+ return self.GetTypeInfo().IsAssignableFrom(o.GetType().GetTypeInfo());
+ }
+
+ static IEnumerable<T> GetParts<T>(Type type, Func<System.Reflection.TypeInfo, IEnumerable<T>> selector)
+ {
+ Type t = type;
+ while (t != null)
+ {
+ System.Reflection.TypeInfo ti = t.GetTypeInfo();
+ foreach (T f in selector(ti))
+ yield return f;
+ t = ti.BaseType;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class RegisterXNamesVisitor : IXamlNodeVisitor
+ {
+ public RegisterXNamesVisitor(HydrationContext context)
+ {
+ Context = context;
+ Values = context.Values;
+ }
+
+ Dictionary<INode, object> Values { get; }
+ HydrationContext Context { get; }
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+ public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ if (!IsXNameProperty(node, parentNode))
+ return;
+ try
+ {
+ ((IElementNode)parentNode).Namescope.RegisterName((string)node.Value, Values[parentNode]);
+ }
+ catch (ArgumentException ae)
+ {
+ if (ae.ParamName != "name")
+ throw ae;
+ throw new XamlParseException($"An element with the name \"{(string)node.Value}\" already exists in this NameScope", node);
+ }
+ var element = Values[parentNode] as Element;
+ if (element != null)
+ element.StyleId = element.StyleId ?? (string)node.Value;
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ static bool IsXNameProperty(ValueNode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode xNameNode;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
+ return true;
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Reflection;
+using Tizen.NUI;
+using System.Xml;
+using Tizen.NUI.Binding.Internals;
+
+// [assembly:Dependency(typeof(Tizen.NUI.Xaml.ResourcesLoader))]
+namespace Tizen.NUI.Xaml
+{
+ internal class ResourcesLoader : IResourcesLoader
+ {
+ public T CreateFromResource<T>(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo) where T: new()
+ {
+ var alternateResource = ResourceLoader.ResourceProvider?.Invoke(assembly.GetName(), resourcePath);
+ if (alternateResource != null) {
+ var rd = new T();
+ rd.LoadFromXaml(alternateResource);
+ return rd;
+ }
+
+ var resourceId = XamlResourceIdAttribute.GetResourceIdForPath(assembly, resourcePath);
+ if (resourceId == null)
+ throw new XamlParseException($"Resource '{resourcePath}' not found.", lineInfo);
+
+ using (var stream = assembly.GetManifestResourceStream(resourceId)) {
+ if (stream == null)
+ throw new XamlParseException($"No resource found for '{resourceId}'.", lineInfo);
+ using (var reader = new StreamReader(stream)) {
+ var rd = new T();
+ rd.LoadFromXaml(reader.ReadToEnd());
+ return rd;
+ }
+ }
+ }
+
+ public string GetResource(string resourcePath, Assembly assembly, IXmlLineInfo lineInfo)
+ {
+ var alternateResource = ResourceLoader.ResourceProvider?.Invoke(assembly.GetName(), resourcePath);
+ if (alternateResource != null)
+ return alternateResource;
+
+ var resourceId = XamlResourceIdAttribute.GetResourceIdForPath(assembly, resourcePath);
+ if (resourceId == null)
+ throw new XamlParseException($"Resource '{resourcePath}' not found.", lineInfo);
+
+ 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();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ internal sealed class RuntimeNamePropertyAttribute : Attribute
+ {
+ public RuntimeNamePropertyAttribute(string name)
+ {
+ Name = name;
+ }
+
+ public string Name { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+
+using System.Collections.Generic;
+using System.Xml;
+
+namespace Tizen.NUI.Xaml
+{
+ internal static class TypeArgumentsParser
+ {
+ public static IList<XmlType> ParseExpression(string expression, IXmlNamespaceResolver resolver, IXmlLineInfo lineInfo)
+ {
+ var typeList = new List<XmlType>();
+ while (!string.IsNullOrWhiteSpace(expression))
+ {
+ var match = expression;
+ typeList.Add(Parse(match, ref expression, resolver, lineInfo));
+ }
+ return typeList;
+ }
+
+ static XmlType Parse(string match, ref string remaining, IXmlNamespaceResolver resolver, IXmlLineInfo lineinfo)
+ {
+ remaining = null;
+ int parensCount = 0;
+ int pos = 0;
+ bool isGeneric = false;
+
+ for (pos = 0; pos < match.Length; pos++)
+ {
+ if (match[pos] == '(')
+ {
+ parensCount++;
+ isGeneric = true;
+ }
+ else if (match[pos] == ')')
+ parensCount--;
+ else if (match[pos] == ',' && parensCount == 0)
+ {
+ remaining = match.Substring(pos + 1);
+ break;
+ }
+ }
+ var type = match.Substring(0, pos).Trim();
+
+ IList<XmlType> typeArguments = null;
+ if (isGeneric)
+ {
+ typeArguments = ParseExpression(
+ type.Substring(type.IndexOf('(') + 1, type.LastIndexOf(')') - type.IndexOf('(') - 1), resolver, lineinfo);
+ type = type.Substring(0, type.IndexOf('('));
+ }
+
+ var split = type.Split(':');
+ if (split.Length > 2)
+ return null;
+
+ string prefix, name;
+ if (split.Length == 2) {
+ prefix = split [0];
+ name = split [1];
+ } else {
+ prefix = "";
+ name = split [0];
+ }
+
+ var namespaceuri = resolver.LookupNamespace(prefix);
+ if (namespaceuri == null)
+ throw new XamlParseException($"No xmlns declaration for prefix '{prefix}'.", lineinfo, null);
+ return new XmlType(namespaceuri, name, typeArguments);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ [System.AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
+ internal sealed class TypeConversionAttribute : Attribute
+ {
+ public Type TargetType { get; private set; }
+
+ public TypeConversionAttribute(Type targetType)
+ {
+ TargetType = targetType;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// TypeConversionExtensions.cs
+//
+// Author:
+// Stephane Delcroix <stephane@mi8.be>
+//
+// Copyright (c) 2013 Mobile Inception
+// Copyright (c) 2014 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Tizen.NUI.Xaml.Internals;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ internal static class TypeConversionExtensions
+ {
+ internal static object ConvertTo(this object value, Type toType, Func<ParameterInfo> pinfoRetriever,
+ IServiceProvider serviceProvider)
+ {
+ Func<TypeConverter> getConverter = () =>
+ {
+ ParameterInfo pInfo;
+ if (pinfoRetriever == null || (pInfo = pinfoRetriever()) == null)
+ return null;
+
+ var converterTypeName = pInfo.CustomAttributes.GetTypeConverterTypeName();
+ if (converterTypeName == null)
+ return null;
+ var convertertype = Type.GetType(converterTypeName);
+ return (TypeConverter)Activator.CreateInstance(convertertype);
+ };
+
+ return ConvertTo(value, toType, getConverter, serviceProvider);
+ }
+
+ internal static object ConvertTo(this object value, Type toType, Func<MemberInfo> minfoRetriever,
+ IServiceProvider serviceProvider)
+ {
+ Func<object> getConverter = () =>
+ {
+ MemberInfo memberInfo;
+
+ var converterTypeName = toType.GetTypeInfo().CustomAttributes.GetTypeConverterTypeName();
+ if (minfoRetriever != null && (memberInfo = minfoRetriever()) != null)
+ converterTypeName = memberInfo.CustomAttributes.GetTypeConverterTypeName() ?? converterTypeName;
+ if (converterTypeName == null)
+ return null;
+
+ var convertertype = Type.GetType(converterTypeName);
+ object ret = Activator.CreateInstance(convertertype);
+ return ret;
+ };
+
+ return ConvertTo(value, toType, getConverter, serviceProvider);
+ }
+
+ static string GetTypeConverterTypeName(this IEnumerable<CustomAttributeData> attributes)
+ {
+ var converterAttribute =
+ attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName));
+ if (converterAttribute == null)
+ return null;
+ if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (string))
+ return (string)converterAttribute.ConstructorArguments[0].Value;
+ if (converterAttribute.ConstructorArguments[0].ArgumentType == typeof (Type))
+ return ((Type)converterAttribute.ConstructorArguments[0].Value).AssemblyQualifiedName;
+ return null;
+ }
+
+ //Don't change the name or the signature of this, it's used by XamlC
+ public static object ConvertTo(this object value, Type toType, Type convertertype, IServiceProvider serviceProvider)
+ {
+ if (convertertype == null)
+ return value.ConvertTo(toType, (Func<object>)null, serviceProvider);
+ Func<object> getConverter = () => Activator.CreateInstance(convertertype);
+ ;
+ return value.ConvertTo(toType, getConverter, serviceProvider);
+ }
+
+ private delegate void ParseValueFunc(string s, IFormatProvider provider);
+
+ static private Dictionary<Type, ParseValueFunc> typeToParseValueFunc = null;
+
+ static private void BuildParseValueFunc()
+ {
+ if (null == typeToParseValueFunc)
+ {
+ typeToParseValueFunc = new Dictionary<Type, ParseValueFunc>();
+
+ }
+ }
+
+ internal static object ConvertTo(this object value, Type toType, Func<object> getConverter,
+ IServiceProvider serviceProvider)
+ {
+ if (value == null)
+ return null;
+
+ var str = value as string;
+ if (str != null)
+ {
+ //If there's a [TypeConverter], use it
+ object converter = getConverter?.Invoke();
+ if (null != converter)
+ {
+ var xfTypeConverter = converter as TypeConverter;
+ var xfExtendedTypeConverter = xfTypeConverter as IExtendedTypeConverter;
+ if (xfExtendedTypeConverter != null)
+ return value = xfExtendedTypeConverter.ConvertFromInvariantString(str, serviceProvider);
+ if (xfTypeConverter != null)
+ return value = xfTypeConverter.ConvertFromInvariantString(str);
+ var converterType = converter?.GetType();
+ if (converterType != null)
+ {
+ var convertFromStringInvariant = converterType.GetRuntimeMethod("ConvertFromInvariantString",
+ new[] { typeof(string) });
+ 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<>))
+ toType = Nullable.GetUnderlyingType(toType);
+
+ //Obvious Built-in conversions
+ if (toType.GetTypeInfo().IsEnum)
+ return Enum.Parse(toType, str, ignoreCase);
+
+ if (toType == typeof(SByte))
+ return SByte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int16))
+ return Int16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int32))
+ return Int32.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Int64))
+ return Int64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Byte))
+ return Byte.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt16))
+ return UInt16.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt32))
+ return UInt32.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(UInt64))
+ return UInt64.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (Single))
+ return Single.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (Double))
+ return Double.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (Boolean))
+ return Boolean.Parse(str);
+ if (toType == typeof (TimeSpan))
+ return TimeSpan.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof (DateTime))
+ return DateTime.Parse(str, CultureInfo.InvariantCulture);
+ if (toType == typeof(Char)) {
+ char c = '\0';
+ Char.TryParse(str, out c);
+ return c;
+ }
+ if (toType == typeof (String) && str.StartsWith("{}", StringComparison.Ordinal))
+ return str.Substring(2);
+ if (toType == typeof (String))
+ return value;
+ if (toType == typeof(Decimal))
+ return Decimal.Parse(str, CultureInfo.InvariantCulture);
+ }
+
+ //if the value is not assignable and there's an implicit conversion, convert
+ if (value != null && !toType.IsAssignableFrom(value.GetType())) {
+ var opImplicit = value.GetType().GetImplicitConversionOperator(fromType: value.GetType(), toType: toType)
+ ?? toType.GetImplicitConversionOperator(fromType: value.GetType(), toType: toType);
+
+ if (opImplicit != null) {
+ value = opImplicit.Invoke(null, new[] { value });
+ return value;
+ }
+ }
+
+ var nativeValueConverterService = DependencyService.Get<INativeValueConverterService>();
+
+ object nativeValue = null;
+ if (nativeValueConverterService != null && nativeValueConverterService.ConvertTo(value, toType, out nativeValue))
+ return nativeValue;
+
+ return value;
+ }
+
+ internal static MethodInfo GetImplicitConversionOperator(this Type onType, Type fromType, Type toType)
+ {
+#if NETSTANDARD1_0
+ var mi = onType.GetRuntimeMethod("op_Implicit", new[] { fromType });
+#else
+ var bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
+ var mi = onType.GetMethod("op_Implicit", bindingFlags, null, new[] { fromType }, null);
+#endif
+ if (mi == null) return null;
+ if (!mi.IsSpecialName) return null;
+ if (!mi.IsPublic) return null;
+ if (!mi.IsStatic) return null;
+ if (!toType.IsAssignableFrom(mi.ReturnType)) return null;
+
+ return mi;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+
+using Tizen.NUI;
+using Tizen.NUI.Xaml;
+
+// [assembly:Dependency(typeof(ValueConverterProvider))]
+namespace Tizen.NUI.Xaml
+{
+ internal class ValueConverterProvider : IValueConverterProvider
+ {
+ public object Convert(object value, Type toType, Func<MemberInfo> minfoRetriever, IServiceProvider serviceProvider)
+ {
+ return value.ConvertTo(toType, minfoRetriever, serviceProvider);
+ }
+ }
+}
--- /dev/null
+//
+// ViewExtensions.cs
+//
+// Author:
+// Stephane Delcroix <stephane@mi8.be>
+//
+// Copyright (c) 2013 Mobile Inception
+// Copyright (c) 2013 Xamarin, Inc
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Reflection;
+using System.ComponentModel;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ /// <summary>
+ /// Extension class for View defining Tizen.NUI.Xaml.Extensions.LoadFromXaml{TView} method.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class Extensions
+ {
+ /// <summary>
+ /// Returns a TXaml with the properties that are defined in the application manifest for callingType.
+ /// </summary>
+ /// <typeparam name="TXaml">The type of view to initialize with state from XAML.</typeparam>
+ /// <param name="view">The view on which this method operates.</param>
+ /// <param name="xaml">The XAML that encodes the view state.</param>
+ /// <returns>A TXaml with the properties that are defined in the application manifest for callingType.</returns>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static TXaml LoadFromXaml<TXaml>(this TXaml view, string xaml)
+ {
+ if (view is Element)
+ {
+ NameScopeExtensions.PushElement(view);
+ }
+
+ XamlLoader.Load(view, xaml);
+
+ if (view is Element)
+ {
+ NameScopeExtensions.PopElement();
+ }
+
+ return view;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ internal static class VisualStateManager
+ {
+ internal class CommonStates
+ {
+ public const string Normal = "Normal";
+ public const string Disabled = "Disabled";
+ public const string Focused = "Focused";
+ }
+
+ public static readonly BindableProperty VisualStateGroupsProperty =
+ BindableProperty.CreateAttached("VisualStateGroups", typeof(VisualStateGroupList), typeof(Element),
+ defaultValue: null, propertyChanged: VisualStateGroupsPropertyChanged,
+ defaultValueCreator: bindable => new VisualStateGroupList());
+
+ static void VisualStateGroupsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ GoToState((Element)bindable, CommonStates.Normal);
+ }
+
+ public static IList<VisualStateGroup> GetVisualStateGroups(Element visualElement)
+ {
+ return (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
+ }
+
+ public static void SetVisualStateGroups(Element visualElement, VisualStateGroupList value)
+ {
+ visualElement.SetValue(VisualStateGroupsProperty, value);
+ }
+
+ public static bool GoToState(Element visualElement, string name)
+ {
+ if (!visualElement.IsSet(VisualStateGroupsProperty))
+ {
+ return false;
+ }
+
+ var groups = (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
+
+ foreach (VisualStateGroup group in groups)
+ {
+ if (group.CurrentState?.Name == name)
+ {
+ // We're already in the target state; nothing else to do
+ return true;
+ }
+
+ // See if this group contains the new state
+ var target = group.GetState(name);
+ if (target == null)
+ {
+ continue;
+ }
+
+ // If we've got a new state to transition to, unapply the setters from the current state
+ if (group.CurrentState != null)
+ {
+ foreach (Setter setter in group.CurrentState.Setters)
+ {
+ setter.UnApply(visualElement);
+ }
+ }
+
+ // Update the current state
+ group.CurrentState = target;
+
+ // Apply the setters from the new state
+ foreach (Setter setter in target.Setters)
+ {
+ setter.Apply(visualElement);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public static bool HasVisualStateGroups(this Element element)
+ {
+ return element.IsSet(VisualStateGroupsProperty);
+ }
+ }
+
+ internal class VisualStateGroupList : IList<VisualStateGroup>
+ {
+ readonly IList<VisualStateGroup> _internalList;
+
+ void Validate(IList<VisualStateGroup> groups)
+ {
+ // If we have 1 group, no need to worry about duplicate group names
+ if (groups.Count > 1)
+ {
+ if (groups.GroupBy(vsg => vsg.Name).Any(g => g.Count() > 1))
+ {
+ throw new InvalidOperationException("VisualStateGroup Names must be unique");
+ }
+ }
+
+ // State names must be unique within this group list, so pull in all
+ // the states in all the groups, group them by name, and see if we have
+ // and duplicates
+ if (groups.SelectMany(group => group.States)
+ .GroupBy(state => state.Name)
+ .Any(g => g.Count() > 1))
+ {
+ throw new InvalidOperationException("VisualState Names must be unique");
+ }
+ }
+
+ public VisualStateGroupList()
+ {
+ _internalList = new WatchAddList<VisualStateGroup>(Validate);
+ }
+
+ void ValidateOnStatesChanged(object sender, EventArgs eventArgs)
+ {
+ Validate(_internalList);
+ }
+
+ public IEnumerator<VisualStateGroup> GetEnumerator()
+ {
+ return _internalList.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)_internalList).GetEnumerator();
+ }
+
+ public void Add(VisualStateGroup item)
+ {
+ _internalList.Add(item);
+ item.StatesChanged += ValidateOnStatesChanged;
+ }
+
+ public void Clear()
+ {
+ foreach (var group in _internalList)
+ {
+ group.StatesChanged -= ValidateOnStatesChanged;
+ }
+
+ _internalList.Clear();
+ }
+
+ public bool Contains(VisualStateGroup item)
+ {
+ return _internalList.Contains(item);
+ }
+
+ public void CopyTo(VisualStateGroup[] array, int arrayIndex)
+ {
+ _internalList.CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(VisualStateGroup item)
+ {
+ item.StatesChanged -= ValidateOnStatesChanged;
+ return _internalList.Remove(item);
+ }
+
+ public int Count => _internalList.Count;
+
+ public bool IsReadOnly => false;
+
+ public int IndexOf(VisualStateGroup item)
+ {
+ return _internalList.IndexOf(item);
+ }
+
+ public void Insert(int index, VisualStateGroup item)
+ {
+ item.StatesChanged += ValidateOnStatesChanged;
+ _internalList.Insert(index, item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ _internalList[index].StatesChanged -= ValidateOnStatesChanged;
+ _internalList.RemoveAt(index);
+ }
+
+ public VisualStateGroup this[int index]
+ {
+ get => _internalList[index];
+ set => _internalList[index] = value;
+ }
+ }
+
+ [RuntimeNameProperty(nameof(Name))]
+ [ContentProperty(nameof(States))]
+ internal sealed class VisualStateGroup
+ {
+ public VisualStateGroup()
+ {
+ States = new WatchAddList<VisualState>(OnStatesChanged);
+ }
+
+ public Type TargetType { get; set; }
+ public string Name { get; set; }
+ public IList<VisualState> States { get; }
+ public VisualState CurrentState { get; internal set; }
+
+ internal VisualState GetState(string name)
+ {
+ foreach (VisualState state in States)
+ {
+ if (string.CompareOrdinal(state.Name, name) == 0)
+ {
+ return state;
+ }
+ }
+
+ return null;
+ }
+
+ internal VisualStateGroup Clone()
+ {
+ var clone = new VisualStateGroup {TargetType = TargetType, Name = Name, CurrentState = CurrentState};
+ foreach (VisualState state in States)
+ {
+ clone.States.Add(state.Clone());
+ }
+
+ return clone;
+ }
+
+ internal event EventHandler StatesChanged;
+
+ void OnStatesChanged(IList<VisualState> list)
+ {
+ if (list.Any(state => string.IsNullOrEmpty(state.Name)))
+ {
+ throw new InvalidOperationException("State names may not be null or empty");
+ }
+
+ StatesChanged?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
+ [RuntimeNameProperty(nameof(Name))]
+ internal sealed class VisualState
+ {
+ public VisualState()
+ {
+ Setters = new ObservableCollection<Setter>();
+ }
+
+ public string Name { get; set; }
+ public IList<Setter> Setters { get;}
+ public Type TargetType { get; set; }
+
+ internal VisualState Clone()
+ {
+ var clone = new VisualState { Name = Name, TargetType = TargetType };
+ foreach (var setter in Setters)
+ {
+ clone.Setters.Add(setter);
+ }
+
+ return clone;
+ }
+ }
+
+ internal static class VisualStateGroupListExtensions
+ {
+ internal static IList<VisualStateGroup> Clone(this IList<VisualStateGroup> groups)
+ {
+ var actual = new VisualStateGroupList();
+ foreach (var group in groups)
+ {
+ actual.Add(group.Clone());
+ }
+
+ return actual;
+ }
+ }
+
+ internal class WatchAddList<T> : IList<T>
+ {
+ readonly Action<List<T>> _onAdd;
+ readonly List<T> _internalList;
+
+ public WatchAddList(Action<List<T>> onAdd)
+ {
+ _onAdd = onAdd;
+ _internalList = new List<T>();
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ return _internalList.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)_internalList).GetEnumerator();
+ }
+
+ public void Add(T item)
+ {
+ _internalList.Add(item);
+ _onAdd(_internalList);
+ }
+
+ public void Clear()
+ {
+ _internalList.Clear();
+ }
+
+ public bool Contains(T item)
+ {
+ return _internalList.Contains(item);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ _internalList.CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(T item)
+ {
+ return _internalList.Remove(item);
+ }
+
+ public int Count => _internalList.Count;
+
+ public bool IsReadOnly => false;
+
+ public int IndexOf(T item)
+ {
+ return _internalList.IndexOf(item);
+ }
+
+ public void Insert(int index, T item)
+ {
+ _internalList.Insert(index, item);
+ _onAdd(_internalList);
+ }
+
+ public void RemoveAt(int index)
+ {
+ _internalList.RemoveAt(index);
+ }
+
+ public T this[int index]
+ {
+ get => _internalList[index];
+ set => _internalList[index] = value;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace Tizen.NUI.Xaml
+{
+ [Flags]
+ internal enum XamlCompilationOptions
+ {
+ Skip = 1 << 0,
+ Compile = 1 << 1
+ }
+
+ //[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class, Inherited = false)]
+ //public sealed class XamlCompilationAttribute : Attribute
+ //{
+ // public XamlCompilationAttribute(XamlCompilationOptions xamlCompilationOptions)
+ // {
+ // XamlCompilationOptions = xamlCompilationOptions;
+ // }
+
+ // public XamlCompilationOptions XamlCompilationOptions { get; set; }
+ //}
+
+ //internal static class XamlCExtensions
+ //{
+ // public static bool IsCompiled(this Type type)
+ // {
+ // var attr = type.GetTypeInfo().GetCustomAttribute<XamlCompilationAttribute>();
+ // if (attr != null)
+ // return attr.XamlCompilationOptions == XamlCompilationOptions.Compile;
+ // attr = type.GetTypeInfo().Module.GetCustomAttribute<XamlCompilationAttribute>();
+ // if (attr != null)
+ // return attr.XamlCompilationOptions == XamlCompilationOptions.Compile;
+ // attr = type.GetTypeInfo().Assembly.GetCustomAttribute<XamlCompilationAttribute>();
+ // if (attr != null)
+ // return attr.XamlCompilationOptions == XamlCompilationOptions.Compile;
+
+ // return false;
+ // }
+ //}
+}
\ No newline at end of file
--- /dev/null
+//
+// XamlLoader.cs
+//
+// Author:
+// Stephane Delcroix <stephane@mi8.be>
+//
+// Copyright (c) 2018 Mobile Inception
+// Copyright (c) 2018-2014 Xamarin, Inc
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using System.Xml;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Xaml.Internals
+{
+ [Obsolete ("Replaced by ResourceLoader")]
+ internal static class XamlLoader
+ {
+ static Func<Type, string> xamlFileProvider;
+
+ public static Func<Type, string> XamlFileProvider {
+ get { return xamlFileProvider; }
+ internal set {
+ xamlFileProvider = value;
+ Tizen.NUI.Xaml.DesignMode.IsDesignModeEnabled = true;
+ //¯\_(ツ)_/¯ the previewer forgot to set that bool
+ DoNotThrowOnExceptions = value != null;
+ }
+ }
+
+ internal static bool DoNotThrowOnExceptions { get; set; }
+ }
+}
+
+namespace Tizen.NUI.Xaml
+{
+ static internal class XamlLoader
+ {
+ public static void Load(object view, string xaml)
+ {
+ using (var textReader = new StringReader(xaml))
+ using (var reader = XmlReader.Create(textReader))
+ {
+ while (reader.Read())
+ {
+ //Skip until element
+ if (reader.NodeType == XmlNodeType.Whitespace)
+ continue;
+ if (reader.NodeType == XmlNodeType.XmlDeclaration)
+ continue;
+ if (reader.NodeType != XmlNodeType.Element) {
+ Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
+ continue;
+ }
+
+ for (int i = 0; i < 100; i++)
+ {
+ XmlType temp = new XmlType(reader.NamespaceURI, reader.Name, null);
+ }
+
+ XmlType xmlType = new XmlType(reader.NamespaceURI, reader.Name, null);
+
+ for (int i = 0; i < 100; i++)
+ {
+ new RuntimeRootNode(xmlType, view, (IXmlNamespaceResolver)reader);
+ }
+
+ var rootnode = new RuntimeRootNode (xmlType, view, (IXmlNamespaceResolver)reader);
+ XamlParser.ParseXaml (rootnode, reader);
+ Visit (rootnode, new HydrationContext {
+ RootElement = view,
+#pragma warning disable 0618
+ ExceptionHandler = ResourceLoader.ExceptionHandler ?? (Internals.XamlLoader.DoNotThrowOnExceptions ? e => { }: (Action<Exception>)null)
+#pragma warning restore 0618
+ });
+ break;
+ }
+ }
+ }
+
+ [Obsolete ("Use the XamlFileProvider to provide xaml files. We will remove this when Cycle 8 hits Stable.")]
+ public static object Create (string xaml, bool doNotThrow = false)
+ {
+ object inflatedView = null;
+ using (var textreader = new StringReader(xaml))
+ using (var reader = XmlReader.Create (textreader)) {
+ while (reader.Read ()) {
+ //Skip until element
+ if (reader.NodeType == XmlNodeType.Whitespace)
+ continue;
+ if (reader.NodeType == XmlNodeType.XmlDeclaration)
+ continue;
+ if (reader.NodeType != XmlNodeType.Element) {
+ Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
+ continue;
+ }
+
+ var rootnode = new RuntimeRootNode (new XmlType (reader.NamespaceURI, reader.Name, null), null, (IXmlNamespaceResolver)reader);
+ XamlParser.ParseXaml (rootnode, reader);
+ var visitorContext = new HydrationContext {
+ ExceptionHandler = doNotThrow ? e => { } : (Action<Exception>)null,
+ };
+ var cvv = new CreateValuesVisitor (visitorContext);
+ cvv.Visit ((ElementNode)rootnode, null);
+ inflatedView = rootnode.Root = visitorContext.Values [rootnode];
+ visitorContext.RootElement = inflatedView as BindableObject;
+
+ Visit (rootnode, visitorContext);
+ break;
+ }
+ }
+ return inflatedView;
+ }
+
+ static void Visit (RootNode rootnode, HydrationContext visitorContext)
+ {
+ rootnode.Accept (new XamlNodeVisitor ((node, parent) => node.Parent = parent), null); //set parents for {StaticResource}
+ rootnode.Accept (new ExpandMarkupsVisitor (visitorContext), null);
+ rootnode.Accept (new PruneIgnoredNodesVisitor(), null);
+ rootnode.Accept (new NamescopingVisitor (visitorContext), null); //set namescopes for {x:Reference}
+ rootnode.Accept (new CreateValuesVisitor (visitorContext), null);
+ rootnode.Accept (new RegisterXNamesVisitor (visitorContext), null);
+ rootnode.Accept (new FillResourceDictionariesVisitor (visitorContext), null);
+ rootnode.Accept (new ApplyPropertiesVisitor (visitorContext, true), null);
+ }
+
+ static string LoadObjectFromXaml(string animationXamlPath)
+ {
+ string xaml;
+ if (File.Exists(animationXamlPath))
+ {
+ StreamReader reader = new StreamReader(animationXamlPath);
+ xaml = reader.ReadToEnd();
+ return xaml;
+ }
+
+ return null;
+ }
+ //if the assembly was generated using a version of XamlG that doesn't outputs XamlResourceIdAttributes, we still need to find the resource, and load it
+
+ // static string GetXamlForType(Type type)
+ // {
+ // //the Previewer might want to provide it's own xaml for this... let them do that
+ // //the check at the end is preferred (using ResourceLoader). keep this until all the previewers are updated
+
+ // string xaml;
+ //#pragma warning disable 0618
+ // if (ResourceLoader.ResourceProvider == null && (xaml = Internals.XamlLoader.XamlFileProvider?.Invoke(type)) != null)
+ // return xaml;
+ //#pragma warning restore 0618
+
+ // var assembly = type.GetTypeInfo().Assembly;
+ // var resourceId = XamlResourceIdAttribute.GetResourceIdForType(type);
+
+ // if (resourceId == null)
+ // return LegacyGetXamlForType(type);
+
+ // using (var stream = assembly.GetManifestResourceStream(resourceId))
+ // {
+ // if (stream != null)
+ // using (var reader = new StreamReader(stream))
+ // xaml = reader.ReadToEnd();
+ // else
+ // xaml = null;
+ // }
+
+ // var alternateXaml = ResourceLoader.ResourceProvider?.Invoke(assembly.GetName(), XamlResourceIdAttribute.GetPathForType(type));
+ // return alternateXaml ?? xaml;
+ // }
+
+ static readonly Dictionary<Type, string> XamlResources = new Dictionary<Type, string>();
+ static string LegacyGetXamlForType(Type type)
+ {
+ var assembly = type.GetTypeInfo().Assembly;
+
+ string resourceId;
+ if (XamlResources.TryGetValue(type, out resourceId)) {
+ var result = ReadResourceAsXaml(type, assembly, resourceId);
+ if (result != null)
+ return result;
+ }
+
+ var likelyResourceName = type.Name + ".xaml";
+ var resourceNames = assembly.GetManifestResourceNames();
+ string resourceName = null;
+
+ // first pass, pray to find it because the user named it correctly
+
+ foreach (var resource in resourceNames) {
+ if (ResourceMatchesFilename(assembly, resource, likelyResourceName)) {
+ resourceName = resource;
+ var xaml = ReadResourceAsXaml(type, assembly, resource);
+ if (xaml != null)
+ return xaml;
+ }
+ }
+
+ // okay maybe they at least named it .xaml
+
+ foreach (var resource in resourceNames) {
+ if (!resource.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase))
+ continue;
+
+ resourceName = resource;
+ var xaml = ReadResourceAsXaml(type, assembly, resource);
+ if (xaml != null)
+ return xaml;
+ }
+
+ foreach (var resource in resourceNames) {
+ if (resource.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase))
+ continue;
+
+ resourceName = resource;
+ var xaml = ReadResourceAsXaml(type, assembly, resource, true);
+ if (xaml != null)
+ return xaml;
+ }
+
+ return null;
+ }
+
+ //legacy...
+ static bool ResourceMatchesFilename(Assembly assembly, string resource, string filename)
+ {
+ try {
+ var info = assembly.GetManifestResourceInfo(resource);
+
+ if (!string.IsNullOrEmpty(info.FileName) &&
+ string.Compare(info.FileName, filename, StringComparison.OrdinalIgnoreCase) == 0)
+ return true;
+ }
+ catch (PlatformNotSupportedException) {
+ // Because Win10 + .NET Native
+ }
+
+ if (resource.EndsWith("." + filename, StringComparison.OrdinalIgnoreCase) ||
+ string.Compare(resource, filename, StringComparison.OrdinalIgnoreCase) == 0)
+ return true;
+
+ return false;
+ }
+
+ //part of the legacy as well...
+ static string ReadResourceAsXaml(Type type, Assembly assembly, string likelyTargetName, bool validate = false)
+ {
+ using (var stream = assembly.GetManifestResourceStream(likelyTargetName))
+ using (var reader = new StreamReader(stream)) {
+ if (validate) {
+ // terrible validation of XML. Unfortunately it will probably work most of the time since comments
+ // also start with a <. We can't bring in any real deps.
+
+ var firstNonWhitespace = (char)reader.Read();
+ while (char.IsWhiteSpace(firstNonWhitespace))
+ firstNonWhitespace = (char)reader.Read();
+
+ if (firstNonWhitespace != '<')
+ return null;
+
+ stream.Seek(0, SeekOrigin.Begin);
+ }
+
+ var xaml = reader.ReadToEnd();
+
+ var pattern = String.Format("x:Class *= *\"{0}\"", type.FullName);
+ var regex = new Regex(pattern, RegexOptions.ECMAScript);
+ if (regex.IsMatch(xaml) || xaml.Contains(String.Format("x:Class=\"{0}\"", type.FullName)))
+ return xaml;
+ }
+ return null;
+ }
+
+ public class RuntimeRootNode : RootNode
+ {
+ public RuntimeRootNode(XmlType xmlType, object root, IXmlNamespaceResolver resolver) : base (xmlType, resolver)
+ {
+ Root = root;
+ }
+
+ public object Root { get; internal set; }
+ }
+ }
+}
--- /dev/null
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Xml;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface INode
+ {
+ List<string> IgnorablePrefixes { get; set; }
+
+ IXmlNamespaceResolver NamespaceResolver { get; }
+
+ INode Parent { get; set; }
+
+ void Accept(IXamlNodeVisitor visitor, INode parentNode);
+ INode Clone();
+ }
+
+ internal interface IValueNode : INode
+ {
+ }
+
+ internal interface IElementNode : INode, IListNode
+ {
+ Dictionary<XmlName, INode> Properties { get; }
+ List<XmlName> SkipProperties { get; }
+ INameScope Namescope { get; }
+ XmlType XmlType { get; }
+ string NamespaceURI { get; }
+ }
+
+ internal interface IListNode : INode
+ {
+ List<INode> CollectionItems { get; }
+ }
+
+ [DebuggerDisplay("{NamespaceUri}:{Name}")]
+ internal class XmlType
+ {
+ public XmlType(string namespaceUri, string name, IList<XmlType> typeArguments)
+ {
+ NamespaceUri = namespaceUri;
+ Name = name;
+ TypeArguments = typeArguments;
+ }
+
+ public string NamespaceUri { get; }
+ public string Name { get; }
+ public IList<XmlType> TypeArguments { get; }
+ }
+
+ internal abstract class BaseNode : IXmlLineInfo, INode
+ {
+ protected BaseNode(IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
+ {
+ NamespaceResolver = namespaceResolver;
+ LineNumber = linenumber;
+ LinePosition = lineposition;
+ }
+
+ public IXmlNamespaceResolver NamespaceResolver { get; }
+ public INode Parent { get; set; }
+ public List<string> IgnorablePrefixes { get; set; }
+ public int LineNumber { get; set; }
+ public int LinePosition { get; set; }
+
+ public bool HasLineInfo() => LineNumber >= 0 && LinePosition >= 0;
+
+ public abstract void Accept(IXamlNodeVisitor visitor, INode parentNode);
+ public abstract INode Clone();
+ }
+
+ [DebuggerDisplay("{Value}")]
+ internal class ValueNode : BaseNode, IValueNode
+ {
+ public ValueNode(object value, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
+ : base(namespaceResolver, linenumber, lineposition)
+ {
+ Value = value;
+ }
+
+ public object Value { get; set; }
+
+ public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
+ {
+ visitor.Visit(this, parentNode);
+ }
+
+ public override INode Clone() => new ValueNode(Value, NamespaceResolver, LineNumber, LinePosition) {
+ IgnorablePrefixes = IgnorablePrefixes
+ };
+ }
+
+ [DebuggerDisplay("{MarkupString}")]
+ internal class MarkupNode : BaseNode, IValueNode
+ {
+ public MarkupNode(string markupString, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
+ : base(namespaceResolver, linenumber, lineposition)
+ {
+ MarkupString = markupString;
+ }
+
+ public string MarkupString { get; }
+
+ public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
+ {
+ visitor.Visit(this, parentNode);
+ }
+
+ public override INode Clone() => new MarkupNode(MarkupString, NamespaceResolver, LineNumber, LinePosition) {
+ IgnorablePrefixes = IgnorablePrefixes
+ };
+ }
+
+ [DebuggerDisplay("{XmlType.Name}")]
+ internal class ElementNode : BaseNode, IValueNode, IElementNode
+ {
+ public ElementNode(XmlType type, string namespaceURI, IXmlNamespaceResolver namespaceResolver, int linenumber = -1,
+ int lineposition = -1)
+ : base(namespaceResolver, linenumber, lineposition)
+ {
+ Properties = new Dictionary<XmlName, INode>();
+ SkipProperties = new List<XmlName>();
+ CollectionItems = new List<INode>();
+ XmlType = type;
+ NamespaceURI = namespaceURI;
+ }
+
+ public Dictionary<XmlName, INode> Properties { get; }
+ public List<XmlName> SkipProperties { get; }
+ public List<INode> CollectionItems { get; }
+ public XmlType XmlType { get; }
+ public string NamespaceURI { get; }
+ public INameScope Namescope { get; set; }
+
+ public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
+ {
+ if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.TopDown)
+ visitor.Visit(this, parentNode);
+
+ if (!SkipChildren(visitor, this, parentNode)) {
+ foreach (var node in Properties.Values.ToList())
+ node.Accept(visitor, this);
+ foreach (var node in CollectionItems)
+ node.Accept(visitor, this);
+ }
+
+ if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.BottomUp)
+ visitor.Visit(this, parentNode);
+
+ }
+
+ bool IsDataTemplate(INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode createContent;
+ if (parentElement != null &&
+ parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
+ createContent == this)
+ return true;
+ return false;
+ }
+
+ protected bool SkipChildren(IXamlNodeVisitor visitor, INode node, INode parentNode) =>
+ (visitor.StopOnDataTemplate && IsDataTemplate(parentNode))
+ || (visitor.StopOnResourceDictionary && visitor.IsResourceDictionary(this))
+ || visitor.SkipChildren(node, parentNode);
+
+ protected bool SkipVisitNode(IXamlNodeVisitor visitor, INode parentNode) =>
+ !visitor.VisitNodeOnDataTemplate && IsDataTemplate(parentNode);
+
+ public override INode Clone()
+ {
+ var clone = new ElementNode(XmlType, NamespaceURI, NamespaceResolver, LineNumber, LinePosition) {
+ IgnorablePrefixes = IgnorablePrefixes
+ };
+ foreach (var kvp in Properties)
+ clone.Properties.Add(kvp.Key, kvp.Value.Clone());
+ foreach (var p in SkipProperties)
+ clone.SkipProperties.Add(p);
+ foreach (var p in CollectionItems)
+ clone.CollectionItems.Add(p.Clone());
+ return clone;
+ }
+ }
+
+ internal abstract class RootNode : ElementNode
+ {
+ protected RootNode(XmlType xmlType, IXmlNamespaceResolver nsResolver) : base(xmlType, xmlType.NamespaceUri, nsResolver)
+ {
+ }
+
+ public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
+ {
+ if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.TopDown)
+ visitor.Visit(this, parentNode);
+
+ if (!SkipChildren(visitor, this, parentNode)) {
+ foreach (var node in Properties.Values.ToList())
+ node.Accept(visitor, this);
+ foreach (var node in CollectionItems)
+ node.Accept(visitor, this);
+ }
+
+ if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.BottomUp)
+ visitor.Visit(this, parentNode);
+ }
+ }
+
+ internal class ListNode : BaseNode, IListNode, IValueNode
+ {
+ public ListNode(IList<INode> nodes, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
+ : base(namespaceResolver, linenumber, lineposition)
+ {
+ CollectionItems = nodes.ToList();
+ }
+
+ public XmlName XmlName { get; set; }
+ public List<INode> CollectionItems { get; set; }
+
+ public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
+ {
+ if (visitor.VisitingMode == TreeVisitingMode.TopDown)
+ visitor.Visit(this, parentNode);
+ foreach (var node in CollectionItems)
+ node.Accept(visitor, this);
+ if (visitor.VisitingMode == TreeVisitingMode.BottomUp)
+ visitor.Visit(this, parentNode);
+ }
+
+ public override INode Clone()
+ {
+ var items = new List<INode>();
+ foreach (var p in CollectionItems)
+ items.Add(p.Clone());
+ return new ListNode(items, NamespaceResolver, LineNumber, LinePosition) {
+ IgnorablePrefixes = IgnorablePrefixes
+ };
+ }
+ }
+
+ internal static class INodeExtensions
+ {
+ public static bool SkipPrefix(this INode node, string prefix)
+ {
+ do {
+ if (node.IgnorablePrefixes != null && node.IgnorablePrefixes.Contains(prefix))
+ return true;
+ node = node.Parent;
+ } while (node != null);
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ internal interface IXamlNodeVisitor
+ {
+ TreeVisitingMode VisitingMode { get; }
+ bool StopOnDataTemplate { get; }
+ bool VisitNodeOnDataTemplate { get; }
+ bool StopOnResourceDictionary { get; }
+
+ void Visit(ValueNode node, INode parentNode);
+ void Visit(MarkupNode node, INode parentNode);
+ void Visit(ElementNode node, INode parentNode);
+ void Visit(RootNode node, INode parentNode);
+ void Visit(ListNode node, INode parentNode);
+ bool SkipChildren(INode node, INode parentNode);
+ bool IsResourceDictionary(ElementNode node);
+ }
+
+ internal enum TreeVisitingMode {
+ TopDown,
+ BottomUp
+ }
+
+ internal class XamlNodeVisitor : IXamlNodeVisitor
+ {
+ readonly Action<INode, INode> action;
+
+ public XamlNodeVisitor(Action<INode, INode> action, TreeVisitingMode visitingMode = TreeVisitingMode.TopDown, bool stopOnDataTemplate = false, bool visitNodeOnDataTemplate = true)
+ {
+ this.action = action;
+ VisitingMode = visitingMode;
+ StopOnDataTemplate = stopOnDataTemplate;
+ VisitNodeOnDataTemplate = visitNodeOnDataTemplate;
+ }
+
+ public TreeVisitingMode VisitingMode { get; }
+ public bool StopOnDataTemplate { get; }
+ public bool StopOnResourceDictionary { get; }
+ public bool VisitNodeOnDataTemplate { get; }
+
+ public void Visit(ValueNode node, INode parentNode) => action(node, parentNode);
+ public void Visit(MarkupNode node, INode parentNode) => action(node, parentNode);
+ public void Visit(ElementNode node, INode parentNode) => action(node, parentNode);
+ public void Visit(RootNode node, INode parentNode) => action(node, parentNode);
+ public void Visit(ListNode node, INode parentNode) => action(node, parentNode);
+ public bool SkipChildren(INode node, INode parentNode) => false;
+ public bool IsResourceDictionary(ElementNode node) => false;
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Diagnostics;
+using System.Text;
+using System.Xml;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class XamlParseException : Exception
+ {
+ readonly string _unformattedMessage;
+
+ static private StringBuilder GetStackInfo()
+ {
+ StringBuilder ret = new StringBuilder("\nStack:\n");
+
+ StackTrace st = new StackTrace();
+
+ for (int i = 2; i < st.FrameCount; i++)
+ {
+ StackFrame sf = st.GetFrame(i);
+ ret.AppendFormat("File:{0}, Method:{1}, Line:{2}\n", sf.GetFileName(), sf.GetMethod().Name, sf.GetFileLineNumber());
+ }
+
+ return ret;
+ }
+
+ public XamlParseException(string message, IXmlLineInfo xmlInfo, Exception innerException = null) : base(FormatMessage(message + GetStackInfo(), xmlInfo), innerException)
+ {
+ _unformattedMessage = message;
+ XmlInfo = xmlInfo;
+ }
+
+ public IXmlLineInfo XmlInfo { get; private set; }
+
+ internal string UnformattedMessage
+ {
+ get { return _unformattedMessage ?? Message; }
+ }
+
+ static string FormatMessage(string message, IXmlLineInfo xmlinfo)
+ {
+ if (xmlinfo == null || !xmlinfo.HasLineInfo())
+ return message;
+ return string.Format("Position {0}:{1}. {2}", xmlinfo.LineNumber, xmlinfo.LinePosition, message);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// XamlParser.cs
+//
+// Author:
+// Stephane Delcroix <stephane@mi8.be>
+//
+// Copyright (c) 2013 Mobile Inception
+// Copyright (c) 2013-2014 Xamarin, Inc
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Xml;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Xaml
+{
+ internal static class XamlParser
+ {
+ //public const string XFUri = "http://xamarin.com/schemas/2014/forms";
+ public const string XFUri = "http://tizen.org/Tizen.NUI/2018/XAML";
+ public const string NUI2018Uri = "http://tizen.org/Tizen.NUI/2018/XAML";
+ public const string X2006Uri = "http://schemas.microsoft.com/winfx/2006/xaml";
+ public const string X2009Uri = "http://schemas.microsoft.com/winfx/2009/xaml";
+ public const string McUri = "http://schemas.openxmlformats.org/markup-compatibility/2006";
+
+ public static void ParseXaml(RootNode rootNode, XmlReader reader)
+ {
+ IList<KeyValuePair<string, string>> xmlns;
+ var attributes = ParseXamlAttributes(reader, out xmlns);
+ var prefixes = PrefixesToIgnore(xmlns);
+ (rootNode.IgnorablePrefixes ?? (rootNode.IgnorablePrefixes=new List<string>())).AddRange(prefixes);
+ rootNode.Properties.AddRange(attributes);
+ ParseXamlElementFor(rootNode, reader);
+ }
+
+ static void ParseXamlElementFor(IElementNode node, XmlReader reader)
+ {
+ Debug.Assert(reader.NodeType == XmlNodeType.Element);
+
+ var elementName = reader.Name;
+ var isEmpty = reader.IsEmptyElement;
+
+ if (isEmpty)
+ return;
+
+ while (reader.Read())
+ {
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.EndElement:
+ Debug.Assert(reader.Name == elementName); //make sure we close the right element
+ return;
+ case XmlNodeType.Element:
+ // 1. Property Element.
+ if (reader.Name.Contains("."))
+ {
+ XmlName name;
+ if (reader.Name.StartsWith(elementName + ".", StringComparison.Ordinal))
+ name = new XmlName(reader.NamespaceURI, reader.Name.Substring(elementName.Length + 1));
+ else //Attached DP
+ name = new XmlName(reader.NamespaceURI, reader.LocalName);
+
+ var prop = ReadNode(reader);
+ if (prop != null)
+ node.Properties.Add(name, prop);
+ }
+ // 2. Xaml2009 primitives, x:Arguments, ...
+ else if (reader.NamespaceURI == X2009Uri && reader.LocalName == "Arguments")
+ {
+ var prop = ReadNode(reader);
+ if (prop != null)
+ node.Properties.Add(XmlName.xArguments, prop);
+ }
+ // 3. DataTemplate (should be handled by 4.)
+ else if ((node.XmlType.NamespaceUri == XFUri || node.XmlType.NamespaceUri == NUI2018Uri) &&
+ (node.XmlType.Name == "DataTemplate" || node.XmlType.Name == "ControlTemplate"))
+ {
+ var prop = ReadNode(reader, true);
+ if (prop != null)
+ node.Properties.Add(XmlName._CreateContent, prop);
+ }
+ // 4. Implicit content, implicit collection, or collection syntax. Add to CollectionItems, resolve case later.
+ else
+ {
+ var item = ReadNode(reader, true);
+ if (item != null)
+ node.CollectionItems.Add(item);
+ }
+ break;
+ case XmlNodeType.Whitespace:
+ break;
+ case XmlNodeType.Text:
+ case XmlNodeType.CDATA:
+ if (node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode)
+ ((ValueNode)node.CollectionItems[0]).Value += reader.Value.Trim();
+ else
+ node.CollectionItems.Add(new ValueNode(reader.Value.Trim(), (IXmlNamespaceResolver)reader));
+ break;
+ default:
+ Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
+ break;
+ }
+ }
+ }
+
+ static INode ReadNode(XmlReader reader, bool nested = false)
+ {
+ var skipFirstRead = nested;
+ Debug.Assert(reader.NodeType == XmlNodeType.Element);
+ var name = reader.Name;
+ List<INode> nodes = new List<INode>();
+ INode node = null;
+
+ while (skipFirstRead || reader.Read())
+ {
+ skipFirstRead = false;
+
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.EndElement:
+ Debug.Assert(reader.Name == name);
+ if (nodes.Count == 0) //Empty element
+ return null;
+ if (nodes.Count == 1)
+ return nodes[0];
+ return new ListNode(nodes, (IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber,
+ ((IXmlLineInfo)reader).LinePosition);
+ case XmlNodeType.Element:
+ var isEmpty = reader.IsEmptyElement && reader.Name == name;
+ var elementName = reader.Name;
+ var elementNsUri = reader.NamespaceURI;
+ var elementXmlInfo = (IXmlLineInfo)reader;
+ IList<KeyValuePair<string, string>> xmlns;
+
+ var attributes = ParseXamlAttributes(reader, out xmlns);
+ var prefixes = PrefixesToIgnore(xmlns);
+
+ IList<XmlType> typeArguments = null;
+ if (attributes.Any(kvp => kvp.Key == XmlName.xTypeArguments))
+ {
+ typeArguments =
+ ((ValueNode)attributes.First(kvp => kvp.Key == XmlName.xTypeArguments).Value).Value as IList<XmlType>;
+ }
+
+ node = new ElementNode(new XmlType(elementNsUri, elementName, typeArguments), elementNsUri,
+ reader as IXmlNamespaceResolver, elementXmlInfo.LineNumber, elementXmlInfo.LinePosition);
+ ((IElementNode)node).Properties.AddRange(attributes);
+ (node.IgnorablePrefixes ?? (node.IgnorablePrefixes = new List<string>())).AddRange(prefixes);
+
+ ParseXamlElementFor((IElementNode)node, reader);
+ nodes.Add(node);
+ if (isEmpty || nested)
+ return node;
+ break;
+ case XmlNodeType.Text:
+ node = new ValueNode(reader.Value.Trim(), (IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber,
+ ((IXmlLineInfo)reader).LinePosition);
+ nodes.Add(node);
+ break;
+ case XmlNodeType.Whitespace:
+ break;
+ default:
+ Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
+ break;
+ }
+ }
+ throw new XamlParseException("Closing PropertyElement expected", (IXmlLineInfo)reader);
+ }
+
+ static IList<KeyValuePair<XmlName, INode>> ParseXamlAttributes(XmlReader reader, out IList<KeyValuePair<string,string>> xmlns)
+ {
+ Debug.Assert(reader.NodeType == XmlNodeType.Element);
+ var attributes = new List<KeyValuePair<XmlName, INode>>();
+ xmlns = new List<KeyValuePair<string, string>>();
+ for (var i = 0; i < reader.AttributeCount; i++)
+ {
+ reader.MoveToAttribute(i);
+
+ //skip xmlns
+ if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/") {
+ xmlns.Add(new KeyValuePair<string, string>(reader.LocalName, reader.Value));
+ continue;
+ }
+
+ var namespaceUri = reader.NamespaceURI;
+ if (reader.LocalName.Contains(".") && namespaceUri == "")
+ namespaceUri = ((IXmlNamespaceResolver)reader).LookupNamespace("");
+ var propertyName = new XmlName(namespaceUri, reader.LocalName);
+
+ object value = reader.Value;
+
+ if (reader.NamespaceURI == X2006Uri)
+ {
+ switch (reader.Name) {
+ case "x:Key":
+ propertyName = XmlName.xKey;
+ break;
+ case "x:Name":
+ propertyName = XmlName.xName;
+ break;
+ case "x:Class":
+ case "x:FieldModifier":
+ continue;
+ default:
+ Debug.WriteLine("Unhandled attribute {0}", reader.Name);
+ continue;
+ }
+ }
+
+ if (reader.NamespaceURI == X2009Uri)
+ {
+ switch (reader.Name) {
+ case "x:Key":
+ propertyName = XmlName.xKey;
+ break;
+ case "x:Name":
+ propertyName = XmlName.xName;
+ break;
+ case "x:TypeArguments":
+ propertyName = XmlName.xTypeArguments;
+ value = TypeArgumentsParser.ParseExpression((string)value, (IXmlNamespaceResolver)reader, (IXmlLineInfo)reader);
+ break;
+ case "x:DataType":
+ propertyName = XmlName.xDataType;
+ break;
+ case "x:Class":
+ case "x:FieldModifier":
+ continue;
+ case "x:FactoryMethod":
+ propertyName = XmlName.xFactoryMethod;
+ break;
+ case "x:Arguments":
+ propertyName = XmlName.xArguments;
+ break;
+ default:
+ Debug.WriteLine("Unhandled attribute {0}", reader.Name);
+ continue;
+ }
+ }
+
+ var propertyNode = GetValueNode(value, reader);
+ attributes.Add(new KeyValuePair<XmlName, INode>(propertyName, propertyNode));
+ }
+ reader.MoveToElement();
+ return attributes;
+ }
+
+ static IList<string> PrefixesToIgnore(IList<KeyValuePair<string, string>> xmlns)
+ {
+ var prefixes = new List<string>();
+ foreach (var kvp in xmlns) {
+ var prefix = kvp.Key;
+
+ string typeName = null, ns = null, asm = null, targetPlatform = null;
+ XmlnsHelper.ParseXmlns(kvp.Value, out typeName, out ns, out asm, out targetPlatform);
+ if (targetPlatform == null)
+ continue;
+ try {
+ if (targetPlatform != Device.RuntimePlatform)
+ {
+ // Special case for Windows backward compatibility
+ if (targetPlatform == "Windows" && Device.RuntimePlatform == Device.UWP)
+ continue;
+
+ prefixes.Add(prefix);
+ }
+ } catch (InvalidOperationException) {
+ prefixes.Add(prefix);
+ }
+ }
+ return prefixes;
+ }
+
+ static IValueNode GetValueNode(object value, XmlReader reader)
+ {
+ var valueString = value as string;
+ if (valueString != null && valueString.Trim().StartsWith("{}", StringComparison.Ordinal))
+ {
+ return new ValueNode(valueString.Substring(2), (IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber,
+ ((IXmlLineInfo)reader).LinePosition);
+ }
+ if (valueString != null && valueString.Trim().StartsWith("{", StringComparison.Ordinal))
+ {
+ return new MarkupNode(valueString.Trim(), reader as IXmlNamespaceResolver, ((IXmlLineInfo)reader).LineNumber,
+ ((IXmlLineInfo)reader).LinePosition);
+ }
+ return new ValueNode(value, (IXmlNamespaceResolver)reader, ((IXmlLineInfo)reader).LineNumber,
+ ((IXmlLineInfo)reader).LinePosition);
+ }
+
+ static IList<XmlnsDefinitionAttribute> s_xmlnsDefinitions;
+ public static IList<Assembly> s_assemblies = new List<Assembly>();// = new Assembly[]{};
+
+ static void GatherXmlnsDefinitionAttributes()
+ {
+ //this could be extended to look for [XmlnsDefinition] in all assemblies
+ // var assemblies = new [] {
+ // typeof(View).GetTypeInfo().Assembly,
+ // typeof(XamlLoader).GetTypeInfo().Assembly,
+ // };
+ // s_assemblies = new Assembly[]{typeof(View).GetTypeInfo().Assembly};
+ s_assemblies.Add(typeof(Element).GetTypeInfo().Assembly);
+
+ s_xmlnsDefinitions = new List<XmlnsDefinitionAttribute>();
+
+ foreach (var assembly in s_assemblies)
+ foreach (XmlnsDefinitionAttribute attribute in assembly.GetCustomAttributes(typeof(XmlnsDefinitionAttribute))) {
+ s_xmlnsDefinitions.Add(attribute);
+ attribute.AssemblyName = attribute.AssemblyName ?? assembly.FullName;
+ }
+ }
+
+ public static Type GetElementType(XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly,
+ out XamlParseException exception)
+ {
+ if (s_xmlnsDefinitions == null)
+ GatherXmlnsDefinitionAttributes();
+
+ var namespaceURI = xmlType.NamespaceUri;
+ var elementName = xmlType.Name;
+ var typeArguments = xmlType.TypeArguments;
+ exception = null;
+
+ if (elementName.Contains("-"))
+ {
+ elementName = elementName.Replace('-', '+');
+ }
+
+ var lookupAssemblies = new List<XmlnsDefinitionAttribute>();
+ var lookupNames = new List<string>();
+
+ foreach (var xmlnsDef in s_xmlnsDefinitions) {
+ if (xmlnsDef.XmlNamespace != namespaceURI)
+ continue;
+ lookupAssemblies.Add(xmlnsDef);
+ }
+
+ if (lookupAssemblies.Count == 0) {
+ string ns, asmstring, _;
+ XmlnsHelper.ParseXmlns(namespaceURI, out _, out ns, out asmstring, out _);
+ lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns, 0) {
+ AssemblyName = asmstring ?? currentAssembly.FullName
+ });
+ }
+
+ lookupNames.Add(elementName);
+ lookupNames.Add(elementName + "Extension");
+
+ for (var i = 0; i < lookupNames.Count; i++)
+ {
+ var name = lookupNames[i];
+ if (name.Contains(":"))
+ name = name.Substring(name.LastIndexOf(':') + 1);
+ if (typeArguments != null)
+ name += "`" + typeArguments.Count; //this will return an open generic Type
+ lookupNames[i] = name;
+ }
+
+ Type type = null;
+ foreach (var asm in lookupAssemblies) {
+ foreach (var name in lookupNames)
+ if ((type = Type.GetType($"{asm.ClrNamespace}.{name}, {asm.AssemblyName}")) != null)
+ break;
+ if (type != null)
+ break;
+ }
+
+ if (type != null && typeArguments != null)
+ {
+ XamlParseException innerexception = null;
+ var args = typeArguments.Select(delegate(XmlType xmltype)
+ {
+ XamlParseException xpe;
+ var t = GetElementType(xmltype, xmlInfo, currentAssembly, out xpe);
+ if (xpe != null)
+ {
+ innerexception = xpe;
+ return null;
+ }
+ return t;
+ }).ToArray();
+ if (innerexception != null)
+ {
+ exception = innerexception;
+ return null;
+ }
+ type = type.MakeGenericType(args);
+ }
+
+ if (type == null)
+ exception = new XamlParseException($"Type {elementName} not found in xmlns {namespaceURI}", xmlInfo);
+
+ return type;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+
+namespace Tizen.NUI.Xaml
+{
+ [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = true)]
+ internal sealed class XamlResourceIdAttribute : Attribute
+ {
+ public string ResourceId { get; set; }
+ public string Path { get; set; }
+ public Type Type { get; set; }
+
+ public XamlResourceIdAttribute(string resourceId, string path, Type type)
+ {
+ ResourceId = resourceId;
+ Path = path;
+ Type = type;
+ }
+
+ internal static string GetResourceIdForType(Type type)
+ {
+ var assembly = type.GetTypeInfo().Assembly;
+ foreach (var xria in assembly.GetCustomAttributes<XamlResourceIdAttribute>()) {
+ if (xria.Type == type)
+ return xria.ResourceId;
+ }
+ return null;
+ }
+
+ internal static string GetPathForType(Type type)
+ {
+ var assembly = type.GetTypeInfo().Assembly;
+ foreach (var xria in assembly.GetCustomAttributes<XamlResourceIdAttribute>()) {
+ if (xria.Type == type)
+ return xria.Path;
+ }
+ return null;
+ }
+
+ internal static string GetResourceIdForPath(Assembly assembly, string path)
+ {
+ foreach (var xria in assembly.GetCustomAttributes<XamlResourceIdAttribute>()) {
+ if (xria.Path == path)
+ return xria.ResourceId;
+ }
+ return null;
+ }
+
+ internal static Type GetTypeForResourceId(Assembly assembly, string resourceId)
+ {
+ foreach (var xria in assembly.GetCustomAttributes<XamlResourceIdAttribute>()) {
+ if (xria.ResourceId == resourceId)
+ return xria.Type;
+ }
+ return null;
+ }
+
+ internal static Type GetTypeForPath(Assembly assembly, string path)
+ {
+ foreach (var xria in assembly.GetCustomAttributes<XamlResourceIdAttribute>()) {
+ if (xria.Path == path)
+ return xria.Type;
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Xml;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class XamlServiceProvider : IServiceProvider
+ {
+ readonly Dictionary<Type, object> services = new Dictionary<Type, object>();
+
+ internal XamlServiceProvider(INode node, HydrationContext context)
+ {
+ object targetObject;
+ if (node != null && node.Parent != null && context.Values.TryGetValue(node.Parent, out targetObject))
+ IProvideValueTarget = new XamlValueTargetProvider(targetObject, node, context, null);
+ if (context != null)
+ IRootObjectProvider = new XamlRootObjectProvider(context.RootElement);
+ if (node != null)
+ {
+ IXamlTypeResolver = new XamlTypeResolver(node.NamespaceResolver, XamlParser.GetElementType,
+ context?.RootElement.GetType().GetTypeInfo().Assembly);
+
+ var enode = node;
+ while (enode != null && !(enode is IElementNode))
+ enode = enode.Parent;
+ if (enode != null)
+ INameScopeProvider = new NameScopeProvider { NameScope = (enode as IElementNode).Namescope };
+ }
+
+ var xmlLineInfo = node as IXmlLineInfo;
+ if (xmlLineInfo != null)
+ IXmlLineInfoProvider = new XmlLineInfoProvider(xmlLineInfo);
+
+ IValueConverterProvider = new ValueConverterProvider();
+ }
+
+ public XamlServiceProvider()
+ {
+ IValueConverterProvider = new ValueConverterProvider();
+ }
+
+ internal IProvideValueTarget IProvideValueTarget
+ {
+ get { return (IProvideValueTarget)GetService(typeof (IProvideValueTarget)); }
+ set { services[typeof (IProvideValueTarget)] = value; }
+ }
+
+ internal IXamlTypeResolver IXamlTypeResolver
+ {
+ get { return (IXamlTypeResolver)GetService(typeof (IXamlTypeResolver)); }
+ set { services[typeof (IXamlTypeResolver)] = value; }
+ }
+
+ internal IRootObjectProvider IRootObjectProvider
+ {
+ get { return (IRootObjectProvider)GetService(typeof (IRootObjectProvider)); }
+ set { services[typeof (IRootObjectProvider)] = value; }
+ }
+
+ internal IXmlLineInfoProvider IXmlLineInfoProvider
+ {
+ get { return (IXmlLineInfoProvider)GetService(typeof (IXmlLineInfoProvider)); }
+ set { services[typeof (IXmlLineInfoProvider)] = value; }
+ }
+
+ internal INameScopeProvider INameScopeProvider
+ {
+ get { return (INameScopeProvider)GetService(typeof (INameScopeProvider)); }
+ set { services[typeof (INameScopeProvider)] = value; }
+ }
+
+ internal IValueConverterProvider IValueConverterProvider
+ {
+ get { return (IValueConverterProvider)GetService(typeof (IValueConverterProvider)); }
+ set { services[typeof (IValueConverterProvider)] = value; }
+ }
+
+ public object GetService(Type serviceType)
+ {
+ object service;
+ return services.TryGetValue(serviceType, out service) ? service : null;
+ }
+
+ public void Add(Type type, object service)
+ {
+ services.Add(type, service);
+ }
+ }
+
+ internal class XamlValueTargetProvider : IProvideParentValues, IProvideValueTarget
+ {
+ public XamlValueTargetProvider(object targetObject, INode node, HydrationContext context, object targetProperty)
+ {
+ Context = context;
+ Node = node;
+ TargetObject = targetObject;
+ TargetProperty = targetProperty;
+ }
+
+ INode Node { get; }
+
+ HydrationContext Context { get; }
+ public object TargetObject { get; }
+ public object TargetProperty { get; internal set; } = null;
+
+ IEnumerable<object> IProvideParentValues.ParentObjects
+ {
+ get
+ {
+ if (Node == null || Context == null)
+ yield break;
+ var n = Node;
+ object obj = null;
+ var context = Context;
+ while (n.Parent != null && context != null)
+ {
+ if (n.Parent is IElementNode)
+ {
+ if (context.Values.TryGetValue(n.Parent, out obj))
+ yield return obj;
+ else
+ {
+ context = context.ParentContext;
+ continue;
+ }
+ }
+ n = n.Parent;
+ }
+ }
+ }
+ }
+
+ internal class SimpleValueTargetProvider : IProvideParentValues, IProvideValueTarget, IReferenceProvider
+ {
+ readonly object[] objectAndParents;
+ readonly object targetProperty;
+
+ [Obsolete("SimpleValueTargetProvider(object[] objectAndParents) is obsolete as of version 2.3.4. Please use SimpleValueTargetProvider(object[] objectAndParents, object targetProperty) instead.")]
+ public SimpleValueTargetProvider(object[] objectAndParents) : this (objectAndParents, null)
+ {
+ }
+
+ public SimpleValueTargetProvider(object[] objectAndParents, object targetProperty)
+ {
+ if (objectAndParents == null)
+ throw new ArgumentNullException(nameof(objectAndParents));
+ if (objectAndParents.Length == 0)
+ throw new ArgumentException();
+
+ this.objectAndParents = objectAndParents;
+ this.targetProperty = targetProperty;
+ }
+
+ IEnumerable<object> IProvideParentValues.ParentObjects
+ {
+ get { return objectAndParents; }
+ }
+
+ object IProvideValueTarget.TargetObject
+ {
+ get { return objectAndParents[0]; }
+ }
+
+ object IProvideValueTarget.TargetProperty
+ {
+ get { return targetProperty; }
+ }
+
+ public object FindByName(string name)
+ {
+ for (var i = 0; i < objectAndParents.Length; i++)
+ {
+ var bo = objectAndParents[i] as BindableObject;
+ if (bo == null) continue;
+ var ns = NameScope.GetNameScope(bo) as INameScope;
+ if (ns == null) continue;
+ var value = ns.FindByName(name);
+ if (value != null)
+ return value;
+ }
+ return null;
+ }
+ }
+
+ internal class XamlTypeResolver : IXamlTypeResolver
+ {
+ readonly Assembly currentAssembly;
+ readonly GetTypeFromXmlName getTypeFromXmlName;
+ readonly IXmlNamespaceResolver namespaceResolver;
+
+ public XamlTypeResolver(IXmlNamespaceResolver namespaceResolver, Assembly currentAssembly)
+ : this(namespaceResolver, XamlParser.GetElementType, currentAssembly)
+ {
+ }
+
+ internal XamlTypeResolver(IXmlNamespaceResolver namespaceResolver, GetTypeFromXmlName getTypeFromXmlName,
+ Assembly currentAssembly)
+ {
+ this.currentAssembly = currentAssembly;
+ if (namespaceResolver == null)
+ throw new ArgumentNullException();
+ if (getTypeFromXmlName == null)
+ throw new ArgumentNullException();
+
+ this.namespaceResolver = namespaceResolver;
+ this.getTypeFromXmlName = getTypeFromXmlName;
+ }
+
+ Type IXamlTypeResolver.Resolve(string qualifiedTypeName, IServiceProvider serviceProvider)
+ {
+ XamlParseException e;
+ var type = Resolve(qualifiedTypeName, serviceProvider, out e);
+ if (e != null)
+ throw e;
+ return type;
+ }
+
+ bool IXamlTypeResolver.TryResolve(string qualifiedTypeName, out Type type)
+ {
+ XamlParseException exception;
+ type = Resolve(qualifiedTypeName, null, out exception);
+ return exception == null;
+ }
+
+ Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider, out XamlParseException exception)
+ {
+ exception = null;
+ var split = qualifiedTypeName.Split(':');
+ if (split.Length > 2)
+ return null;
+
+ string prefix, name;
+ if (split.Length == 2)
+ {
+ prefix = split[0];
+ name = split[1];
+ }
+ else
+ {
+ prefix = "";
+ name = split[0];
+ }
+
+ IXmlLineInfo xmlLineInfo = null;
+ if (serviceProvider != null)
+ {
+ var lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ if (lineInfoProvider != null)
+ xmlLineInfo = lineInfoProvider.XmlLineInfo;
+ }
+
+ var namespaceuri = namespaceResolver.LookupNamespace(prefix);
+ if (namespaceuri == null)
+ {
+ exception = new XamlParseException(string.Format("No xmlns declaration for prefix \"{0}\"", prefix), xmlLineInfo);
+ return null;
+ }
+
+ return getTypeFromXmlName(new XmlType(namespaceuri, name, null), xmlLineInfo, currentAssembly, out exception);
+ }
+
+ internal delegate Type GetTypeFromXmlName(
+ XmlType xmlType, IXmlLineInfo xmlInfo, Assembly currentAssembly, out XamlParseException exception);
+ }
+
+ internal class XamlRootObjectProvider : IRootObjectProvider
+ {
+ public XamlRootObjectProvider(object rootObject)
+ {
+ RootObject = rootObject;
+ }
+
+ public object RootObject { get; }
+ }
+
+ internal class XmlLineInfoProvider : IXmlLineInfoProvider
+ {
+ public XmlLineInfoProvider(IXmlLineInfo xmlLineInfo)
+ {
+ XmlLineInfo = xmlLineInfo;
+ }
+
+ public IXmlLineInfo XmlLineInfo { get; }
+ }
+
+ internal class NameScopeProvider : INameScopeProvider
+ {
+ public INameScope NameScope { get; set; }
+ }
+
+ internal class XmlNamespaceResolver : IXmlNamespaceResolver
+ {
+ readonly Dictionary<string, string> namespaces = new Dictionary<string, string>();
+
+ public IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string LookupNamespace(string prefix)
+ {
+ string result;
+ if (namespaces.TryGetValue(prefix, out result))
+ return result;
+ return null;
+ }
+
+ public string LookupPrefix(string namespaceName)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Add(string prefix, string ns)
+ {
+ namespaces.Add(prefix, ns);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Xml;
+
+namespace Tizen.NUI.Xaml
+{
+ internal class XmlLineInfo : IXmlLineInfo
+ {
+ readonly bool _hasLineInfo;
+ private int v1;
+ private int v2;
+
+ public XmlLineInfo()
+ {
+ }
+
+ public XmlLineInfo(int linenumber, int lineposition)
+ {
+ _hasLineInfo = true;
+ LineNumber = linenumber;
+ LinePosition = lineposition;
+ }
+
+ public bool HasLineInfo()
+ {
+ return _hasLineInfo;
+ }
+
+ public int LineNumber { get; }
+
+ public int LinePosition { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Diagnostics;
+
+namespace Tizen.NUI.Xaml
+{
+ [DebuggerDisplay("{NamespaceURI}:{LocalName}")]
+ internal struct XmlName
+ {
+ public static readonly XmlName _CreateContent = new XmlName("_", "CreateContent");
+ public static readonly XmlName xKey = new XmlName("x", "Key");
+ public static readonly XmlName xName = new XmlName("x", "Name");
+ public static readonly XmlName xTypeArguments = new XmlName("x", "TypeArguments");
+ public static readonly XmlName xArguments = new XmlName("x", "Arguments");
+ public static readonly XmlName xFactoryMethod = new XmlName("x", "FactoryMethod");
+ public static readonly XmlName xDataType = new XmlName("x", "DataType");
+ public static readonly XmlName Empty = new XmlName();
+
+ public string NamespaceURI { get; }
+ public string LocalName { get; }
+
+ public XmlName(string namespaceUri, string localName)
+ {
+ NamespaceURI = namespaceUri;
+ LocalName = localName;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null)
+ return false;
+ if (obj.GetType() != typeof (XmlName))
+ return false;
+ var other = (XmlName)obj;
+ return NamespaceURI == other.NamespaceURI && LocalName == other.LocalName;
+ }
+
+ public bool Equals(string namespaceUri, string localName)
+ => Equals(new XmlName(namespaceUri, localName));
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hashCode = 0;
+ if (NamespaceURI != null)
+ hashCode = NamespaceURI.GetHashCode();
+ if (LocalName != null)
+ hashCode = (hashCode * 397) ^ LocalName.GetHashCode();
+ return hashCode;
+ }
+ }
+
+ public static bool operator ==(XmlName x1, XmlName x2)
+ => x1.NamespaceURI == x2.NamespaceURI && x1.LocalName == x2.LocalName;
+
+ public static bool operator !=(XmlName x1, XmlName x2)
+ => !(x1 == x2);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Xaml
+{
+ internal static class XmlnsHelper
+ {
+ public static string ParseNamespaceFromXmlns(string xmlns)
+ {
+ string typeName;
+ string ns;
+ string asm;
+ string targetPlatform;
+
+ ParseXmlns(xmlns, out typeName, out ns, out asm, out targetPlatform);
+
+ return ns;
+ }
+
+ public static void ParseXmlns(string xmlns, out string typeName, out string ns, out string asm, out string targetPlatform)
+ {
+ typeName = ns = asm = targetPlatform = null;
+
+ xmlns = xmlns.Trim();
+
+ if (xmlns.StartsWith("using:", StringComparison.Ordinal)) {
+ ParseUsing(xmlns, out typeName, out ns, out asm, out targetPlatform);
+ return;
+ }
+ ParseClrNamespace(xmlns, out typeName, out ns, out asm, out targetPlatform);
+ }
+
+ static void ParseClrNamespace(string xmlns, out string typeName, out string ns, out string asm, out string targetPlatform)
+ {
+ typeName = ns = asm = targetPlatform = null;
+
+ foreach (var decl in xmlns.Split(';'))
+ {
+ if (decl.StartsWith("clr-namespace:", StringComparison.Ordinal))
+ {
+ ns = decl.Substring(14, decl.Length - 14);
+ continue;
+ }
+ if (decl.StartsWith("assembly=", StringComparison.Ordinal))
+ {
+ asm = decl.Substring(9, decl.Length - 9);
+ continue;
+ }
+ if (decl.StartsWith("targetPlatform=", StringComparison.Ordinal)) {
+ targetPlatform = decl.Substring(15, decl.Length - 15);
+ continue;
+ }
+ var nsind = decl.LastIndexOf(".", StringComparison.Ordinal);
+ if (nsind > 0)
+ {
+ ns = decl.Substring(0, nsind);
+ typeName = decl.Substring(nsind + 1, decl.Length - nsind - 1);
+ }
+ else
+ typeName = decl;
+ }
+ }
+
+ static void ParseUsing(string xmlns, out string typeName, out string ns, out string asm, out string targetPlatform)
+ {
+ typeName = ns = asm = targetPlatform = null;
+
+ foreach (var decl in xmlns.Split(';')) {
+ if (decl.StartsWith("using:", StringComparison.Ordinal)) {
+ ns = decl.Substring(6, decl.Length - 6);
+ continue;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// Provides a mechanism by which application developers can propagate changes that are made to data in one object to another, by enabling validation, type coercion, and an event system.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal abstract class BindableObject : INotifyPropertyChanged, IDynamicResourceHandler
+ {
+ /// <summary>
+ /// Implements the bound property whose interface is provided by the BindingContext property.
+ /// </summary>
+ public static readonly BindableProperty BindingContextProperty =
+ BindableProperty.Create("BindingContext", typeof(object), typeof(BindableObject), default(object),
+ BindingMode.OneWay, null, BindingContextPropertyChanged, null, null, BindingContextPropertyBindingChanging);
+
+ readonly List<BindablePropertyContext> _properties = new List<BindablePropertyContext>(4);
+
+ bool _applying;
+ object _inheritedContext;
+
+ /// <summary>
+ /// Gets or sets object that contains the properties that will be targeted by the bound properties that belong to this BindableObject.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public object BindingContext
+ {
+ get { return _inheritedContext ?? GetValue(BindingContextProperty); }
+ set { SetValue(BindingContextProperty, value); }
+ }
+
+ void IDynamicResourceHandler.SetDynamicResource(BindableProperty property, string key)
+ {
+ SetDynamicResource(property, key, false);
+ }
+
+ /// <summary>
+ /// Raised when a property has changed.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ /// <summary>
+ /// Raised whenever the BindingContext property changes.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event EventHandler BindingContextChanged;
+
+ internal void ClearValue(BindableProperty property, bool fromStyle)
+ {
+ ClearValue(property, fromStyle: fromStyle, checkAccess: true);
+ }
+
+ /// <summary>
+ /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue.
+ /// </summary>
+ /// <param name="property">The BindableProperty to clear</param>
+ internal void ClearValue(BindableProperty property)
+ {
+ ClearValue(property, fromStyle: false, checkAccess: true);
+ }
+
+ /// <summary>
+ /// Clears any value set by Tizen.NUI.Xaml.BindableObject.SetValue for the property that is identified by propertyKey.
+ /// </summary>
+ /// <param name="propertyKey">The BindablePropertyKey that identifies the BindableProperty to clear.</param>
+ internal void ClearValue(BindablePropertyKey propertyKey)
+ {
+ if (propertyKey == null)
+ throw new ArgumentNullException("propertyKey");
+
+ ClearValue(propertyKey.BindableProperty, fromStyle:false, checkAccess: false);
+ }
+
+ /// <summary>
+ /// Return true if the target property exists and has been set.
+ /// </summary>
+ /// <param name="targetProperty">The target property</param>
+ /// <returns>return true if the target property exists and has been set</returns>
+ internal bool IsSet(BindableProperty targetProperty)
+ {
+ if (targetProperty == null)
+ throw new ArgumentNullException(nameof(targetProperty));
+
+ var bpcontext = GetContext(targetProperty);
+ return bpcontext != null
+ && (bpcontext.Attributes & BindableContextAttributes.IsDefaultValue) == 0;
+ }
+
+ /// <summary>
+ /// Returns the value that is contained the BindableProperty.
+ /// </summary>
+ /// <param name="property">The BindableProperty for which to get the value.</param>
+ /// <returns>The value that is contained the BindableProperty</returns>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public object GetValue(BindableProperty property)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ BindablePropertyContext context = property.DefaultValueCreator != null ? GetOrCreateContext(property) : GetContext(property);
+
+ if (context == null)
+ return property.DefaultValue;
+
+ return context.Value;
+ }
+
+ /// <summary>
+ /// Raised when a property is about to change.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event PropertyChangingEventHandler PropertyChanging;
+
+ /// <summary>
+ /// Removes a previously set binding.
+ /// </summary>
+ /// <param name="property">The BindableProperty from which to remove bindings.</param>
+ internal void RemoveBinding(BindableProperty property)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ BindablePropertyContext context = GetContext(property);
+ if (context == null || context.Binding == null)
+ return;
+
+ RemoveBinding(property, context);
+ }
+
+ /// <summary>
+ /// Assigns a binding to a property.
+ /// </summary>
+ /// <param name="targetProperty">The BindableProperty on which to set a binding.</param>
+ /// <param name="binding">The binding to set.</param>
+ public void SetBinding(BindableProperty targetProperty, BindingBase binding)
+ {
+ SetBinding(targetProperty, binding, false);
+ }
+
+ private bool isCreateByXaml = false;
+ internal virtual bool IsCreateByXaml
+ {
+ get
+ {
+ return isCreateByXaml;
+ }
+ set
+ {
+ isCreateByXaml = value;
+ }
+ }
+
+ /// <summary>
+ /// Sets the value of the specified property.
+ /// </summary>
+ /// <param name="property">The BindableProperty on which to assign a value.</param>
+ /// <param name="value">The value to set.</param>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SetValue(BindableProperty property, object value)
+ {
+ SetValue(property, value, false, true);
+ //if (true == isCreateByXaml)
+ //{
+ // SetValue(property, value, false, true);
+ //}
+ //else
+ //{
+ // property.PropertyChanged?.Invoke(this, null, value);
+ //}
+ }
+
+ internal void SetValueAndForceSendChangeSignal(BindableProperty property, object value)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ if (property.IsReadOnly)
+ throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
+
+ SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
+ SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
+
+ //if (true == isCreateByXaml)
+ //{
+ // if (property.IsReadOnly)
+ // throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
+
+ // SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
+ // SetValuePrivateFlags.ManuallySet | SetValuePrivateFlags.CheckAccess, true);
+ //}
+ //else
+ //{
+ // property.PropertyChanged?.Invoke(this, null, value);
+ //}
+ }
+
+ /// <summary>
+ /// Sets the value of the propertyKey.
+ /// </summary>
+ /// <param name="propertyKey">The BindablePropertyKey on which to assign a value.</param>
+ /// <param name="value">The value to set.</param>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SetValue(BindablePropertyKey propertyKey, object value)
+ {
+ if (propertyKey == null)
+ throw new ArgumentNullException("propertyKey");
+
+ SetValue(propertyKey.BindableProperty, value, false, false);
+ }
+
+ /// <summary>
+ /// Set the inherited context to a neated element.
+ /// </summary>
+ /// <param name="bindable">The object on which to set the inherited binding context.</param>
+ /// <param name="value">The inherited context to set.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetInheritedBindingContext(BindableObject bindable, object value)
+ {
+ BindablePropertyContext bpContext = bindable.GetContext(BindingContextProperty);
+ if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
+ return;
+
+ object oldContext = bindable._inheritedContext;
+
+ if (ReferenceEquals(oldContext, value))
+ return;
+
+ if (bpContext != null && oldContext == null)
+ oldContext = bpContext.Value;
+
+ if (bpContext != null && bpContext.Binding != null)
+ {
+ bpContext.Binding.Context = value;
+ bindable._inheritedContext = null;
+ }
+ else
+ {
+ bindable._inheritedContext = value;
+ }
+
+ bindable.ApplyBindings(skipBindingContext:false, fromBindingContextChanged:true);
+ bindable.OnBindingContextChanged();
+ }
+
+ /// <summary>
+ /// Apply the bindings to BindingContext.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected void ApplyBindings()
+ {
+ ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);
+ }
+
+ /// <summary>
+ /// Override this method to execute an action when the BindingContext changes.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void OnBindingContextChanged()
+ {
+ BindingContextChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ /// <summary>
+ /// Call this method from a child class to notify that a change happened on a property.
+ /// </summary>
+ /// <param name="propertyName">The name of the property that changed.</param>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+
+ /// <summary>
+ /// Call this method from a child class to notify that a change is going to happen on a property.
+ /// </summary>
+ /// <param name="propertyName">The name of the property that is changing.</param>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
+ => PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
+
+ /// <summary>
+ /// Unapplies all previously set bindings.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected void UnapplyBindings()
+ {
+ for (int i = 0, _propertiesCount = _properties.Count; i < _propertiesCount; i++) {
+ BindablePropertyContext context = _properties [i];
+ if (context.Binding == null)
+ continue;
+
+ context.Binding.Unapply();
+ }
+ }
+
+ internal bool GetIsBound(BindableProperty targetProperty)
+ {
+ if (targetProperty == null)
+ throw new ArgumentNullException("targetProperty");
+
+ BindablePropertyContext bpcontext = GetContext(targetProperty);
+ return bpcontext != null && bpcontext.Binding != null;
+ }
+
+ /// <summary>
+ /// Returns the value that is contained the BindableProperty.
+ /// </summary>
+ /// <param name="property0">The BindableProperty instance.</param>
+ /// <param name="property1">The BindableProperty instance.</param>
+ /// <returns>The value that is contained the BindableProperty</returns>
+ internal object[] GetValues(BindableProperty property0, BindableProperty property1)
+ {
+ var values = new object[2];
+
+ for (var i = 0; i < _properties.Count; i++)
+ {
+ BindablePropertyContext context = _properties[i];
+
+ if (ReferenceEquals(context.Property, property0))
+ {
+ values[0] = context.Value;
+ property0 = null;
+ }
+ else if (ReferenceEquals(context.Property, property1))
+ {
+ values[1] = context.Value;
+ property1 = null;
+ }
+
+ if (property0 == null && property1 == null)
+ return values;
+ }
+
+ if (!ReferenceEquals(property0, null))
+ values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
+ if (!ReferenceEquals(property1, null))
+ values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
+
+ return values;
+ }
+
+ /// <summary>
+ /// Returns the value that is contained the BindableProperty.
+ /// </summary>
+ /// <param name="property0">The BindableProperty instance.</param>
+ /// <param name="property1">The BindableProperty instance.</param>
+ /// <param name="property2">The BindableProperty instance.</param>
+ /// <returns>The value that is contained the BindableProperty</returns>
+ internal object[] GetValues(BindableProperty property0, BindableProperty property1, BindableProperty property2)
+ {
+ var values = new object[3];
+
+ for (var i = 0; i < _properties.Count; i++)
+ {
+ BindablePropertyContext context = _properties[i];
+
+ if (ReferenceEquals(context.Property, property0))
+ {
+ values[0] = context.Value;
+ property0 = null;
+ }
+ else if (ReferenceEquals(context.Property, property1))
+ {
+ values[1] = context.Value;
+ property1 = null;
+ }
+ else if (ReferenceEquals(context.Property, property2))
+ {
+ values[2] = context.Value;
+ property2 = null;
+ }
+
+ if (property0 == null && property1 == null && property2 == null)
+ return values;
+ }
+
+ if (!ReferenceEquals(property0, null))
+ values[0] = property0.DefaultValueCreator == null ? property0.DefaultValue : CreateAndAddContext(property0).Value;
+ if (!ReferenceEquals(property1, null))
+ values[1] = property1.DefaultValueCreator == null ? property1.DefaultValue : CreateAndAddContext(property1).Value;
+ if (!ReferenceEquals(property2, null))
+ values[2] = property2.DefaultValueCreator == null ? property2.DefaultValue : CreateAndAddContext(property2).Value;
+
+ return values;
+ }
+
+ /// <summary>
+ /// Returns the value that is contained the BindableProperty.
+ /// </summary>
+ /// <param name="properties">The array of the BindableProperty instances</param>
+ /// <returns>The values that is contained the BindableProperty instances.</returns>
+ internal object[] GetValues(params BindableProperty[] properties)
+ {
+ var values = new object[properties.Length];
+ for (var i = 0; i < _properties.Count; i++) {
+ var context = _properties[i];
+ var index = properties.IndexOf(context.Property);
+ if (index < 0)
+ continue;
+ values[index] = context.Value;
+ }
+ for (var i = 0; i < values.Length; i++) {
+ if (!ReferenceEquals(values[i], null))
+ continue;
+ values[i] = properties[i].DefaultValueCreator == null ? properties[i].DefaultValue : CreateAndAddContext(properties[i]).Value;
+ }
+ return values;
+ }
+
+ internal virtual void OnRemoveDynamicResource(BindableProperty property)
+ {
+ }
+
+ internal virtual void OnSetDynamicResource(BindableProperty property, string key)
+ {
+ }
+
+ internal void RemoveDynamicResource(BindableProperty property)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ OnRemoveDynamicResource(property);
+ BindablePropertyContext context = GetOrCreateContext(property);
+ context.Attributes &= ~BindableContextAttributes.IsDynamicResource;
+ }
+
+ internal void SetBinding(BindableProperty targetProperty, BindingBase binding, bool fromStyle)
+ {
+ if (targetProperty == null)
+ throw new ArgumentNullException("targetProperty");
+ if (binding == null)
+ throw new ArgumentNullException("binding");
+
+ if (fromStyle && !CanBeSetFromStyle(targetProperty))
+ return;
+
+ var context = GetOrCreateContext(targetProperty);
+ if (fromStyle)
+ context.Attributes |= BindableContextAttributes.IsSetFromStyle;
+ else
+ context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
+
+ if (context.Binding != null)
+ context.Binding.Unapply();
+
+ BindingBase oldBinding = context.Binding;
+ context.Binding = binding;
+
+ targetProperty.BindingChanging?.Invoke(this, oldBinding, binding);
+
+ binding.Apply(BindingContext, this, targetProperty);
+ }
+
+ bool CanBeSetFromStyle(BindableProperty property)
+ {
+ var context = GetContext(property);
+ if (context == null)
+ return true;
+ if ((context.Attributes & BindableContextAttributes.IsSetFromStyle) == BindableContextAttributes.IsSetFromStyle)
+ return true;
+ if ((context.Attributes & BindableContextAttributes.IsDefaultValue) == BindableContextAttributes.IsDefaultValue)
+ return true;
+ if ((context.Attributes & BindableContextAttributes.IsDefaultValueCreated) == BindableContextAttributes.IsDefaultValueCreated)
+ return true;
+ return false;
+ }
+
+ internal void SetDynamicResource(BindableProperty property, string key)
+ {
+ SetDynamicResource(property, key, false);
+ }
+
+ internal void SetDynamicResource(BindableProperty property, string key, bool fromStyle)
+ {
+ if (property == null)
+ throw new ArgumentNullException(nameof(property));
+ if (string.IsNullOrEmpty(key))
+ throw new ArgumentNullException(nameof(key));
+ if (fromStyle && !CanBeSetFromStyle(property))
+ return;
+
+ var context = GetOrCreateContext(property);
+
+ context.Attributes |= BindableContextAttributes.IsDynamicResource;
+ if (fromStyle)
+ context.Attributes |= BindableContextAttributes.IsSetFromStyle;
+ else
+ context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
+
+ OnSetDynamicResource(property, key);
+ }
+
+ internal void SetValue(BindableProperty property, object value, bool fromStyle)
+ {
+ SetValue(property, value, fromStyle, true);
+ }
+
+ internal void SetValueCore(BindablePropertyKey propertyKey, object value, SetValueFlags attributes = SetValueFlags.None)
+ {
+ SetValueCore(propertyKey.BindableProperty, value, attributes, SetValuePrivateFlags.None, false);
+ }
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ /// <param name="property">The BindableProperty on which to assign a value.</param>
+ /// <param name="value">The value to set</param>
+ /// <param name="attributes">The set value flag</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
+ {
+ SetValueCore(property, value, attributes, SetValuePrivateFlags.Default, false);
+ }
+
+ internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes, bool forceSendChangeSignal)
+ {
+ bool checkAccess = (privateAttributes & SetValuePrivateFlags.CheckAccess) != 0;
+ bool manuallySet = (privateAttributes & SetValuePrivateFlags.ManuallySet) != 0;
+ bool silent = (privateAttributes & SetValuePrivateFlags.Silent) != 0;
+ bool fromStyle = (privateAttributes & SetValuePrivateFlags.FromStyle) != 0;
+ bool converted = (privateAttributes & SetValuePrivateFlags.Converted) != 0;
+
+ if (property == null)
+ throw new ArgumentNullException("property");
+ if (checkAccess && property.IsReadOnly)
+ {
+ Debug.WriteLine("Can not set the BindableProperty \"{0}\" because it is readonly.", property.PropertyName);
+ return;
+ }
+
+ if (!converted && !property.TryConvert(ref value))
+ {
+ Console.WriteLine("SetValue", "Can not convert {0} to type '{1}'", value, property.ReturnType);
+ return;
+ }
+
+ if (property.ValidateValue != null && !property.ValidateValue(this, value))
+ throw new ArgumentException("Value was an invalid value for " + property.PropertyName, "value");
+
+ if (property.CoerceValue != null)
+ value = property.CoerceValue(this, value);
+
+ BindablePropertyContext context = GetOrCreateContext(property);
+ if (manuallySet) {
+ context.Attributes |= BindableContextAttributes.IsManuallySet;
+ context.Attributes &= ~BindableContextAttributes.IsSetFromStyle;
+ } else
+ context.Attributes &= ~BindableContextAttributes.IsManuallySet;
+
+ if (fromStyle)
+ context.Attributes |= BindableContextAttributes.IsSetFromStyle;
+ // else omitted on purpose
+
+ bool currentlyApplying = _applying;
+
+ if ((context.Attributes & BindableContextAttributes.IsBeingSet) != 0)
+ {
+ Queue<SetValueArgs> delayQueue = context.DelayedSetters;
+ if (delayQueue == null)
+ context.DelayedSetters = delayQueue = new Queue<SetValueArgs>();
+
+ delayQueue.Enqueue(new SetValueArgs(property, context, value, currentlyApplying, attributes));
+ }
+ else
+ {
+ context.Attributes |= BindableContextAttributes.IsBeingSet;
+ SetValueActual(property, context, value, currentlyApplying, forceSendChangeSignal, attributes, silent);
+
+ Queue<SetValueArgs> delayQueue = context.DelayedSetters;
+ if (delayQueue != null)
+ {
+ while (delayQueue.Count > 0)
+ {
+ SetValueArgs s = delayQueue.Dequeue();
+ SetValueActual(s.Property, s.Context, s.Value, s.CurrentlyApplying, forceSendChangeSignal, s.Attributes);
+ }
+
+ context.DelayedSetters = null;
+ }
+
+ context.Attributes &= ~BindableContextAttributes.IsBeingSet;
+ }
+ }
+
+ internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChanged)
+ {
+ var prop = _properties.ToArray();
+ for (int i = 0, propLength = prop.Length; i < propLength; i++) {
+ BindablePropertyContext context = prop [i];
+ BindingBase binding = context.Binding;
+ if (binding == null)
+ continue;
+
+ if (skipBindingContext && ReferenceEquals(context.Property, BindingContextProperty))
+ continue;
+
+ binding.Unapply(fromBindingContextChanged: fromBindingContextChanged);
+ binding.Apply(BindingContext, this, context.Property, fromBindingContextChanged: fromBindingContextChanged);
+ }
+ }
+
+ static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
+ {
+ object context = bindable._inheritedContext;
+ var oldBinding = oldBindingBase as Binding;
+ var newBinding = newBindingBase as Binding;
+
+ if (context == null && oldBinding != null)
+ context = oldBinding.Context;
+ if (context != null && newBinding != null)
+ newBinding.Context = context;
+ }
+
+ static void BindingContextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue)
+ {
+ bindable._inheritedContext = null;
+ bindable.ApplyBindings(skipBindingContext: true, fromBindingContextChanged:true);
+ bindable.OnBindingContextChanged();
+ }
+
+ void ClearValue(BindableProperty property, bool fromStyle, bool checkAccess)
+ {
+ if (property == null)
+ throw new ArgumentNullException(nameof(property));
+
+ 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 && !CanBeSetFromStyle(property))
+ return;
+
+ object original = bpcontext.Value;
+
+ object newValue = property.GetDefaultValue(this);
+
+ bool same = Equals(original, newValue);
+ if (!same)
+ {
+ property.PropertyChanging?.Invoke(this, original, newValue);
+
+ OnPropertyChanging(property.PropertyName);
+ }
+
+ bpcontext.Attributes &= ~BindableContextAttributes.IsManuallySet;
+ bpcontext.Value = newValue;
+ if (property.DefaultValueCreator == null)
+ bpcontext.Attributes |= BindableContextAttributes.IsDefaultValue;
+ else
+ bpcontext.Attributes |= BindableContextAttributes.IsDefaultValueCreated;
+
+ if (!same)
+ {
+ OnPropertyChanged(property.PropertyName);
+ property.PropertyChanged?.Invoke(this, original, newValue);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ BindablePropertyContext CreateAndAddContext(BindableProperty property)
+ {
+ var context = new BindablePropertyContext { Property = property, Value = property.DefaultValueCreator != null ? property.DefaultValueCreator(this) : property.DefaultValue };
+
+ if (property.DefaultValueCreator == null)
+ context.Attributes = BindableContextAttributes.IsDefaultValue;
+ else
+ context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
+
+ _properties.Add(context);
+ return context;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ BindablePropertyContext GetContext(BindableProperty property)
+ {
+ List<BindablePropertyContext> properties = _properties;
+
+ for (var i = 0; i < properties.Count; i++)
+ {
+ BindablePropertyContext context = properties[i];
+ if (ReferenceEquals(context.Property, property))
+ return context;
+ }
+
+ return null;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ BindablePropertyContext GetOrCreateContext(BindableProperty property)
+ {
+ BindablePropertyContext context = GetContext(property);
+ if (context == null)
+ {
+ context = CreateAndAddContext(property);
+ }
+ else if (property.DefaultValueCreator != null )
+ {
+ context.Value = property.DefaultValueCreator(this); //Update Value from dali
+ }//added by xb.teng
+
+ return context;
+ }
+
+ void RemoveBinding(BindableProperty property, BindablePropertyContext context)
+ {
+ context.Binding.Unapply();
+
+ property.BindingChanging?.Invoke(this, context.Binding, null);
+
+ context.Binding = null;
+ }
+
+ void SetValue(BindableProperty property, object value, bool fromStyle, bool checkAccess)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ if (checkAccess && property.IsReadOnly)
+ throw new InvalidOperationException(string.Format("The BindableProperty \"{0}\" is readonly.", property.PropertyName));
+
+ if (fromStyle && !CanBeSetFromStyle(property))
+ return;
+
+ SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource,
+ (fromStyle ? SetValuePrivateFlags.FromStyle : SetValuePrivateFlags.ManuallySet) | (checkAccess ? SetValuePrivateFlags.CheckAccess : 0),
+ false);
+ }
+
+ void SetValueActual(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, bool forceSendChangeSignal, SetValueFlags attributes, bool silent = false)
+ {
+ object original = context.Value;
+ bool raiseOnEqual = (attributes & SetValueFlags.RaiseOnEqual) != 0;
+ bool clearDynamicResources = (attributes & SetValueFlags.ClearDynamicResource) != 0;
+ bool clearOneWayBindings = (attributes & SetValueFlags.ClearOneWayBindings) != 0;
+ bool clearTwoWayBindings = (attributes & SetValueFlags.ClearTwoWayBindings) != 0;
+
+ bool same = ReferenceEquals(context.Property, BindingContextProperty) ? ReferenceEquals(value, original) : Equals(value, original);
+ if (!silent && (!same || raiseOnEqual))
+ {
+ property.PropertyChanging?.Invoke(this, original, value);
+
+ OnPropertyChanging(property.PropertyName);
+ }
+
+ if (!same || raiseOnEqual)
+ {
+ context.Value = value;
+ }
+
+ context.Attributes &= ~BindableContextAttributes.IsDefaultValue;
+ context.Attributes &= ~BindableContextAttributes.IsDefaultValueCreated;
+
+ if ((context.Attributes & BindableContextAttributes.IsDynamicResource) != 0 && clearDynamicResources)
+ RemoveDynamicResource(property);
+
+ BindingBase binding = context.Binding;
+ if (binding != null)
+ {
+ if (clearOneWayBindings && binding.GetRealizedMode(property) == BindingMode.OneWay || clearTwoWayBindings && binding.GetRealizedMode(property) == BindingMode.TwoWay)
+ {
+ RemoveBinding(property, context);
+ binding = null;
+ }
+ }
+
+ if (!silent)
+ {
+ if ((!same || raiseOnEqual))
+ {
+ property.PropertyChanged?.Invoke(this, original, value);
+
+ if (binding != null && !currentlyApplying)
+ {
+ _applying = true;
+ binding.Apply(true);
+ _applying = false;
+ }
+
+ OnPropertyChanged(property.PropertyName);
+ }
+ else if (true == same && true == forceSendChangeSignal)
+ {
+ if (binding != null && !currentlyApplying)
+ {
+ _applying = true;
+ binding.Apply(true);
+ _applying = false;
+ }
+
+ OnPropertyChanged(property.PropertyName);
+ }
+ }
+ }
+
+ [Flags]
+ enum BindableContextAttributes
+ {
+ IsManuallySet = 1 << 0,
+ IsBeingSet = 1 << 1,
+ IsDynamicResource = 1 << 2,
+ IsSetFromStyle = 1 << 3,
+ IsDefaultValue = 1 << 4,
+ IsDefaultValueCreated = 1 << 5,
+ }
+
+ class BindablePropertyContext
+ {
+ public BindableContextAttributes Attributes;
+ public BindingBase Binding;
+ public Queue<SetValueArgs> DelayedSetters;
+ public BindableProperty Property;
+ public object Value;
+ }
+
+ [Flags]
+ internal enum SetValuePrivateFlags
+ {
+ None = 0,
+ CheckAccess = 1 << 0,
+ Silent = 1 << 1,
+ ManuallySet = 1 << 2,
+ FromStyle = 1 << 3,
+ Converted = 1 << 4,
+ Default = CheckAccess
+ }
+
+ class SetValueArgs
+ {
+ public readonly SetValueFlags Attributes;
+ public readonly BindablePropertyContext Context;
+ public readonly bool CurrentlyApplying;
+ public readonly BindableProperty Property;
+ public readonly object Value;
+
+ public SetValueArgs(BindableProperty property, BindablePropertyContext context, object value, bool currentlyApplying, SetValueFlags attributes)
+ {
+ Property = property;
+ Context = context;
+ Value = value;
+ CurrentlyApplying = currentlyApplying;
+ Attributes = attributes;
+ }
+ }
+ }
+}
+
+namespace Tizen.NUI.Binding.Internals
+{
+ /// <summary>
+ /// SetValueFlags. For internal use.
+ /// </summary>
+ [Flags]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public enum SetValueFlags
+ {
+ /// <summary>
+ /// None.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ None = 0,
+
+ /// <summary>
+ /// Clear OneWay bindings.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ ClearOneWayBindings = 1 << 0,
+
+ /// <summary>
+ /// Clear TwoWay bindings.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ ClearTwoWayBindings = 1 << 1,
+
+ /// <summary>
+ /// Clear dynamic resource.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ ClearDynamicResource = 1 << 2,
+
+ /// <summary>
+ /// Raise or equal.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ RaiseOnEqual = 1 << 3
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.ComponentModel;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// A BindableProperty is a backing store for properties allowing bindings on BindableObject.
+ /// </summary>
+ [DebuggerDisplay("{PropertyName}")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal sealed class BindableProperty
+ {
+ /// <summary>
+ /// Delegate for BindableProperty.PropertyChanged.
+ /// </summary>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="oldValue">The old property value.</param>
+ /// <param name="newValue">The new property value.</param>
+ public delegate void BindingPropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue);
+
+ /// <summary>
+ /// Strongly-typed delegate for BindableProperty.PropertyChanged.
+ /// </summary>
+ /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="oldValue">The old property value.</param>
+ /// <param name="newValue">The new property value.</param>
+ public delegate void BindingPropertyChangedDelegate<in TPropertyType>(BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
+
+ /// <summary>
+ /// Delegate for BindableProperty.PropertyChanging.
+ /// </summary>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="oldValue">The old property value.</param>
+ /// <param name="newValue">The new property value.</param>
+ public delegate void BindingPropertyChangingDelegate(BindableObject bindable, object oldValue, object newValue);
+
+ /// <summary>
+ /// Strongly-typed delegate for BindableProperty.PropertyChanging.
+ /// </summary>
+ /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="oldValue">The old property value.</param>
+ /// <param name="newValue">The new property value.</param>
+ public delegate void BindingPropertyChangingDelegate<in TPropertyType>(BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
+
+ /// <summary>
+ /// Delegate for BindableProperty.CoerceValue.
+ /// </summary>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="value">The value to coerce.</param>
+ /// <returns>System.Object</returns>
+ public delegate object CoerceValueDelegate(BindableObject bindable, object value);
+
+ /// <summary>
+ /// Strongly-typed delegate for BindableProperty.CoerceValue.
+ /// </summary>
+ /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="value">The value to coerce.</param>
+ /// <returns>TPropertyType</returns>
+ public delegate TPropertyType CoerceValueDelegate<TPropertyType>(BindableObject bindable, TPropertyType value);
+
+ /// <summary>
+ /// Delegate for BindableProperty.DefaultValueCreator.
+ /// </summary>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <returns>System.Object</returns>
+ public delegate object CreateDefaultValueDelegate(BindableObject bindable);
+
+ /// <summary>
+ /// Strongly-typed delegate for BindableProperty.DefaultValueCreator.
+ /// </summary>
+ /// <typeparam name="TDeclarer">The type of the object that delared the property.</typeparam>
+ /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <returns>TPropertyType</returns>
+ public delegate TPropertyType CreateDefaultValueDelegate<in TDeclarer, out TPropertyType>(TDeclarer bindable);
+
+ /// <summary>
+ /// Delegate for BindableProperty.ValidateValue.
+ /// </summary>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="value">The default value.</param>
+ /// <returns>System.Boolean</returns>
+ public delegate bool ValidateValueDelegate(BindableObject bindable, object value);
+
+ /// <summary>
+ /// Strongly-typed delegate for BindableProperty.ValidateValue.
+ /// </summary>
+ /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
+ /// <param name="bindable">The bindable object that contains the property.</param>
+ /// <param name="value">The default value.</param>
+ /// <returns>System.Boolean</returns>
+ public delegate bool ValidateValueDelegate<in TPropertyType>(BindableObject bindable, TPropertyType value);
+
+ static readonly Dictionary<Type, TypeConverter> WellKnownConvertTypes = new Dictionary<Type,TypeConverter>
+ {
+ //Fang: Wait for check
+ //{ typeof(Uri), new UriTypeConverter() },
+ //{ typeof(Color), new ColorTypeConverter() },
+ //{ typeof(Size2D), new Size2DTypeConverter() },
+ //{ typeof(Position2D), new Position2DTypeConverter() },
+ //{ typeof(Size), new SizeTypeConverter() },
+ //{ typeof(Position), new PositionTypeConverter() },
+ //{ typeof(Rectangle), new RectangleTypeConverter() },
+ //{ typeof(Rotation), new RotationTypeConverter() },
+ //{ typeof(Thickness), new ThicknessTypeConverter() },
+ //{ typeof(Vector2), new Vector2TypeConverter() },
+ //{ typeof(Vector3), new Vector3TypeConverter() },
+ //{ typeof(Vector4), new Vector4TypeConverter() },
+ //{ typeof(RelativeVector2), new RelativeVector2TypeConverter() },
+ //{ typeof(RelativeVector3), new RelativeVector3TypeConverter() },
+ //{ typeof(RelativeVector4), new RelativeVector4TypeConverter() },
+ };
+
+ // more or less the encoding of this, without the need to reflect
+ // http://msdn.microsoft.com/en-us/library/y5b434w4.aspx
+ static readonly Dictionary<Type, Type[]> SimpleConvertTypes = new Dictionary<Type, Type[]>
+ {
+ { typeof(sbyte), new[] { typeof(string), typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(byte), new[] { typeof(string), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(short), new[] { typeof(string), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(ushort), new[] { typeof(string), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(int), new[] { typeof(string), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(uint), new[] { typeof(string), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(long), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(char), new[] { typeof(string), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
+ { typeof(float), new[] { typeof(string), typeof(double) } },
+ { typeof(ulong), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } }
+ };
+
+ BindableProperty(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
+ ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
+ CoerceValueDelegate coerceValue = null, BindablePropertyBindingChanging bindingChanging = null, bool isReadOnly = false, CreateDefaultValueDelegate defaultValueCreator = null)
+ {
+ if (propertyName == null)
+ throw new ArgumentNullException("propertyName");
+ if (ReferenceEquals(returnType, null))
+ throw new ArgumentNullException("returnType");
+ if (ReferenceEquals(declaringType, null))
+ throw new ArgumentNullException("declaringType");
+
+ // don't use Enum.IsDefined as its redonkulously expensive for what it does
+ if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay && defaultBindingMode != BindingMode.OneTime)
+ throw new ArgumentException("Not a valid type of BindingMode", "defaultBindingMode");
+ if (defaultValue == null && Nullable.GetUnderlyingType(returnType) == null && returnType.GetTypeInfo().IsValueType)
+ throw new ArgumentException("Not a valid default value", "defaultValue");
+ if (defaultValue != null && !returnType.IsInstanceOfType(defaultValue))
+ throw new ArgumentException("Default value did not match return type", "defaultValue");
+ if (defaultBindingMode == BindingMode.Default)
+ defaultBindingMode = BindingMode.OneWay;
+
+ PropertyName = propertyName;
+ ReturnType = returnType;
+ ReturnTypeInfo = returnType.GetTypeInfo();
+ DeclaringType = declaringType;
+ DefaultValue = defaultValue;
+ DefaultBindingMode = defaultBindingMode;
+ PropertyChanged = propertyChanged;
+ PropertyChanging = propertyChanging;
+ ValidateValue = validateValue;
+ CoerceValue = coerceValue;
+ BindingChanging = bindingChanging;
+ IsReadOnly = isReadOnly;
+ DefaultValueCreator = defaultValueCreator;
+ }
+
+ /// <summary>
+ /// Gets the type declaring the BindableProperty.
+ /// </summary>
+ public Type DeclaringType { get; private set; }
+
+ /// <summary>
+ /// Gets the default BindingMode.
+ /// </summary>
+ public BindingMode DefaultBindingMode { get; private set; }
+
+ /// <summary>
+ /// Gets the default value for the BindableProperty.
+ /// </summary>
+ public object DefaultValue { get; }
+
+ /// <summary>
+ /// Gets a value indicating if the BindableProperty is created form a BindablePropertyKey.
+ /// </summary>
+ public bool IsReadOnly { get; private set; }
+
+ /// <summary>
+ /// Gets the property name.
+ /// </summary>
+ public string PropertyName { get; }
+
+ /// <summary>
+ /// Gets the type of the BindableProperty.
+ /// </summary>
+ public Type ReturnType { get; }
+
+ internal BindablePropertyBindingChanging BindingChanging { get; private set; }
+
+ internal CoerceValueDelegate CoerceValue { get; private set; }
+
+ internal CreateDefaultValueDelegate DefaultValueCreator { get; }
+
+ internal BindingPropertyChangedDelegate PropertyChanged { get; private set; }
+
+ internal BindingPropertyChangingDelegate PropertyChanging { get; private set; }
+
+ internal System.Reflection.TypeInfo ReturnTypeInfo { get; }
+
+ internal ValidateValueDelegate ValidateValue { get; private set; }
+
+ /// <summary>
+ /// Deprecated. Do not use.
+ /// </summary>
+ /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
+ /// <typeparam name="TPropertyType">The type of the property.</typeparam>
+ /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ /// <returns>A newly created BindableProperty.</returns>
+ [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
+ public static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
+ ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
+ BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
+ CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
+ {
+ return Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, defaultValueCreator: defaultValueCreator);
+ }
+
+ /// <summary>
+ /// Creates a new instance of the BindableProperty class.
+ /// </summary>
+ /// <param name="propertyName">The name of the BindableProperty.</param>
+ /// <param name="returnType">The type of the property.</param>
+ /// <param name="declaringType">The type of the declaring object.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ /// <returns>A newly created BindableProperty.</returns>
+ public static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue = null, BindingMode defaultBindingMode = BindingMode.OneWay,
+ ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
+ CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
+ {
+ return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
+ defaultValueCreator: defaultValueCreator);
+ }
+
+ /// <summary>
+ /// Deprecated. Do not use.
+ /// </summary>
+ /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
+ /// <typeparam name="TPropertyType">The type of the property.</typeparam>
+ /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
+ public static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
+ BindingMode defaultBindingMode = BindingMode.OneWay, ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
+ BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
+ CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
+ {
+ return CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null,
+ defaultValueCreator: defaultValueCreator);
+ }
+
+ /// <summary>
+ /// Creates a new instance of the BindableProperty class for an attached property.
+ /// </summary>
+ /// <param name="propertyName">The name of the BindableProperty.</param>
+ /// <param name="returnType">The type of the property.</param>
+ /// <param name="declaringType">The type of the declaring object.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ /// <returns>A newly created BindableProperty.</returns>
+ public static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
+ ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
+ CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
+ {
+ return CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false, defaultValueCreator);
+ }
+
+ /// <summary>
+ /// Deprecated. Do not use.
+ /// </summary>
+ /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
+ /// <typeparam name="TPropertyType">The type of the property.</typeparam>
+ /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
+ [Obsolete("CreateAttachedReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
+ public static BindablePropertyKey CreateAttachedReadOnly<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
+ BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
+ BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
+ CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
+
+ {
+ return
+ new BindablePropertyKey(CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
+ defaultValueCreator));
+ }
+
+ /// <summary>
+ /// Creates a new instance of the BindableProperty class for attached read-only properties.
+ /// </summary>
+ /// <param name="propertyName">The name of the BindableProperty.</param>
+ /// <param name="returnType">The type of the property.</param>
+ /// <param name="declaringType">The type of the declaring object.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
+ public static BindablePropertyKey CreateAttachedReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
+ ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
+ CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
+ {
+ return
+ new BindablePropertyKey(CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
+ defaultValueCreator));
+ }
+
+ /// <summary>
+ /// Deprecated. Do not use.
+ /// </summary>
+ /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
+ /// <typeparam name="TPropertyType">The type of the property.</typeparam>
+ /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ /// <returns>A newly created BindablePropertyKey.</returns>
+ [Obsolete("CreateReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
+ public static BindablePropertyKey CreateReadOnly<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue,
+ BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
+ BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
+ CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
+ {
+ return new BindablePropertyKey(Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true, defaultValueCreator));
+ }
+
+ /// <summary>
+ /// Creates a new instance of the BindablePropertyKey class.
+ /// </summary>
+ /// <param name="propertyName">The name of the BindableProperty.</param>
+ /// <param name="returnType">The type of the property.</param>
+ /// <param name="declaringType">The type of the declaring object.</param>
+ /// <param name="defaultValue">The default value for the property.</param>
+ /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
+ /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
+ /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
+ /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
+ /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
+ /// <returns>A newly created BindablePropertyKey.</returns>
+ public static BindablePropertyKey CreateReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
+ ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
+ CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
+ {
+ return
+ new BindablePropertyKey(new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
+ isReadOnly: true, defaultValueCreator: defaultValueCreator));
+ }
+
+ [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
+ internal static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode,
+ ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
+ CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
+ CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
+ {
+ if (getter == null)
+ throw new ArgumentNullException("getter");
+
+ Expression expr = getter.Body;
+
+ var unary = expr as UnaryExpression;
+ if (unary != null)
+ expr = unary.Operand;
+
+ var member = expr as MemberExpression;
+ if (member == null)
+ throw new ArgumentException("getter must be a MemberExpression", "getter");
+
+ var property = (PropertyInfo)member.Member;
+
+ ValidateValueDelegate untypedValidateValue = null;
+ BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
+ BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
+ CoerceValueDelegate untypedCoerceValue = null;
+ CreateDefaultValueDelegate untypedDefaultValueCreator = null;
+ if (validateValue != null)
+ untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
+ if (propertyChanged != null)
+ untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
+ if (propertyChanging != null)
+ untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
+ if (coerceValue != null)
+ untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
+ if (defaultValueCreator != null)
+ untypedDefaultValueCreator = o => defaultValueCreator((TDeclarer)o);
+
+ return new BindableProperty(property.Name, property.PropertyType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged,
+ untypedBindingPropertyChanging, untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
+ }
+
+ internal static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
+ BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
+ CreateDefaultValueDelegate defaultValueCreator = null)
+ {
+ return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging,
+ defaultValueCreator: defaultValueCreator);
+ }
+
+ [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
+ internal static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue, BindingMode defaultBindingMode,
+ ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
+ CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
+ CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
+ {
+ if (staticgetter == null)
+ throw new ArgumentNullException("staticgetter");
+
+ Expression expr = staticgetter.Body;
+
+ var unary = expr as UnaryExpression;
+ if (unary != null)
+ expr = unary.Operand;
+
+ var methodcall = expr as MethodCallExpression;
+ if (methodcall == null)
+ throw new ArgumentException("staticgetter must be a MethodCallExpression", "staticgetter");
+
+ MethodInfo method = methodcall.Method;
+ if (!method.Name.StartsWith("Get", StringComparison.Ordinal))
+ throw new ArgumentException("staticgetter name must start with Get", "staticgetter");
+
+ string propertyname = method.Name.Substring(3);
+
+ ValidateValueDelegate untypedValidateValue = null;
+ BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
+ BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
+ CoerceValueDelegate untypedCoerceValue = null;
+ CreateDefaultValueDelegate untypedDefaultValueCreator = null;
+ if (validateValue != null)
+ untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
+ if (propertyChanged != null)
+ untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
+ if (propertyChanging != null)
+ untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
+ if (coerceValue != null)
+ untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
+ if (defaultValueCreator != null)
+ untypedDefaultValueCreator = o => defaultValueCreator(o);
+
+ return new BindableProperty(propertyname, method.ReturnType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged, untypedBindingPropertyChanging,
+ untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
+ }
+
+ internal static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
+ BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
+ bool isReadOnly, CreateDefaultValueDelegate defaultValueCreator = null)
+ {
+ return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, isReadOnly,
+ defaultValueCreator);
+ }
+
+ internal object GetDefaultValue(BindableObject bindable)
+ {
+ if (DefaultValueCreator != null)
+ return DefaultValueCreator(bindable);
+
+ return DefaultValue;
+ }
+
+ internal bool TryConvert(ref object value)
+ {
+ if (value == null)
+ {
+ return !ReturnTypeInfo.IsValueType || ReturnTypeInfo.IsGenericType && ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
+ }
+
+ Type valueType = value.GetType();
+ Type type = ReturnType;
+
+ // Dont support arbitrary IConvertible by limiting which types can use this
+ Type[] convertableTo;
+ TypeConverter typeConverterTo;
+ if (SimpleConvertTypes.TryGetValue(valueType, out convertableTo) && Array.IndexOf(convertableTo, type) != -1)
+ {
+ value = Convert.ChangeType(value, type);
+ }
+ else if (WellKnownConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
+ {
+ value = typeConverterTo.ConvertFromInvariantString(value.ToString());
+ }
+ else if (!ReturnTypeInfo.IsAssignableFrom(valueType.GetTypeInfo()))
+ {
+ var cast = type.GetImplicitConversionOperator(fromType: valueType, toType: type)
+ ?? valueType.GetImplicitConversionOperator(fromType: valueType, toType: type);
+
+ if (cast == null)
+ return false;
+
+ value = cast.Invoke(null, new[] { value });
+ }
+
+ return true;
+ }
+
+ internal delegate void BindablePropertyBindingChanging(BindableObject bindable, BindingBase oldValue, BindingBase newValue);
+ }
+}
--- /dev/null
+using System;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// The secret key to a BindableProperty, used to implement a BindableProperty with restricted write access.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal sealed class BindablePropertyKey
+ {
+ internal BindablePropertyKey(BindableProperty property)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ BindableProperty = property;
+ }
+
+ /// <summary>
+ /// Gets the BindableProperty.
+ /// </summary>
+ public BindableProperty BindableProperty { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ internal sealed class Binding : BindingBase
+ {
+ internal const string SelfPath = ".";
+ IValueConverter _converter;
+ object _converterParameter;
+
+ BindingExpression _expression;
+ string _path;
+ object _source;
+ string _updateSourceEventName;
+
+ public Binding()
+ {
+ }
+
+ public Binding(string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null, string stringFormat = null, object source = null)
+ {
+ if (path == null)
+ throw new ArgumentNullException("path");
+ if (string.IsNullOrWhiteSpace(path))
+ throw new ArgumentException("path can not be an empty string", "path");
+
+ Path = path;
+ Converter = converter;
+ ConverterParameter = converterParameter;
+ Mode = mode;
+ StringFormat = stringFormat;
+ Source = source;
+ }
+
+ public IValueConverter Converter
+ {
+ get { return _converter; }
+ set
+ {
+ ThrowIfApplied();
+
+ _converter = value;
+ }
+ }
+
+ public object ConverterParameter
+ {
+ get { return _converterParameter; }
+ set
+ {
+ ThrowIfApplied();
+
+ _converterParameter = value;
+ }
+ }
+
+ public string Path
+ {
+ get { return _path; }
+ set
+ {
+ ThrowIfApplied();
+
+ _path = value;
+ _expression = new BindingExpression(this, !string.IsNullOrWhiteSpace(value) ? value : SelfPath);
+ }
+ }
+
+ public object Source
+ {
+ get { return _source; }
+ set
+ {
+ ThrowIfApplied();
+ _source = value;
+ }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string UpdateSourceEventName {
+ get { return _updateSourceEventName; }
+ set {
+ ThrowIfApplied();
+ _updateSourceEventName = value;
+ }
+ }
+
+ [Obsolete]
+ public static Binding Create<TSource>(Expression<Func<TSource, object>> propertyGetter, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null,
+ string stringFormat = null)
+ {
+ if (propertyGetter == null)
+ throw new ArgumentNullException("propertyGetter");
+
+ return new Binding(GetBindingPath(propertyGetter), mode, converter, converterParameter, stringFormat);
+ }
+
+ internal override void Apply(bool fromTarget)
+ {
+ base.Apply(fromTarget);
+
+ if (_expression == null)
+ _expression = new BindingExpression(this, SelfPath);
+
+ _expression.Apply(fromTarget);
+ }
+
+ internal override void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
+ {
+ object src = _source;
+ var isApplied = IsApplied;
+
+ base.Apply(src ?? newContext, bindObj, targetProperty, fromBindingContextChanged: fromBindingContextChanged);
+
+ if (src != null && isApplied && fromBindingContextChanged)
+ return;
+
+ object bindingContext = src ?? Context ?? newContext;
+ if (_expression == null && bindingContext != null)
+ _expression = new BindingExpression(this, SelfPath);
+
+ _expression?.Apply(bindingContext, bindObj, targetProperty);
+ }
+
+ internal override BindingBase Clone()
+ {
+ return new Binding(Path, Mode) { Converter = Converter, ConverterParameter = ConverterParameter, StringFormat = StringFormat, Source = Source, UpdateSourceEventName = UpdateSourceEventName };
+ }
+
+ internal override object GetSourceValue(object value, Type targetPropertyType)
+ {
+ if (Converter != null)
+ value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
+
+ return base.GetSourceValue(value, targetPropertyType);
+ }
+
+ internal override object GetTargetValue(object value, Type sourcePropertyType)
+ {
+ if (Converter != null)
+ value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
+
+ return base.GetTargetValue(value, sourcePropertyType);
+ }
+
+ internal override void Unapply(bool fromBindingContextChanged = false)
+ {
+ if (Source != null && fromBindingContextChanged && IsApplied)
+ return;
+
+ base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
+
+ if (_expression != null)
+ _expression.Unapply();
+ }
+
+ [Obsolete]
+ static string GetBindingPath<TSource>(Expression<Func<TSource, object>> propertyGetter)
+ {
+ Expression expr = propertyGetter.Body;
+
+ var unary = expr as UnaryExpression;
+ if (unary != null)
+ expr = unary.Operand;
+
+ var builder = new StringBuilder();
+
+ var indexed = false;
+
+ var member = expr as MemberExpression;
+ if (member == null)
+ {
+ var methodCall = expr as MethodCallExpression;
+ if (methodCall != null)
+ {
+ if (methodCall.Arguments.Count == 0)
+ throw new ArgumentException("Method calls are not allowed in binding expression");
+
+ var arguments = new List<string>(methodCall.Arguments.Count);
+ foreach (Expression arg in methodCall.Arguments)
+ {
+ if (arg.NodeType != ExpressionType.Constant)
+ throw new ArgumentException("Only constants can be used as indexer arguments");
+
+ object value = ((ConstantExpression)arg).Value;
+ arguments.Add(value != null ? value.ToString() : "null");
+ }
+
+ Type declarerType = methodCall.Method.DeclaringType;
+ DefaultMemberAttribute defaultMember = declarerType.GetTypeInfo().GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault();
+ string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";
+
+ MethodInfo getterInfo =
+ declarerType.GetProperties().Where(pi => pi.Name == indexerName && pi.CanRead && pi.GetMethod.IsPublic && !pi.GetMethod.IsStatic).Select(pi => pi.GetMethod).FirstOrDefault();
+ if (getterInfo != null)
+ {
+ if (getterInfo == methodCall.Method)
+ {
+ indexed = true;
+ builder.Append("[");
+
+ var first = true;
+ foreach (string argument in arguments)
+ {
+ if (!first)
+ builder.Append(",");
+
+ builder.Append(argument);
+ first = false;
+ }
+
+ builder.Append("]");
+
+ member = methodCall.Object as MemberExpression;
+ }
+ else
+ throw new ArgumentException("Method calls are not allowed in binding expressions");
+ }
+ else
+ throw new ArgumentException("Public indexer not found");
+ }
+ else
+ throw new ArgumentException("Invalid expression type");
+ }
+
+ while (member != null)
+ {
+ var property = (PropertyInfo)member.Member;
+ if (builder.Length != 0)
+ {
+ if (!indexed)
+ builder.Insert(0, ".");
+ else
+ indexed = false;
+ }
+
+ builder.Insert(0, property.Name);
+
+ //member = member.Expression as MemberExpression ?? (member.Expression as UnaryExpression)?.Operand as MemberExpression;
+ member = member.Expression as MemberExpression ?? (member.Expression is UnaryExpression ? (member.Expression as UnaryExpression).Operand as MemberExpression : null);
+ }
+
+ return builder.ToString();
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections;
+using System.Runtime.CompilerServices;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// An abstract class that provides a BindingMode and a formatting option.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal abstract class BindingBase
+ {
+ static readonly ConditionalWeakTable<IEnumerable, CollectionSynchronizationContext> SynchronizedCollections = new ConditionalWeakTable<IEnumerable, CollectionSynchronizationContext>();
+
+ BindingMode _mode = BindingMode.Default;
+ string _stringFormat;
+ object _targetNullValue;
+ object _fallbackValue;
+
+ internal BindingBase()
+ {
+ }
+
+ /// <summary>
+ /// Gets or sets the mode for this binding.
+ /// </summary>
+ public BindingMode Mode
+ {
+ get { return _mode; }
+ set
+ {
+ if ( value != BindingMode.Default
+ && value != BindingMode.OneWay
+ && value != BindingMode.OneWayToSource
+ && value != BindingMode.TwoWay
+ && value != BindingMode.OneTime)
+ throw new ArgumentException("mode is not a valid BindingMode", "mode");
+
+ ThrowIfApplied();
+
+ _mode = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the string format for this binding.
+ /// </summary>
+ public string StringFormat
+ {
+ get { return _stringFormat; }
+ set
+ {
+ ThrowIfApplied();
+
+ _stringFormat = value;
+ }
+ }
+
+ public object TargetNullValue
+ {
+ get { return _targetNullValue; }
+ set {
+ ThrowIfApplied();
+ _targetNullValue = value;
+ }
+ }
+
+ public object FallbackValue {
+ get => _fallbackValue;
+ set {
+ ThrowIfApplied();
+ _fallbackValue = value;
+ }
+ }
+
+ internal bool AllowChaining { get; set; }
+
+ internal object Context { get; set; }
+
+ internal bool IsApplied { get; private set; }
+
+ /// <summary>
+ /// Stops synchronization on the collection.
+ /// </summary>
+ /// <param name="collection">The collection on which to stop synchronization.</param>
+ public static void DisableCollectionSynchronization(IEnumerable collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException(nameof(collection));
+
+ SynchronizedCollections.Remove(collection);
+ }
+
+ public static void EnableCollectionSynchronization(IEnumerable collection, object context, CollectionSynchronizationCallback callback)
+ {
+ if (collection == null)
+ throw new ArgumentNullException(nameof(collection));
+ if (callback == null)
+ throw new ArgumentNullException(nameof(callback));
+
+ SynchronizedCollections.Add(collection, new CollectionSynchronizationContext(context, callback));
+ }
+
+ /// <summary>
+ /// Throws an InvalidOperationException if the binding has been applied.
+ /// </summary>
+ protected void ThrowIfApplied()
+ {
+ if (IsApplied)
+ throw new InvalidOperationException("Can not change a binding while it's applied");
+ }
+
+ internal virtual void Apply(bool fromTarget)
+ {
+ IsApplied = true;
+ }
+
+ internal virtual void Apply(object context, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
+ {
+ IsApplied = true;
+ }
+
+ internal abstract BindingBase Clone();
+
+ internal virtual object GetSourceValue(object value, Type targetPropertyType)
+ {
+ if (value == null && TargetNullValue != null)
+ return TargetNullValue;
+ if (StringFormat != null)
+ return string.Format(StringFormat, value);
+
+ return value;
+ }
+
+ internal virtual object GetTargetValue(object value, Type sourcePropertyType)
+ {
+ return value;
+ }
+
+ internal static bool TryGetSynchronizedCollection(IEnumerable collection, out CollectionSynchronizationContext synchronizationContext)
+ {
+ if (collection == null)
+ throw new ArgumentNullException(nameof(collection));
+
+ return SynchronizedCollections.TryGetValue(collection, out synchronizationContext);
+ }
+
+ internal virtual void Unapply(bool fromBindingContextChanged = false)
+ {
+ IsApplied = false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ internal static class BindingBaseExtensions
+ {
+ public static BindingMode GetRealizedMode(this BindingBase self, BindableProperty property)
+ {
+ return self.Mode != BindingMode.Default ? self.Mode : property.DefaultBindingMode;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Tizen.NUI.Binding.Internals;
+using System.Runtime.CompilerServices;
+
+namespace Tizen.NUI.Binding
+{
+ internal class BindingExpression
+ {
+ internal const string PropertyNotFoundErrorMessage = "'{0}' property not found on '{1}', target property: '{2}.{3}'";
+
+ readonly List<BindingExpressionPart> _parts = new List<BindingExpressionPart>();
+
+ BindableProperty _targetProperty;
+ WeakReference<object> _weakSource;
+ WeakReference<BindableObject> _weakTarget;
+
+ internal BindingExpression(BindingBase binding, string path)
+ {
+ if (binding == null)
+ throw new ArgumentNullException(nameof(binding));
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
+
+ Binding = binding;
+ Path = path;
+
+ ParsePath();
+ }
+
+ internal BindingBase Binding { get; }
+
+ internal string Path { get; }
+
+ /// <summary>
+ /// Applies the binding expression to a previously set source and target.
+ /// </summary>
+ internal void Apply(bool fromTarget = false)
+ {
+ if (_weakSource == null || _weakTarget == null)
+ return;
+
+ BindableObject target;
+ if (!_weakTarget.TryGetTarget(out target))
+ {
+ Unapply();
+ return;
+ }
+
+ object source;
+ if (_weakSource.TryGetTarget(out source) && _targetProperty != null)
+ ApplyCore(source, target, _targetProperty, fromTarget);
+ }
+
+ /// <summary>
+ /// Applies the binding expression to a new source or target.
+ /// </summary>
+ internal void Apply(object sourceObject, BindableObject target, BindableProperty property)
+ {
+ _targetProperty = property;
+
+ BindableObject prevTarget;
+ if (_weakTarget != null && _weakTarget.TryGetTarget(out prevTarget) && !ReferenceEquals(prevTarget, target))
+ throw new InvalidOperationException("Binding instances can not be reused");
+
+ object previousSource;
+ if (_weakSource != null && _weakSource.TryGetTarget(out previousSource) && !ReferenceEquals(previousSource, sourceObject))
+ throw new InvalidOperationException("Binding instances can not be reused");
+
+ _weakSource = new WeakReference<object>(sourceObject);
+ _weakTarget = new WeakReference<BindableObject>(target);
+
+ ApplyCore(sourceObject, target, property);
+ }
+
+ internal void Unapply()
+ {
+ object sourceObject;
+ if (_weakSource != null && _weakSource.TryGetTarget(out sourceObject))
+ {
+ for (var i = 0; i < _parts.Count - 1; i++)
+ {
+ BindingExpressionPart part = _parts[i];
+
+ if (!part.IsSelf)
+ {
+ part.TryGetValue(sourceObject, out sourceObject);
+ }
+
+ part.Unsubscribe();
+ }
+ }
+
+ _weakSource = null;
+ _weakTarget = null;
+ }
+
+ /// <summary>
+ /// Applies the binding expression to a previously set source or target.
+ /// </summary>
+ void ApplyCore(object sourceObject, BindableObject target, BindableProperty property, bool fromTarget = false)
+ {
+ BindingMode mode = Binding.GetRealizedMode(_targetProperty);
+ if ((mode == BindingMode.OneWay || mode == BindingMode.OneTime) && fromTarget)
+ return;
+
+ bool needsGetter = (mode == BindingMode.TwoWay && !fromTarget) || mode == BindingMode.OneWay || mode == BindingMode.OneTime;
+ bool needsSetter = !needsGetter && ((mode == BindingMode.TwoWay && fromTarget) || mode == BindingMode.OneWayToSource);
+
+ object current = sourceObject;
+ object previous = null;
+ BindingExpressionPart part = null;
+
+ for (var i = 0; i < _parts.Count; i++)
+ {
+ part = _parts[i];
+ bool isLast = i + 1 == _parts.Count;
+
+ if (!part.IsSelf && current != null)
+ {
+ // Allow the object instance itself to provide its own TypeInfo
+ var reflectable = current as IReflectableType;
+ System.Reflection.TypeInfo currentType = reflectable != null ? reflectable.GetTypeInfo() : current.GetType().GetTypeInfo();
+ if (part.LastGetter == null || !part.LastGetter.DeclaringType.GetTypeInfo().IsAssignableFrom(currentType))
+ SetupPart(currentType, part);
+
+ if (!isLast)
+ part.TryGetValue(current, out current);
+ }
+
+ if (!part.IsSelf && current != null)
+ {
+ if ((needsGetter && part.LastGetter == null) || (needsSetter && part.NextPart == null && part.LastSetter == null))
+ {
+ Console.WriteLine("Binding", PropertyNotFoundErrorMessage, part.Content, current, target.GetType(), property.PropertyName);
+ break;
+ }
+ }
+
+ if (mode == BindingMode.OneWay || mode == BindingMode.TwoWay)
+ {
+ var inpc = current as INotifyPropertyChanged;
+ if (inpc != null && !ReferenceEquals(current, previous))
+ part.Subscribe(inpc);
+ }
+
+ previous = current;
+ }
+
+ Debug.Assert(part != null, "There should always be at least the self part in the expression.");
+
+ if (needsGetter)
+ {
+ object value = property.DefaultValue;
+ if (part.TryGetValue(current, out value) || part.IsSelf)
+ {
+ value = Binding.GetSourceValue(value, property.ReturnType);
+ }
+ else
+ value = property.DefaultValue;
+
+ if (!TryConvert(part, ref value, property.ReturnType, true))
+ {
+ Console.WriteLine("Binding", "{0} can not be converted to type '{1}'", value, property.ReturnType);
+ return;
+ }
+
+ target.SetValueCore(property, value, SetValueFlags.ClearDynamicResource, BindableObject.SetValuePrivateFlags.Default | BindableObject.SetValuePrivateFlags.Converted, false);
+ }
+ else if (needsSetter && part.LastSetter != null && current != null)
+ {
+ object value = Binding.GetTargetValue(target.GetValue(property), part.SetterType);
+
+ if (!TryConvert(part, ref value, part.SetterType, false))
+ {
+ Console.WriteLine("Binding", "{0} can not be converted to type '{1}'", value, part.SetterType);
+ return;
+ }
+
+ object[] args;
+ if (part.IsIndexer)
+ {
+ args = new object[part.Arguments.Length + 1];
+ part.Arguments.CopyTo(args, 0);
+ args[args.Length - 1] = value;
+ }
+ else if (part.IsBindablePropertySetter)
+ {
+ args = new[] { part.BindablePropertyField, value };
+ }
+ else
+ {
+ args = new[] { value };
+ }
+
+ part.LastSetter.Invoke(current, args);
+ }
+ }
+
+ IEnumerable<BindingExpressionPart> GetPart(string part)
+ {
+ part = part.Trim();
+ if (part == string.Empty)
+ throw new FormatException("Path contains an empty part");
+
+ BindingExpressionPart indexer = null;
+
+ int lbIndex = part.IndexOf('[');
+ if (lbIndex != -1)
+ {
+ int rbIndex = part.LastIndexOf(']');
+ if (rbIndex == -1)
+ throw new FormatException("Indexer did not contain closing bracket");
+
+ int argLength = rbIndex - lbIndex - 1;
+ if (argLength == 0)
+ throw new FormatException("Indexer did not contain arguments");
+
+ string argString = part.Substring(lbIndex + 1, argLength);
+ indexer = new BindingExpressionPart(this, argString, true);
+
+ part = part.Substring(0, lbIndex);
+ part = part.Trim();
+ }
+
+ if (part.Length > 0)
+ yield return new BindingExpressionPart(this, part);
+ if (indexer != null)
+ yield return indexer;
+ }
+
+ void ParsePath()
+ {
+ string p = Path.Trim();
+
+ var last = new BindingExpressionPart(this, ".");
+ _parts.Add(last);
+
+ if (p[0] == '.')
+ {
+ if (p.Length == 1)
+ return;
+
+ p = p.Substring(1);
+ }
+
+ string[] pathParts = p.Split('.');
+ for (var i = 0; i < pathParts.Length; i++)
+ {
+ foreach (BindingExpressionPart part in GetPart(pathParts[i]))
+ {
+ last.NextPart = part;
+ _parts.Add(part);
+ last = part;
+ }
+ }
+ }
+
+ void SetupPart(System.Reflection.TypeInfo sourceType, BindingExpressionPart part)
+ {
+ part.Arguments = null;
+ part.LastGetter = null;
+ part.LastSetter = null;
+
+ PropertyInfo property = null;
+ if (part.IsIndexer)
+ {
+ if (sourceType.IsArray)
+ {
+ int index;
+ if (!int.TryParse(part.Content, out index))
+ Console.WriteLine("Binding", "{0} could not be parsed as an index for a {1}", part.Content, sourceType);
+ else
+ part.Arguments = new object[] { index };
+
+ part.LastGetter = sourceType.GetDeclaredMethod("Get");
+ part.LastSetter = sourceType.GetDeclaredMethod("Set");
+ part.SetterType = sourceType.GetElementType();
+ }
+
+ DefaultMemberAttribute defaultMember = sourceType.GetCustomAttributes(typeof(DefaultMemberAttribute), true).OfType<DefaultMemberAttribute>().FirstOrDefault();
+ string indexerName = defaultMember != null ? defaultMember.MemberName : "Item";
+
+ part.IndexerName = indexerName;
+
+#if NETSTANDARD2_0
+ try {
+ property = sourceType.GetDeclaredProperty(indexerName);
+ }
+ catch (AmbiguousMatchException) {
+ // Get most derived instance of property
+ foreach (var p in sourceType.GetProperties().Where(prop => prop.Name == indexerName)) {
+ if (property == null || property.DeclaringType.IsAssignableFrom(property.DeclaringType))
+ property = p;
+ }
+ }
+#else
+ property = sourceType.GetDeclaredProperty(indexerName);
+#endif
+
+ if (property == null) //is the indexer defined on the base class?
+ property = sourceType.BaseType.GetProperty(indexerName);
+ if (property == null) //is the indexer defined on implemented interface ?
+ {
+ foreach (var implementedInterface in sourceType.ImplementedInterfaces)
+ {
+ property = implementedInterface.GetProperty(indexerName);
+ if (property != null)
+ break;
+ }
+ }
+
+ if (property != null)
+ {
+ ParameterInfo parameter = property.GetIndexParameters().FirstOrDefault();
+ if (parameter != null)
+ {
+ try
+ {
+ object arg = Convert.ChangeType(part.Content, parameter.ParameterType, CultureInfo.InvariantCulture);
+ part.Arguments = new[] { arg };
+ }
+ catch (FormatException)
+ {
+ }
+ catch (InvalidCastException)
+ {
+ }
+ catch (OverflowException)
+ {
+ }
+ }
+ }
+ }
+ else
+ property = sourceType.GetDeclaredProperty(part.Content) ?? sourceType.BaseType?.GetProperty(part.Content);
+
+ if (property != null)
+ {
+ if (property.CanRead && property.GetMethod.IsPublic && !property.GetMethod.IsStatic)
+ part.LastGetter = property.GetMethod;
+ if (property.CanWrite && property.SetMethod.IsPublic && !property.SetMethod.IsStatic)
+ {
+ part.LastSetter = property.SetMethod;
+ part.SetterType = part.LastSetter.GetParameters().Last().ParameterType;
+
+ if (Binding.AllowChaining)
+ {
+ FieldInfo bindablePropertyField = sourceType.GetDeclaredField(part.Content + "Property");
+ if (bindablePropertyField != null && bindablePropertyField.FieldType == typeof(BindableProperty) && sourceType.ImplementedInterfaces.Contains(typeof(IElementController)))
+ {
+ MethodInfo setValueMethod = null;
+#if NETSTANDARD1_0
+ foreach (MethodInfo m in sourceType.AsType().GetRuntimeMethods())
+ {
+ if (m.Name.EndsWith("IElementController.SetValueFromRenderer"))
+ {
+ ParameterInfo[] parameters = m.GetParameters();
+ if (parameters.Length == 2 && parameters[0].ParameterType == typeof(BindableProperty))
+ {
+ setValueMethod = m;
+ break;
+ }
+ }
+ }
+#else
+ setValueMethod = typeof(IElementController).GetMethod("SetValueFromRenderer", new[] { typeof(BindableProperty), typeof(object) });
+#endif
+ if (setValueMethod != null)
+ {
+ part.LastSetter = setValueMethod;
+ part.IsBindablePropertySetter = true;
+ part.BindablePropertyField = bindablePropertyField.GetValue(null);
+ }
+ }
+ }
+ }
+#if !NETSTANDARD1_0
+ //TupleElementNamesAttribute tupleEltNames;
+ //if (property != null
+ // && part.NextPart != null
+ // && property.PropertyType.IsGenericType
+ // && (property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<>)
+ // || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,>)
+ // || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,>)
+ // || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,>)
+ // || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,>)
+ // || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,,>)
+ // || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,,,>)
+ // || property.PropertyType.GetGenericTypeDefinition() == typeof(ValueTuple<,,,,,,,>))
+ // && (tupleEltNames = property.GetCustomAttribute(typeof(TupleElementNamesAttribute)) as TupleElementNamesAttribute) != null)
+ //{
+ // // modify the nextPart to access the tuple item via the ITuple indexer
+ // var nextPart = part.NextPart;
+ // var name = nextPart.Content;
+ // var index = tupleEltNames.TransformNames.IndexOf(name);
+ // if (index >= 0)
+ // {
+ // nextPart.IsIndexer = true;
+ // nextPart.Content = index.ToString();
+ // }
+ //}
+#endif
+ }
+
+ }
+ static Type[] DecimalTypes = new[] { typeof(float), typeof(decimal), typeof(double) };
+
+ bool TryConvert(BindingExpressionPart part, ref object value, Type convertTo, bool toTarget)
+ {
+ if (value == null)
+ return true;
+ if ((toTarget && _targetProperty.TryConvert(ref value)) || (!toTarget && convertTo.IsInstanceOfType(value)))
+ return true;
+
+ object original = value;
+ try
+ {
+ var stringValue = value as string ?? string.Empty;
+ // see: https://bugzilla.xamarin.com/show_bug.cgi?id=32871
+ // do not canonicalize "*.[.]"; "1." should not update bound BindableProperty
+ if (stringValue.EndsWith(".") && DecimalTypes.Contains(convertTo))
+ throw new FormatException();
+
+ // do not canonicalize "-0"; user will likely enter a period after "-0"
+ if (stringValue == "-0" && DecimalTypes.Contains(convertTo))
+ throw new FormatException();
+
+ value = Convert.ChangeType(value, convertTo, CultureInfo.InvariantCulture);
+ return true;
+ }
+ catch (InvalidCastException)
+ {
+ value = original;
+ return false;
+ }
+ catch (FormatException)
+ {
+ value = original;
+ return false;
+ }
+ catch (OverflowException)
+ {
+ value = original;
+ return false;
+ }
+ }
+
+ class BindingPair
+ {
+ public BindingPair(BindingExpressionPart part, object source, bool isLast)
+ {
+ Part = part;
+ Source = source;
+ IsLast = isLast;
+ }
+
+ public bool IsLast { get; set; }
+
+ public BindingExpressionPart Part { get; private set; }
+
+ public object Source { get; private set; }
+ }
+
+ internal class WeakPropertyChangedProxy
+ {
+ readonly WeakReference<INotifyPropertyChanged> _source = new WeakReference<INotifyPropertyChanged>(null);
+ readonly WeakReference<PropertyChangedEventHandler> _listener = new WeakReference<PropertyChangedEventHandler>(null);
+ readonly PropertyChangedEventHandler _handler;
+ readonly EventHandler _bchandler;
+ internal WeakReference<INotifyPropertyChanged> Source => _source;
+
+ public WeakPropertyChangedProxy()
+ {
+ _handler = new PropertyChangedEventHandler(OnPropertyChanged);
+ _bchandler = new EventHandler(OnBCChanged);
+ }
+
+ public WeakPropertyChangedProxy(INotifyPropertyChanged source, PropertyChangedEventHandler listener) : this()
+ {
+ SubscribeTo(source, listener);
+ }
+
+ public void SubscribeTo(INotifyPropertyChanged source, PropertyChangedEventHandler listener)
+ {
+ source.PropertyChanged += _handler;
+ var bo = source as BindableObject;
+ if (bo != null)
+ bo.BindingContextChanged += _bchandler;
+ _source.SetTarget(source);
+ _listener.SetTarget(listener);
+ }
+
+ public void Unsubscribe()
+ {
+ INotifyPropertyChanged source;
+ if (_source.TryGetTarget(out source) && source != null)
+ source.PropertyChanged -= _handler;
+ var bo = source as BindableObject;
+ if (bo != null)
+ bo.BindingContextChanged -= _bchandler;
+
+ _source.SetTarget(null);
+ _listener.SetTarget(null);
+ }
+
+ void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ PropertyChangedEventHandler handler;
+ if (_listener.TryGetTarget(out handler) && handler != null)
+ handler(sender, e);
+ else
+ Unsubscribe();
+ }
+
+ void OnBCChanged(object sender, EventArgs e)
+ {
+ OnPropertyChanged(sender, new PropertyChangedEventArgs("BindingContext"));
+ }
+ }
+
+ class BindingExpressionPart
+ {
+ readonly BindingExpression _expression;
+ readonly PropertyChangedEventHandler _changeHandler;
+ WeakPropertyChangedProxy _listener;
+
+ public BindingExpressionPart(BindingExpression expression, string content, bool isIndexer = false)
+ {
+ _expression = expression;
+ IsSelf = content == Tizen.NUI.Binding.Binding.SelfPath;
+ Content = content;
+ IsIndexer = isIndexer;
+
+ _changeHandler = PropertyChanged;
+ }
+
+ public void Subscribe(INotifyPropertyChanged handler)
+ {
+ INotifyPropertyChanged source;
+ if (_listener != null && _listener.Source.TryGetTarget(out source) && ReferenceEquals(handler, source))
+ // Already subscribed
+ return;
+
+ // Clear out the old subscription if necessary
+ Unsubscribe();
+
+ _listener = new WeakPropertyChangedProxy(handler, _changeHandler);
+ }
+
+ public void Unsubscribe()
+ {
+ var listener = _listener;
+ if (listener != null)
+ {
+ listener.Unsubscribe();
+ _listener = null;
+ }
+ }
+
+ public object[] Arguments { get; set; }
+
+ public object BindablePropertyField { get; set; }
+
+ public string Content { get; internal set; }
+
+ public string IndexerName { get; set; }
+
+ public bool IsBindablePropertySetter { get; set; }
+
+ public bool IsIndexer { get; internal set; }
+
+ public bool IsSelf { get; }
+
+ public MethodInfo LastGetter { get; set; }
+
+ public MethodInfo LastSetter { get; set; }
+
+ public BindingExpressionPart NextPart { get; set; }
+
+ public Type SetterType { get; set; }
+
+ public void PropertyChanged(object sender, PropertyChangedEventArgs args)
+ {
+ BindingExpressionPart part = NextPart ?? this;
+
+ string name = args.PropertyName;
+
+ if (!string.IsNullOrEmpty(name))
+ {
+ if (part.IsIndexer)
+ {
+ if (name.Contains("["))
+ {
+ if (name != string.Format("{0}[{1}]", part.IndexerName, part.Content))
+ return;
+ }
+ else if (name != part.IndexerName)
+ return;
+ }
+ else if (name != part.Content)
+ {
+ return;
+ }
+ }
+
+ _expression.Apply();
+ // Device.BeginInvokeOnMainThread(() => _expression.Apply());
+ }
+
+ public bool TryGetValue(object source, out object value)
+ {
+ value = source;
+
+ if (LastGetter != null && value != null)
+ {
+ if (IsIndexer)
+ {
+ try
+ {
+ value = LastGetter.Invoke(value, Arguments);
+ }
+ catch (TargetInvocationException ex)
+ {
+ if (!(ex.InnerException is KeyNotFoundException))
+ throw;
+ value = null;
+ }
+ return true;
+ }
+ value = LastGetter.Invoke(value, Arguments);
+ return true;
+ }
+
+ return false;
+ }
+ }
+ }
+}
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// The direction of changes propagation for bindings.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal enum BindingMode
+ {
+ /// <summary>
+ /// When used in Bindings, indicates that the Binding should use the DefaultBindingMode. When used in BindableProperty declaration, defaults to BindingMode.OneWay.
+ /// </summary>
+ Default,
+
+ /// <summary>
+ /// Indicates that the binding should propagates changes from source (usually the View Model) to target (the BindableObject) in both directions.
+ /// </summary>
+ TwoWay,
+
+ /// <summary>
+ /// Indicates that the binding should only propagate changes from source (usually the View Model) to target (the BindableObject). This is the default mode for most BindableProperty values.
+ /// </summary>
+ OneWay,
+
+ /// <summary>
+ /// Indicates that the binding should only propagate changes from target (the BindableObject) to source (usually the View Model). This is mainly used for read-only BindableProperty values.
+ /// </summary>
+ OneWayToSource,
+
+ /// <summary>
+ /// Indicates that the binding will be applied only when the binding context changes and the value will not be monitored for changes with INotifyPropertyChanged.
+ /// </summary>
+ OneTime,
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+
+namespace Tizen.NUI.Binding
+{
+ public delegate void CollectionSynchronizationCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess);
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ internal sealed class CollectionSynchronizationContext
+ {
+ internal CollectionSynchronizationContext(object context, CollectionSynchronizationCallback callback)
+ {
+ ContextReference = new WeakReference(context);
+ Callback = callback;
+ }
+
+ internal CollectionSynchronizationCallback Callback { get; private set; }
+
+ internal object Context
+ {
+ get { return ContextReference != null ? ContextReference.Target : null; }
+ }
+
+ internal WeakReference ContextReference { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// ContentPropertyAttribute.cs
+//
+// Author:
+// Stephane Delcroix <stephane@delcroix.org>
+//
+// Copyright (c) 2013 S. Delcroix
+//
+
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ internal sealed class ContentPropertyAttribute : Attribute
+ {
+ internal static string[] ContentPropertyTypes = { "Tizen.NUI.Binding.ContentPropertyAttribute", "System.Windows.Markup.ContentPropertyAttribute" };
+
+ public ContentPropertyAttribute(string name)
+ {
+ Name = name;
+ }
+
+ public string Name { get; private set; }
+ }
+}
--- /dev/null
+using System;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// Template that specifies a group of styles and effects for controls.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class ControlTemplate : ElementTemplate
+ {
+ /// <summary>
+ /// For internal use only.
+ /// </summary>
+ public ControlTemplate()
+ {
+ }
+
+ /// <summary>
+ /// Creates a new control template for the specified control type.
+ /// </summary>
+ /// <param name="type">The type of control for which to create a template.</param>
+ public ControlTemplate(Type type) : base(type)
+ {
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Binding
+{
+ internal class DataTemplate : ElementTemplate
+ {
+ public DataTemplate()
+ {
+ }
+
+ public DataTemplate(Type type) : base(type)
+ {
+ }
+
+ public DataTemplate(Func<object> loadTemplate) : base(loadTemplate)
+ {
+ }
+
+ public IDictionary<BindableProperty, BindingBase> Bindings { get; } = new Dictionary<BindableProperty, BindingBase>();
+
+ public IDictionary<BindableProperty, object> Values { get; } = new Dictionary<BindableProperty, object>();
+
+ public void SetBinding(BindableProperty property, BindingBase binding)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+ if (binding == null)
+ throw new ArgumentNullException("binding");
+
+ Values.Remove(property);
+ Bindings[property] = binding;
+ }
+
+ public void SetValue(BindableProperty property, object value)
+ {
+ if (property == null)
+ throw new ArgumentNullException("property");
+
+ Bindings.Remove(property);
+ Values[property] = value;
+ }
+
+ internal override void SetupContent(object item)
+ {
+ ApplyBindings(item);
+ ApplyValues(item);
+ }
+
+ void ApplyBindings(object item)
+ {
+ if (Bindings == null)
+ return;
+
+ var bindable = item as BindableObject;
+ if (bindable == null)
+ return;
+
+ foreach (KeyValuePair<BindableProperty, BindingBase> kvp in Bindings)
+ {
+ if (Values.ContainsKey(kvp.Key))
+ throw new InvalidOperationException("Binding and Value found for " + kvp.Key.PropertyName);
+
+ bindable.SetBinding(kvp.Key, kvp.Value.Clone());
+ }
+ }
+
+ void ApplyValues(object item)
+ {
+ if (Values == null)
+ return;
+
+ var bindable = item as BindableObject;
+ if (bindable == null)
+ return;
+ foreach (KeyValuePair<BindableProperty, object> kvp in Values)
+ bindable.SetValue(kvp.Key, kvp.Value);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class DataTemplateExtensions
+ {
+ public static DataTemplate SelectDataTemplate(this DataTemplate self, object item, BindableObject container)
+ {
+ var selector = self as DataTemplateSelector;
+ if (selector == null)
+ return self;
+
+ return selector.SelectTemplate(item, container);
+ }
+
+ public static object CreateContent(this DataTemplate self, object item, BindableObject container)
+ {
+ return self.SelectDataTemplate(item, container).CreateContent();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Binding
+{
+ internal abstract class DataTemplateSelector : DataTemplate
+ {
+ Dictionary<Type, DataTemplate> _dataTemplates = new Dictionary<Type, DataTemplate>();
+
+ public DataTemplate SelectTemplate(object item, BindableObject container)
+ {
+ // var listView = container as ListView;
+
+ // var recycle = listView == null ? false :
+ // (listView.CachingStrategy & ListViewCachingStrategy.RecycleElementAndDataTemplate) ==
+ // ListViewCachingStrategy.RecycleElementAndDataTemplate;
+
+ DataTemplate dataTemplate = null;
+ // if (recycle && _dataTemplates.TryGetValue(item.GetType(), out dataTemplate))
+ // return dataTemplate;
+
+ dataTemplate = OnSelectTemplate(item, container);
+ if (dataTemplate is DataTemplateSelector)
+ throw new NotSupportedException(
+ "DataTemplateSelector.OnSelectTemplate must not return another DataTemplateSelector");
+
+ // if (recycle)
+ // {
+ // if (!dataTemplate.CanRecycle)
+ // throw new NotSupportedException(
+ // "RecycleElementAndDataTemplate requires DataTemplate activated with ctor taking a type.");
+
+ // _dataTemplates[item.GetType()] = dataTemplate;
+ // }
+
+ return dataTemplate;
+ }
+
+ protected abstract DataTemplate OnSelectTemplate(object item, BindableObject container);
+ }
+}
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ internal class DependencyAttribute : Attribute
+ {
+ public DependencyAttribute(Type implementorType)
+ {
+ Implementor = implementorType;
+ }
+
+ internal Type Implementor { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Binding
+{
+ internal enum DependencyFetchTarget
+ {
+ GlobalInstance,
+ NewInstance
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Linq;
+using System.Reflection;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Binding
+{
+ internal static class DependencyResolver
+ {
+ static Func<Type, object[], object> Resolver { get; set; }
+
+ public static void ResolveUsing(Func<Type, object[], object> resolver)
+ {
+ Resolver = resolver;
+ }
+
+ public static void ResolveUsing(Func<Type, object> resolver)
+ {
+ Resolver = (type, objects) => resolver.Invoke(type);
+ }
+
+ internal static object Resolve(Type type, params object[] args)
+ {
+ var result = Resolver?.Invoke(type, args);
+
+ if (result != null)
+ {
+ if (!type.IsInstanceOfType(result))
+ {
+ throw new InvalidCastException("Resolved instance is not of the correct type.");
+ }
+ }
+
+ return result;
+ }
+
+ internal static object ResolveOrCreate(Type type, params object[] args)
+ {
+ var result = Resolve(type, args);
+
+ if (result != null) return result;
+
+ if (args.Length > 0)
+ {
+ // This is by no means a general solution to matching with the correct constructor, but it'll
+ // do for finding Android renderers which need Context (vs older custom renderers which may still use
+ // parameterless constructors)
+ if (type.GetTypeInfo().DeclaredConstructors.Any(info => info.GetParameters().Length == args.Length))
+ {
+ return Activator.CreateInstance(type, args);
+ }
+ }
+
+ return Activator.CreateInstance(type);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ internal static class DependencyService
+ {
+ static bool s_initialized;
+
+ static readonly List<Type> DependencyTypes = new List<Type>();
+ static readonly Dictionary<Type, DependencyData> DependencyImplementations = new Dictionary<Type, DependencyData>();
+
+ public static T Resolve<T>(DependencyFetchTarget fallbackFetchTarget = DependencyFetchTarget.GlobalInstance) where T : class
+ {
+ var result = DependencyResolver.Resolve(typeof(T)) as T;
+
+ return result ?? Get<T>(fallbackFetchTarget);
+ }
+
+ public static T Get<T>(DependencyFetchTarget fetchTarget = DependencyFetchTarget.GlobalInstance) where T : class
+ {
+ Initialize();
+
+ Type targetType = typeof(T);
+
+ if (!DependencyImplementations.ContainsKey(targetType))
+ {
+ Type implementor = FindImplementor(targetType);
+ DependencyImplementations[targetType] = implementor != null ? new DependencyData { ImplementorType = implementor } : null;
+ }
+
+ DependencyData dependencyImplementation = DependencyImplementations[targetType];
+ if (dependencyImplementation == null)
+ return null;
+
+ if (fetchTarget == DependencyFetchTarget.GlobalInstance)
+ {
+ if (dependencyImplementation.GlobalInstance == null)
+ {
+ dependencyImplementation.GlobalInstance = Activator.CreateInstance(dependencyImplementation.ImplementorType);
+ }
+ return (T)dependencyImplementation.GlobalInstance;
+ }
+ return (T)Activator.CreateInstance(dependencyImplementation.ImplementorType);
+ }
+
+ public static void Register<T>() where T : class
+ {
+ Type type = typeof(T);
+ if (!DependencyTypes.Contains(type))
+ DependencyTypes.Add(type);
+ }
+
+ public static void Register<T, TImpl>() where T : class where TImpl : class, T
+ {
+ Type targetType = typeof(T);
+ Type implementorType = typeof(TImpl);
+ if (!DependencyTypes.Contains(targetType))
+ DependencyTypes.Add(targetType);
+
+ DependencyImplementations[targetType] = new DependencyData { ImplementorType = implementorType };
+ }
+
+ static Type FindImplementor(Type target)
+ {
+ return DependencyTypes.FirstOrDefault(t => target.IsAssignableFrom(t));
+ }
+
+ static void Initialize()
+ {
+ if (s_initialized)
+ {
+ return;
+ }
+
+ Assembly[] assemblies = Device.GetAssemblies();
+ if (Tizen.NUI.Binding.Internals.Registrar.ExtraAssemblies != null)
+ {
+ assemblies = assemblies.Union(Tizen.NUI.Binding.Internals.Registrar.ExtraAssemblies).ToArray();
+ }
+
+ Initialize(assemblies);
+ }
+
+ internal static void Initialize(Assembly[] assemblies)
+ {
+ if (s_initialized || assemblies == null)
+ {
+ return;
+ }
+ DependencyService.Register<IValueConverterProvider, ValueConverterProvider>();
+
+ Type targetAttrType = typeof(DependencyAttribute);
+
+ // Don't use LINQ for performance reasons
+ // Naive implementation can easily take over a second to run
+ foreach (Assembly assembly in assemblies)
+ {
+ Attribute[] attributes;
+ try
+ {
+ attributes = assembly.GetCustomAttributes(targetAttrType).ToArray();
+ }
+ catch (System.IO.FileNotFoundException)
+ {
+ // Sometimes the previewer doesn't actually have everything required for these loads to work
+ Console.WriteLine(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, targetAttrType.FullName);
+ continue;
+ }
+
+ if (attributes.Length == 0)
+ continue;
+
+ foreach (DependencyAttribute attribute in attributes)
+ {
+ if (!DependencyTypes.Contains(attribute.Implementor))
+ {
+ DependencyTypes.Add(attribute.Implementor);
+ }
+ }
+ }
+
+ s_initialized = true;
+ }
+
+ class DependencyData
+ {
+ public object GlobalInstance { get; set; }
+
+ public Type ImplementorType { get; set; }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ internal static class Device
+ {
+ public const string iOS = "iOS";
+ public const string Android = "Android";
+ public const string UWP = "UWP";
+ public const string macOS = "macOS";
+ public const string GTK = "GTK";
+ public const string Tizen = "Tizen";
+ public const string WPF = "WPF";
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static DeviceInfo info;
+
+ static IPlatformServices s_platformServices;
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetIdiom(TargetIdiom value) => Idiom = value;
+ public static TargetIdiom Idiom { get; internal set; }
+
+ //TODO: Why are there two of these? This is never used...?
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetTargetIdiom(TargetIdiom value) => Idiom = value;
+
+ [Obsolete("TargetPlatform is obsolete as of version 2.3.4. Please use RuntimePlatform instead.")]
+#pragma warning disable 0618
+ public static TargetPlatform OS
+ {
+ get
+ {
+ TargetPlatform platform;
+ if (Enum.TryParse(RuntimePlatform, out platform))
+ return platform;
+
+ // In the old TargetPlatform, there was no distinction between WinRT/UWP
+ if (RuntimePlatform == UWP)
+ {
+ return TargetPlatform.Windows;
+ }
+
+ return TargetPlatform.Other;
+ }
+ }
+#pragma warning restore 0618
+
+ public static string RuntimePlatform => PlatformServices?.RuntimePlatform;
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static DeviceInfo Info
+ {
+ get
+ {
+ // if (info == null)
+ // throw new InvalidOperationException("You MUST call Tizen.NUI.Xaml.Init(); prior to using it.");
+ return info;
+ }
+ set { info = value; }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetFlowDirection(FlowDirection value) => FlowDirection = value;
+ public static FlowDirection FlowDirection { get; internal set; }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool IsInvokeRequired
+ {
+ get { return PlatformServices.IsInvokeRequired; }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static IPlatformServices PlatformServices
+ {
+ get
+ {
+ if (s_platformServices == null)
+ throw new InvalidOperationException("You MUST call Tizen.NUI.Init(); prior to using it.");
+ return s_platformServices;
+ }
+ set
+ {
+ s_platformServices = value;
+ Console.WriteLine("Device s_platformServices : " + s_platformServices );
+ }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static IReadOnlyList<string> Flags { get; private set; }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetFlags(IReadOnlyList<string> flags)
+ {
+ Flags = flags;
+ }
+
+ public static void BeginInvokeOnMainThread(Action action)
+ {
+ PlatformServices?.BeginInvokeOnMainThread(action);
+ action();
+ Console.WriteLine("Device BeginInvokeOnMainThread action called");
+ }
+
+ // public static double GetNamedSize(NamedSize size, Element targetElement)
+ // {
+ // return GetNamedSize(size, targetElement.GetType());
+ // }
+
+ // public static double GetNamedSize(NamedSize size, Type targetElementType)
+ // {
+ // return GetNamedSize(size, targetElementType, false);
+ // }
+
+ [Obsolete("OnPlatform is obsolete as of version 2.3.4. Please use switch(RuntimePlatform) instead.")]
+ public static void OnPlatform(Action iOS = null, Action Android = null, Action WinPhone = null, Action Default = null)
+ {
+ switch (OS)
+ {
+ case TargetPlatform.iOS:
+ if (iOS != null)
+ iOS();
+ else if (Default != null)
+ Default();
+ break;
+ case TargetPlatform.Android:
+ if (Android != null)
+ Android();
+ else if (Default != null)
+ Default();
+ break;
+ case TargetPlatform.Windows:
+ case TargetPlatform.WinPhone:
+ if (WinPhone != null)
+ WinPhone();
+ else if (Default != null)
+ Default();
+ break;
+ case TargetPlatform.Other:
+ if (Default != null)
+ Default();
+ break;
+ }
+ }
+
+ [Obsolete("OnPlatform<> (generic) is obsolete as of version 2.3.4. Please use switch(RuntimePlatform) instead.")]
+ public static T OnPlatform<T>(T iOS, T Android, T WinPhone)
+ {
+ switch (OS)
+ {
+ case TargetPlatform.iOS:
+ return iOS;
+ case TargetPlatform.Android:
+ return Android;
+ case TargetPlatform.Windows:
+ case TargetPlatform.WinPhone:
+ return WinPhone;
+ }
+
+ return iOS;
+ }
+
+ public static void OpenUri(Uri uri)
+ {
+ // PlatformServices?.OpenUriAction(uri);
+ }
+
+ public static void StartTimer(TimeSpan interval, Func<bool> callback)
+ {
+ PlatformServices.StartTimer(interval, callback);
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static Assembly[] GetAssemblies()
+ {
+ return PlatformServices?.GetAssemblies();
+ }
+
+ // [EditorBrowsable(EditorBrowsableState.Never)]
+ // public static double GetNamedSize(NamedSize size, Type targetElementType, bool useOldSizes)
+ // {
+ // return PlatformServices.GetNamedSize(size, targetElementType, useOldSizes);
+ // }
+
+ internal static Task<Stream> GetStreamAsync(Uri uri, CancellationToken cancellationToken)
+ {
+ return PlatformServices?.GetStreamAsync(uri, cancellationToken);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal abstract class DeviceInfo : INotifyPropertyChanged, IDisposable
+ {
+ DeviceOrientation _currentOrientation;
+ bool _disposed;
+
+ public DeviceOrientation CurrentOrientation
+ {
+ get { return _currentOrientation; }
+ set
+ {
+ if (Equals(_currentOrientation, value))
+ return;
+ _currentOrientation = value;
+ OnPropertyChanged();
+ }
+ }
+
+ public virtual double DisplayRound(double value) =>
+ Math.Round(value);
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ return;
+ _disposed = true;
+ }
+
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+}
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal enum DeviceOrientation
+ {
+ Portrait,
+ Landscape,
+ PortraitUp,
+ PortraitDown,
+ LandscapeLeft,
+ LandscapeRight,
+ Other
+ }
+}
--- /dev/null
+using System;
+using System.ComponentModel;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// A collection of styles and properties that can be added to an element at run time.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal abstract class Effect
+ {
+ internal Effect()
+ {
+ }
+
+ /// <summary>
+ /// Gets the element to which the style is attached.
+ /// </summary>
+ public Element Element { get; internal set; }
+
+ /// <summary>
+ /// Gets a value that tells whether the effect is attached to an element.
+ /// </summary>
+ public bool IsAttached { get; private set; }
+
+ /// <summary>
+ /// Gets the ID that is used to resolve this effect at runtime.
+ /// </summary>
+ public string ResolveId { get; internal set; }
+
+ #region Statics
+ /// <summary>
+ /// Returns an Effect for the specified name, which is of the form ResolutionGroupName.ExportEffect.
+ /// </summary>
+ /// <param name="name">The name of the effect to get.</param>
+ /// <returns>The uniquely identified effect.</returns>
+ public static Effect Resolve(string name)
+ {
+ Effect result = null;
+ if (Tizen.NUI.Binding.Internals.Registrar.Effects.TryGetValue(name, out Type effectType))
+ {
+ result = (Effect)DependencyResolver.ResolveOrCreate(effectType);
+ }
+
+ if (result == null)
+ result = new NullEffect();
+ result.ResolveId = name;
+ return result;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Method that is called after the effect is attached and made valid.
+ /// </summary>
+ protected abstract void OnAttached();
+
+ /// <summary>
+ /// Method that is called after the effect is detached and invalidated.
+ /// </summary>
+ protected abstract void OnDetached();
+
+ internal virtual void ClearEffect()
+ {
+ if (IsAttached)
+ SendDetached();
+ Element = null;
+ }
+
+ internal virtual void SendAttached()
+ {
+ if (IsAttached)
+ return;
+ OnAttached();
+ IsAttached = true;
+ }
+
+ internal virtual void SendDetached()
+ {
+ if (!IsAttached)
+ return;
+ OnDetached();
+ IsAttached = false;
+ }
+
+ internal virtual void SendOnElementPropertyChanged(PropertyChangedEventArgs args)
+ {
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using System.Xml;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// Provides the base class for all Tizen.NUI.Binding hierarchal elements. This class contains all the methods and properties required to represent an element in the Tizen.NUI.Binding hierarchy.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal abstract partial class Element : BindableObject, IElement, INameScope, IElementController
+ {
+
+ // public static readonly BindableProperty MenuProperty = BindableProperty.CreateAttached(nameof(Menu), typeof(Menu), typeof(Element), null);
+
+ // public static Menu GetMenu(BindableObject bindable)
+ // {
+ // return (Menu)bindable.GetValue(MenuProperty);
+ // }
+
+ // public static void SetMenu(BindableObject bindable, Menu menu)
+ // {
+ // bindable.SetValue(MenuProperty, menu);
+ // }
+
+ internal static readonly ReadOnlyCollection<Element> EmptyChildren = new ReadOnlyCollection<Element>(new Element[0]);
+
+ /// <summary>
+ /// Identifies the ClassId bindable property.
+ /// </summary>
+ internal static readonly BindableProperty ClassIdProperty = BindableProperty.Create("ClassId", typeof(string), typeof(Element), null);
+
+ string _automationId;
+
+ IList<BindableObject> _bindableResources;
+
+ List<Action<object, ResourcesChangedEventArgs>> _changeHandlers;
+
+ Dictionary<BindableProperty, string> _dynamicResources;
+
+ IEffectControlProvider _effectControlProvider;
+
+ TrackableCollection<Effect> _effects;
+
+ Guid? _id;
+
+ Element _parentOverride;
+
+ IPlatform _platform;
+
+ string _styleId;
+
+ /// <summary>
+ /// Gets or sets a value that allows the automation framework to find and interact with this element.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string AutomationId
+ {
+ get { return _automationId; }
+ set
+ {
+ if (_automationId != null)
+ throw new InvalidOperationException("AutomationId may only be set one time");
+ _automationId = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value used to identify a collection of semantically similar elements.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string ClassId
+ {
+ get { return (string)GetValue(ClassIdProperty); }
+ set { SetValue(ClassIdProperty, value); }
+ }
+
+ internal IList<Effect> Effects
+ {
+ get
+ {
+ if (_effects == null)
+ {
+ _effects = new TrackableCollection<Effect>();
+ _effects.CollectionChanged += EffectsOnCollectionChanged;
+ _effects.Clearing += EffectsOnClearing;
+ }
+ return _effects;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value that can be used to uniquely identify an element through the run of an application.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Guid Id
+ {
+ get
+ {
+ if (!_id.HasValue)
+ _id = Guid.NewGuid();
+ return _id.Value;
+ }
+ }
+
+ /// <summary>
+ /// Gets the element which is the closest ancestor of this element that is a BaseHandle.
+ /// </summary>
+ [Obsolete("ParentView is obsolete as of version 2.1.0. Please use Parent instead.")]
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Element ParentView
+ {
+ get
+ {
+ Element parent = Parent;
+ while (parent != null)
+ {
+ var parentView = parent as Element;
+ if (parentView != null)
+ return parentView;
+ parent = parent.RealParent;
+ }
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a user defined value to uniquely identify the element.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string StyleId
+ {
+ get { return _styleId; }
+ set
+ {
+ if (_styleId == value)
+ return;
+
+ OnPropertyChanging();
+ _styleId = value;
+ OnPropertyChanged();
+ }
+ }
+
+ internal virtual ReadOnlyCollection<Element> LogicalChildrenInternal => EmptyChildren;
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ReadOnlyCollection<Element> LogicalChildren => LogicalChildrenInternal;
+
+ internal bool Owned { get; set; }
+
+ internal Element ParentOverride
+ {
+ get { return _parentOverride; }
+ set
+ {
+ if (_parentOverride == value)
+ return;
+
+ bool emitChange = Parent != value;
+
+ if (emitChange)
+ OnPropertyChanging(nameof(Parent));
+
+ _parentOverride = value;
+
+ if (emitChange)
+ OnPropertyChanged(nameof(Parent));
+ }
+ }
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ internal IPlatform Platform
+ {
+ get
+ {
+ if (_platform == null && RealParent != null)
+ return RealParent.Platform;
+ return _platform;
+ }
+ set
+ {
+ if (_platform == value)
+ return;
+ _platform = value;
+ PlatformSet?.Invoke(this, EventArgs.Empty);
+ foreach (Element descendant in Descendants())
+ {
+ descendant._platform = _platform;
+ descendant.PlatformSet?.Invoke(this, EventArgs.Empty);
+ }
+ }
+ }
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Element RealParent { get; private set; }
+
+ Dictionary<BindableProperty, string> DynamicResources
+ {
+ get { return _dynamicResources ?? (_dynamicResources = new Dictionary<BindableProperty, string>()); }
+ }
+
+ void IElement.AddResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
+ {
+ _changeHandlers = _changeHandlers ?? new List<Action<object, ResourcesChangedEventArgs>>(2);
+ _changeHandlers.Add(onchanged);
+ }
+
+ /// <summary>
+ /// Gets or sets the parent element of the element.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Element Parent
+ {
+ get { return _parentOverride ?? RealParent; }
+ set
+ {
+ if (RealParent == value)
+ return;
+
+ OnPropertyChanging();
+
+ if (RealParent != null)
+ ((IElement)RealParent).RemoveResourcesChangedListener(OnParentResourcesChanged);
+ RealParent = value;
+ if (RealParent != null)
+ {
+ OnParentResourcesChanged(RealParent?.GetMergedResources());
+ ((IElement)RealParent).AddResourcesChangedListener(OnParentResourcesChanged);
+ }
+
+ object context = value != null ? value.BindingContext : null;
+ if (value != null)
+ {
+ value.SetChildInheritedBindingContext(this, context);
+ }
+ else
+ {
+ SetInheritedBindingContext(this, null);
+ }
+
+ OnParentSet();
+
+ if (RealParent != null)
+ {
+ IPlatform platform = RealParent.Platform;
+ if (platform != null)
+ Platform = platform;
+ }
+
+ OnPropertyChanged();
+ }
+ }
+
+ void IElement.RemoveResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
+ {
+ if (_changeHandlers == null)
+ return;
+ _changeHandlers.Remove(onchanged);
+ }
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ internal IEffectControlProvider EffectControlProvider
+ {
+ get { return _effectControlProvider; }
+ set
+ {
+ if (_effectControlProvider == value)
+ return;
+ if (_effectControlProvider != null && _effects != null)
+ {
+ foreach (Effect effect in _effects)
+ effect?.SendDetached();
+ }
+ _effectControlProvider = value;
+ if (_effectControlProvider != null && _effects != null)
+ {
+ foreach (Effect effect in _effects)
+ {
+ if (effect != null)
+ AttachEffect(effect);
+ }
+ }
+ }
+ }
+
+ //void IElementController.SetValueFromRenderer(BindableProperty property, object value) => SetValueFromRenderer(property, value);
+
+ /// <summary>
+ /// Sets the value of the specified property.
+ /// </summary>
+ /// <param name="property">The BindableProperty on which to assign a value.</param>
+ /// <param name="value">The value to set.</param>
+ internal void SetValueFromRenderer(BindableProperty property, object value)
+ {
+ SetValueCore(property, value);
+ }
+
+ /// <summary>
+ /// Sets the value of the propertyKey.
+ /// </summary>
+ /// <param name="property">The BindablePropertyKey on which to assign a value.</param>
+ /// <param name="value">The value to set.</param>
+ internal void SetValueFromRenderer(BindablePropertyKey property, object value)
+ {
+ SetValueCore(property, value);
+ }
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ /// <param name="name">The nameof the effect</param>
+ /// <returns>true if attached</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool EffectIsAttached(string name)
+ {
+ foreach (var effect in Effects)
+ {
+ if (effect.ResolveId == name)
+ return true;
+ }
+ return false;
+ }
+
+ object INameScope.FindByName(string name)
+ {
+ INameScope namescope = GetNameScope();
+ if (namescope == null)
+ {
+ //throw new InvalidOperationException("this element is not in a namescope");
+ return null;
+ }
+ else
+ {
+ return namescope.FindByName(name);
+ }
+ }
+
+ void INameScope.RegisterName(string name, object scopedElement)
+ {
+ INameScope namescope = GetNameScope();
+ if (namescope == null)
+ throw new InvalidOperationException("this element is not in a namescope");
+ namescope.RegisterName(name, scopedElement);
+ }
+
+ [Obsolete]
+ void INameScope.RegisterName(string name, object scopedElement, IXmlLineInfo xmlLineInfo)
+ {
+ INameScope namescope = GetNameScope();
+ if (namescope == null)
+ throw new InvalidOperationException("this element is not in a namescope");
+ namescope.RegisterName(name, scopedElement, xmlLineInfo);
+ }
+
+ void INameScope.UnregisterName(string name)
+ {
+ INameScope namescope = GetNameScope();
+ if (namescope == null)
+ throw new InvalidOperationException("this element is not in a namescope");
+ namescope.UnregisterName(name);
+ }
+
+ internal event EventHandler<ElementEventArgs> ChildAdded;
+
+ internal event EventHandler<ElementEventArgs> ChildRemoved;
+
+ internal event EventHandler<ElementEventArgs> DescendantAdded;
+
+ internal event EventHandler<ElementEventArgs> DescendantRemoved;
+
+ /// <summary>
+ /// Removes a previously set dynamic resource.
+ /// </summary>
+ /// <param name="property">The BindableProperty from which to remove the DynamicResource.</param>
+ internal new void RemoveDynamicResource(BindableProperty property)
+ {
+ base.RemoveDynamicResource(property);
+ }
+
+ /// <summary>
+ /// Sets the BindableProperty property of this element to be updated via the DynamicResource with the provided key.
+ /// </summary>
+ /// <param name="property">The BindableProperty.</param>
+ /// <param name="key">The key of the DynamicResource</param>
+ internal new void SetDynamicResource(BindableProperty property, string key)
+ {
+ base.SetDynamicResource(property, key);
+ }
+
+ /// <summary>
+ /// Invoked whenever the binding context of the element changes. Implement this method to add class handling for this event.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void OnBindingContextChanged()
+ {
+ var gotBindingContext = false;
+ object bc = null;
+
+ for (var index = 0; index < LogicalChildrenInternal.Count; index++)
+ {
+ Element child = LogicalChildrenInternal[index];
+
+ if (!gotBindingContext)
+ {
+ bc = BindingContext;
+ gotBindingContext = true;
+ }
+
+ SetChildInheritedBindingContext(child, bc);
+ }
+
+ if (_bindableResources != null)
+ foreach (BindableObject item in _bindableResources)
+ {
+ SetInheritedBindingContext(item, BindingContext);
+ }
+
+ base.OnBindingContextChanged();
+ }
+
+ /// <summary>
+ /// Invoked whenever the ChildAdded event needs to be emitted.Implement this method to add class handling for this event.
+ /// </summary>
+ /// <param name="child">The element that was added.</param>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void OnChildAdded(Element child)
+ {
+ child.Parent = this;
+ if (Platform != null)
+ child.Platform = Platform;
+
+ child.ApplyBindings(skipBindingContext: false, fromBindingContextChanged:true);
+
+ ChildAdded?.Invoke(this, new ElementEventArgs(child));
+
+ OnDescendantAdded(child);
+ foreach (Element element in child.Descendants())
+ OnDescendantAdded(element);
+ }
+
+ /// <summary>
+ /// Invoked whenever the ChildRemoved event needs to be emitted.Implement this method to add class handling for this event.
+ /// </summary>
+ /// <param name="child">The element that was removed.</param>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void OnChildRemoved(Element child)
+ {
+ child.Parent = null;
+
+ ChildRemoved?.Invoke(child, new ElementEventArgs(child));
+
+ OnDescendantRemoved(child);
+ foreach (Element element in child.Descendants())
+ OnDescendantRemoved(element);
+ }
+
+ /// <summary>
+ /// Invoked whenever the Parent of an element is set.Implement this method in order to add behavior when the element is added to a parent.
+ /// </summary>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected virtual void OnParentSet()
+ {
+ ParentSet?.Invoke(this, EventArgs.Empty);
+ // ApplyStyleSheetsOnParentSet();
+ }
+
+ /// <summary>
+ /// Method that is called when a bound property is changed.
+ /// </summary>
+ /// <param name="propertyName">The name of the bound property that changed.</param>
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ base.OnPropertyChanged(propertyName);
+
+ if (_effects == null || _effects.Count == 0)
+ return;
+
+ var args = new PropertyChangedEventArgs(propertyName);
+ foreach (Effect effect in _effects)
+ {
+ effect?.SendOnElementPropertyChanged(args);
+ }
+ }
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ /// <returns>the elements</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public IEnumerable<Element> Descendants()
+ {
+ var queue = new Queue<Element>(16);
+ queue.Enqueue(this);
+
+ while (queue.Count > 0)
+ {
+ ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
+ for (var i = 0; i < children.Count; i++)
+ {
+ Element child = children[i];
+ yield return child;
+ queue.Enqueue(child);
+ }
+ }
+ }
+
+ internal virtual void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
+ {
+ // if (e == ResourcesChangedEventArgs.StyleSheets)
+ // // ApplyStyleSheetsOnParentSet();
+ // else
+ // OnParentResourcesChanged(e.Values);
+ }
+
+ internal virtual void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
+ {
+ OnResourcesChanged(values);
+ }
+
+ internal override void OnRemoveDynamicResource(BindableProperty property)
+ {
+ DynamicResources.Remove(property);
+
+ if (DynamicResources.Count == 0)
+ _dynamicResources = null;
+ base.OnRemoveDynamicResource(property);
+ }
+
+ internal virtual void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
+ {
+ OnResourcesChanged(e.Values);
+ }
+
+ internal void OnResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
+ {
+ if (values == null)
+ return;
+ if (_changeHandlers != null)
+ foreach (Action<object, ResourcesChangedEventArgs> handler in _changeHandlers)
+ handler(this, new ResourcesChangedEventArgs(values));
+ if (_dynamicResources == null)
+ return;
+ if (_bindableResources == null)
+ _bindableResources = new List<BindableObject>();
+ foreach (KeyValuePair<string, object> value in values)
+ {
+ List<BindableProperty> changedResources = null;
+ foreach (KeyValuePair<BindableProperty, string> dynR in DynamicResources)
+ {
+ // when the DynamicResource bound to a BindableProperty is
+ // changing then the BindableProperty needs to be refreshed;
+ // The .Value is the name of DynamicResouce to which the BindableProperty is bound.
+ // The .Key is the name of the DynamicResource whose value is changing.
+ if (dynR.Value != value.Key)
+ continue;
+ changedResources = changedResources ?? new List<BindableProperty>();
+ changedResources.Add(dynR.Key);
+ }
+ if (changedResources == null)
+ continue;
+ foreach (BindableProperty changedResource in changedResources)
+ OnResourceChanged(changedResource, value.Value);
+
+ var bindableObject = value.Value as BindableObject;
+ if (bindableObject != null && (bindableObject as Element)?.Parent == null)
+ {
+ if (!_bindableResources.Contains(bindableObject))
+ _bindableResources.Add(bindableObject);
+ SetInheritedBindingContext(bindableObject, BindingContext);
+ }
+ }
+ }
+
+ internal override void OnSetDynamicResource(BindableProperty property, string key)
+ {
+ base.OnSetDynamicResource(property, key);
+ DynamicResources[property] = key;
+ object value;
+ if (this.TryGetResource(key, out value))
+ OnResourceChanged(property, value);
+
+ Application.AddResourceChangedCallback(this, (this as Element).OnResourcesChanged);
+ }
+
+ internal event EventHandler ParentSet;
+
+ internal static void SetFlowDirectionFromParent(Element child)
+ {
+ // IFlowDirectionController controller = child as IFlowDirectionController;
+ // if (controller == null)
+ // return;
+
+ // if (controller.EffectiveFlowDirection.IsImplicit())
+ // {
+ // var parentView = child.Parent as IFlowDirectionController;
+ // if (parentView == null)
+ // return;
+
+ // var flowDirection = parentView.EffectiveFlowDirection.ToFlowDirection();
+
+ // if (flowDirection != controller.EffectiveFlowDirection.ToFlowDirection())
+ // {
+ // controller.EffectiveFlowDirection = flowDirection.ToEffectiveFlowDirection();
+ // }
+ // }
+ }
+
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event EventHandler PlatformSet;
+
+ internal virtual void SetChildInheritedBindingContext(Element child, object context)
+ {
+ SetInheritedBindingContext(child, context);
+ }
+
+ internal IEnumerable<Element> VisibleDescendants()
+ {
+ var queue = new Queue<Element>(16);
+ queue.Enqueue(this);
+
+ while (queue.Count > 0)
+ {
+ ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
+ for (var i = 0; i < children.Count; i++)
+ {
+ var child = children[i] as Element;
+ if (child == null /*|| !child.IsVisible*/)
+ continue;
+ yield return child;
+ queue.Enqueue(child);
+ }
+ }
+ }
+
+ void AttachEffect(Effect effect)
+ {
+ if (_effectControlProvider == null)
+ return;
+ if (effect.IsAttached)
+ throw new InvalidOperationException("Cannot attach Effect to multiple sources");
+
+ Effect effectToRegister = effect;
+ if (effect is RoutingEffect)
+ effectToRegister = ((RoutingEffect)effect).Inner;
+ _effectControlProvider.RegisterEffect(effectToRegister);
+ effectToRegister.Element = this;
+ effect.SendAttached();
+ }
+
+ void EffectsOnClearing(object sender, EventArgs eventArgs)
+ {
+ foreach (Effect effect in _effects)
+ {
+ effect?.ClearEffect();
+ }
+ }
+
+ void EffectsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ foreach (Effect effect in e.NewItems)
+ {
+ AttachEffect(effect);
+ }
+ break;
+ case NotifyCollectionChangedAction.Move:
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ foreach (Effect effect in e.OldItems)
+ {
+ effect.ClearEffect();
+ }
+ break;
+ case NotifyCollectionChangedAction.Replace:
+ foreach (Effect effect in e.NewItems)
+ {
+ AttachEffect(effect);
+ }
+ foreach (Effect effect in e.OldItems)
+ {
+ effect.ClearEffect();
+ }
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ if (e.NewItems != null)
+ {
+ foreach (Effect effect in e.NewItems)
+ {
+ AttachEffect(effect);
+ }
+ }
+ if (e.OldItems != null)
+ {
+ foreach (Effect effect in e.OldItems)
+ {
+ effect.ClearEffect();
+ }
+ }
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ INameScope GetNameScope()
+ {
+ INameScope namescope = NameScope.GetNameScope(this);
+ Element p = RealParent;
+ while (namescope == null && p != null)
+ {
+ namescope = NameScope.GetNameScope(p);
+ p = p.RealParent;
+ }
+ return namescope;
+ }
+
+ void OnDescendantAdded(Element child)
+ {
+ DescendantAdded?.Invoke(this, new ElementEventArgs(child));
+
+ if (RealParent != null)
+ RealParent.OnDescendantAdded(child);
+ }
+
+ void OnDescendantRemoved(Element child)
+ {
+ DescendantRemoved?.Invoke(this, new ElementEventArgs(child));
+
+ if (RealParent != null)
+ RealParent.OnDescendantRemoved(child);
+ }
+
+ void OnResourceChanged(BindableProperty property, object value)
+ {
+ SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearTwoWayBindings);
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ internal class ElementEventArgs : EventArgs
+ {
+ public ElementEventArgs(Element element)
+ {
+ if (element == null)
+ throw new ArgumentNullException("element");
+
+ Element = element;
+ }
+
+ public Element Element { get; private set; }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// Base class for DataTemplate and ControlTemplate classes.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class ElementTemplate : IElement, IDataTemplate
+ {
+ List<Action<object, ResourcesChangedEventArgs>> _changeHandlers;
+ Element _parent;
+ bool _canRecycle; // aka IsDeclarative
+
+ internal ElementTemplate()
+ {
+ }
+
+ internal ElementTemplate(Type type) : this()
+ {
+ if (type == null)
+ throw new ArgumentNullException("type");
+
+ _canRecycle = true;
+
+ LoadTemplate = () => Activator.CreateInstance(type);
+ }
+
+ internal ElementTemplate(Func<object> loadTemplate) : this()
+ {
+ if (loadTemplate == null)
+ throw new ArgumentNullException("loadTemplate");
+
+ LoadTemplate = loadTemplate;
+ }
+
+ Func<object> LoadTemplate { get; set; }
+
+#pragma warning disable 0612
+ Func<object> IDataTemplate.LoadTemplate
+ {
+ get { return LoadTemplate; }
+ set { LoadTemplate = value; }
+ }
+#pragma warning restore 0612
+
+ void IElement.AddResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
+ {
+ _changeHandlers = _changeHandlers ?? new List<Action<object, ResourcesChangedEventArgs>>(1);
+ _changeHandlers.Add(onchanged);
+ }
+
+ internal bool CanRecycle => _canRecycle;
+ Element IElement.Parent
+ {
+ get { return _parent; }
+ set
+ {
+ if (_parent == value)
+ return;
+ if (_parent != null)
+ ((IElement)_parent).RemoveResourcesChangedListener(OnResourcesChanged);
+ _parent = value;
+ if (_parent != null)
+ ((IElement)_parent).AddResourcesChangedListener(OnResourcesChanged);
+ }
+ }
+
+ void IElement.RemoveResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged)
+ {
+ if (_changeHandlers == null)
+ return;
+ _changeHandlers.Remove(onchanged);
+ }
+
+ /// <summary>
+ /// Used by the XAML infrastructure to load data templates and set up the content of the resulting UI.
+ /// </summary>
+ /// <returns></returns>
+ public object CreateContent()
+ {
+ if (LoadTemplate == null)
+ throw new InvalidOperationException("LoadTemplate should not be null");
+ if (this is DataTemplateSelector)
+ throw new InvalidOperationException("Cannot call CreateContent directly on a DataTemplateSelector");
+
+ object item = LoadTemplate();
+ SetupContent(item);
+
+ return item;
+ }
+
+ internal virtual void SetupContent(object item)
+ {
+ }
+
+ void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
+ {
+ if (_changeHandlers == null)
+ return;
+ foreach (Action<object, ResourcesChangedEventArgs> handler in _changeHandlers)
+ handler(this, e);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class EnumerableExtensions
+ {
+ public static IEnumerable<T> GetGesturesFor<T>(this IEnumerable<IGestureRecognizer> gestures, Func<T, bool> predicate = null) where T : GestureRecognizer
+ {
+ if (gestures == null)
+ yield break;
+
+ if (predicate == null)
+ predicate = x => true;
+
+ foreach (IGestureRecognizer item in gestures)
+ {
+ var gesture = item as T;
+ if (gesture != null && predicate(gesture))
+ {
+ yield return gesture;
+ }
+ }
+ }
+
+ internal static IEnumerable<T> Append<T>(this IEnumerable<T> enumerable, T item)
+ {
+ foreach (T x in enumerable)
+ yield return x;
+
+ yield return item;
+ }
+
+ public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
+ {
+ foreach (T item in enumeration)
+ {
+ action(item);
+ }
+ }
+
+ public static int IndexOf<T>(this IEnumerable<T> enumerable, T item)
+ {
+ if (enumerable == null)
+ throw new ArgumentNullException("enumerable");
+
+ var i = 0;
+ foreach (T element in enumerable)
+ {
+ if (Equals(element, item))
+ return i;
+
+ i++;
+ }
+
+ return -1;
+ }
+
+ public static int IndexOf<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
+ {
+ var i = 0;
+ foreach (T element in enumerable)
+ {
+ if (predicate(element))
+ return i;
+
+ i++;
+ }
+
+ return -1;
+ }
+
+ public static IEnumerable<T> Prepend<T>(this IEnumerable<T> enumerable, T item)
+ {
+ yield return item;
+
+ foreach (T x in enumerable)
+ yield return x;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ internal class ExportEffectAttribute : Attribute
+ {
+ public ExportEffectAttribute(Type effectType, string uniqueName)
+ {
+ if (uniqueName.Contains("."))
+ throw new ArgumentException("uniqueName must not contain a .");
+ Type = effectType;
+ Id = uniqueName;
+ }
+
+ internal string Id { get; private set; }
+
+ internal Type Type { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [TypeConverter(typeof(FlowDirectionConverter))]
+ internal enum FlowDirection
+ {
+ MatchParent = 0,
+ LeftToRight = 1,
+ RightToLeft = 2,
+ }
+
+ [Xaml.TypeConversion(typeof(FlowDirection))]
+ internal 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)));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Binding
+{
+ internal class GestureRecognizer : Element, IGestureRecognizer
+ {
+ internal GestureRecognizer()
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ internal abstract class HandlerAttribute : Attribute
+ {
+ protected HandlerAttribute(Type handler, Type target)
+ {
+ TargetType = target;
+ HandlerType = handler;
+ }
+
+ internal Type HandlerType { get; private set; }
+
+ internal Type TargetType { get; private set; }
+
+ public virtual bool ShouldRegister()
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Binding
+{
+ internal interface IControlTemplated
+ {
+ // ControlTemplate ControlTemplate { get; set; }
+
+ IList<Element> InternalChildren { get; }
+
+ void OnControlTemplateChanged(ControlTemplate oldValue, ControlTemplate newValue);
+ }
+}
--- /dev/null
+using System.ComponentModel;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IDynamicResourceHandler
+ {
+ void SetDynamicResource(BindableProperty property, string key);
+ }
+}
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// When implemented in a renderer, registers a platform-specific effect on an element.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IEffectControlProvider
+ {
+ /// <summary>
+ /// Registers the effect with the element by establishing the parent-child relations needed for rendering on the specific platform.
+ /// </summary>
+ /// <param name="effect">The effect to register.</param>
+ void RegisterEffect(Effect effect);
+ }
+}
--- /dev/null
+using System;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ internal interface IElement
+ {
+ Element Parent { get; set; }
+
+ //Use these 2 instead of an event to avoid cloning way too much multicastdelegates on mono
+ void AddResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged);
+ void RemoveResourcesChangedListener(Action<object, ResourcesChangedEventArgs> onchanged);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ internal interface IElementController
+ {
+ // IEffectControlProvider EffectControlProvider { get; set; }
+
+ // bool EffectIsAttached(string name);
+
+ // void SetValueFromRenderer(BindableProperty property, object value);
+ // void SetValueFromRenderer(BindablePropertyKey propertyKey, object value);
+ // ReadOnlyCollection<Element> LogicalChildren { get; }
+ // IPlatform Platform { get; set; }
+ // Element RealParent { get; }
+ // IEnumerable<Element> Descendants();
+ // event EventHandler PlatformSet;
+ }
+}
--- /dev/null
+using System;
+using System.Globalization;
+
+namespace Tizen.NUI.Binding
+{
+ internal interface IExtendedTypeConverter
+ {
+ [Obsolete("IExtendedTypeConverter.ConvertFrom is obsolete as of version 2.2.0. Please use ConvertFromInvariantString (string, IServiceProvider) instead.")]
+ object ConvertFrom(CultureInfo culture, object value, IServiceProvider serviceProvider);
+
+ object ConvertFromInvariantString(string value, IServiceProvider serviceProvider);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ internal interface IGestureRecognizer : INotifyPropertyChanged
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Binding
+{
+
+ internal interface INativeBindingService
+ {
+ bool TrySetBinding(object target, string propertyName, BindingBase binding);
+ bool TrySetBinding(object target, BindableProperty property, BindingBase binding);
+ bool TrySetValue(object target, BindableProperty property, object value);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IPlatform
+ {
+ /// <summary>
+ /// Returns the native size.
+ /// </summary>
+ /// <param name="view">The view</param>
+ /// <param name="widthConstraint">The width constraint.</param>
+ /// <param name="heightConstraint">The height constraint.</param>
+ /// <returns>The native size.</returns>
+ //SizeRequest GetNativeSize(BaseHandle view, double widthConstraint, double heightConstraint);
+ }
+}
--- /dev/null
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IPlatformServices
+ {
+ bool IsInvokeRequired { get; }
+
+ void BeginInvokeOnMainThread(Action action);
+
+ Ticker CreateTicker();
+
+ Assembly[] GetAssemblies();
+
+ string GetMD5Hash(string input);
+
+ // double GetNamedSize(NamedSize size, Type targetElementType, bool useOldSizes);
+
+ Task<Stream> GetStreamAsync(Uri uri, CancellationToken cancellationToken);
+
+ // IIsolatedStorageFile GetUserStoreForApplication();
+
+ // void OpenUriAction(Uri uri);
+
+ void StartTimer(TimeSpan interval, Func<bool> callback);
+
+ string RuntimePlatform { get; }
+
+ void QuitApplication();
+ }
+}
--- /dev/null
+namespace Tizen.NUI.Binding
+{
+ internal interface IRegisterable
+ {
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IResourceDictionary : IEnumerable<KeyValuePair<string, object>>
+ {
+ bool TryGetValue(string key, out object value);
+
+ event EventHandler<ResourcesChangedEventArgs> ValuesChanged;
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Binding
+{
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IResourcesProvider
+ {
+ bool IsResourcesCreated { get; }
+ ResourceDictionary Resources { get; set; }
+ }
+}
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface ISystemResourcesProvider
+ {
+ IResourceDictionary GetSystemResources();
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Globalization;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IValueConverter
+ {
+ object Convert(object value, Type targetType, object parameter, CultureInfo culture);
+ object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Tizen.NUI.Binding
+{
+ internal class AttachedCollection<T> : ObservableCollection<T>, ICollection<T>, IAttachedObject where T : BindableObject, IAttachedObject
+ {
+ readonly List<WeakReference> _associatedObjects = new List<WeakReference>();
+
+ public AttachedCollection()
+ {
+ }
+
+ public AttachedCollection(IEnumerable<T> collection) : base(collection)
+ {
+ }
+
+ public AttachedCollection(IList<T> list) : base(list)
+ {
+ }
+
+ public void AttachTo(BindableObject bindable)
+ {
+ if (bindable == null)
+ throw new ArgumentNullException("bindable");
+ OnAttachedTo(bindable);
+ }
+
+ public void DetachFrom(BindableObject bindable)
+ {
+ OnDetachingFrom(bindable);
+ }
+
+ protected override void ClearItems()
+ {
+ foreach (WeakReference weakbindable in _associatedObjects)
+ {
+ foreach (T item in this)
+ {
+ var bindable = weakbindable.Target as BindableObject;
+ if (bindable == null)
+ continue;
+ item.DetachFrom(bindable);
+ }
+ }
+ base.ClearItems();
+ }
+
+ protected override void InsertItem(int index, T item)
+ {
+ base.InsertItem(index, item);
+ foreach (WeakReference weakbindable in _associatedObjects)
+ {
+ var bindable = weakbindable.Target as BindableObject;
+ if (bindable == null)
+ continue;
+ item.AttachTo(bindable);
+ }
+ }
+
+ protected virtual void OnAttachedTo(BindableObject bindable)
+ {
+ lock (_associatedObjects)
+ {
+ _associatedObjects.Add(new WeakReference(bindable));
+ }
+ foreach (T item in this)
+ item.AttachTo(bindable);
+ }
+
+ protected virtual void OnDetachingFrom(BindableObject bindable)
+ {
+ foreach (T item in this)
+ item.DetachFrom(bindable);
+ lock (_associatedObjects)
+ {
+ for (var i = 0; i < _associatedObjects.Count; i++)
+ {
+ object target = _associatedObjects[i].Target;
+
+ if (target == null || target == bindable)
+ {
+ _associatedObjects.RemoveAt(i);
+ i--;
+ }
+ }
+ }
+ }
+
+ protected override void RemoveItem(int index)
+ {
+ T item = this[index];
+ foreach (WeakReference weakbindable in _associatedObjects)
+ {
+ var bindable = weakbindable.Target as BindableObject;
+ if (bindable == null)
+ continue;
+ item.DetachFrom(bindable);
+ }
+
+ base.RemoveItem(index);
+ }
+
+ protected override void SetItem(int index, T item)
+ {
+ T old = this[index];
+ foreach (WeakReference weakbindable in _associatedObjects)
+ {
+ var bindable = weakbindable.Target as BindableObject;
+ if (bindable == null)
+ continue;
+ old.DetachFrom(bindable);
+ }
+
+ base.SetItem(index, item);
+
+ foreach (WeakReference weakbindable in _associatedObjects)
+ {
+ var bindable = weakbindable.Target as BindableObject;
+ if (bindable == null)
+ continue;
+ item.AttachTo(bindable);
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Reflection;
+
+namespace Tizen.NUI.Binding
+{
+ internal abstract class Behavior : BindableObject, IAttachedObject
+ {
+ internal Behavior(Type associatedType)
+ {
+ if (associatedType == null)
+ throw new ArgumentNullException("associatedType");
+ AssociatedType = associatedType;
+ }
+
+ protected Type AssociatedType { get; }
+
+ void IAttachedObject.AttachTo(BindableObject bindable)
+ {
+ if (bindable == null)
+ throw new ArgumentNullException("bindable");
+ if (!AssociatedType.IsInstanceOfType(bindable))
+ throw new InvalidOperationException("bindable not an instance of AssociatedType");
+ OnAttachedTo(bindable);
+ }
+
+ void IAttachedObject.DetachFrom(BindableObject bindable)
+ {
+ OnDetachingFrom(bindable);
+ }
+
+ protected virtual void OnAttachedTo(BindableObject bindable)
+ {
+ }
+
+ protected virtual void OnDetachingFrom(BindableObject bindable)
+ {
+ }
+ }
+
+ internal abstract class Behavior<T> : Behavior where T : BindableObject
+ {
+ protected Behavior() : base(typeof(T))
+ {
+ }
+
+ protected override void OnAttachedTo(BindableObject bindable)
+ {
+ base.OnAttachedTo(bindable);
+ OnAttachedTo((T)bindable);
+ }
+
+ protected virtual void OnAttachedTo(T bindable)
+ {
+ }
+
+ protected override void OnDetachingFrom(BindableObject bindable)
+ {
+ OnDetachingFrom((T)bindable);
+ base.OnDetachingFrom(bindable);
+ }
+
+ protected virtual void OnDetachingFrom(T bindable)
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ [ProvideCompiled("Tizen.NUI.Xaml.Core.XamlC.PassthroughValueProvider")]
+ [AcceptEmptyServiceProvider]
+ internal sealed class BindingCondition : Condition, IValueProvider
+ {
+ readonly BindableProperty _boundProperty;
+
+ BindingBase _binding;
+ object _triggerValue;
+
+ public BindingCondition()
+ {
+ _boundProperty = BindableProperty.CreateAttached("Bound", typeof(object), typeof(BindingCondition), null, propertyChanged: OnBoundPropertyChanged);
+ }
+
+ public BindingBase Binding
+ {
+ get { return _binding; }
+ set
+ {
+ if (_binding == value)
+ return;
+ if (IsSealed)
+ throw new InvalidOperationException("Can not change Binding once the Condition has been applied.");
+ _binding = value;
+ }
+ }
+
+ public object Value
+ {
+ get { return _triggerValue; }
+ set
+ {
+ if (_triggerValue == value)
+ return;
+ if (IsSealed)
+ throw new InvalidOperationException("Can not change Value once the Condition has been applied.");
+ _triggerValue = value;
+ }
+ }
+
+ object IValueProvider.ProvideValue(IServiceProvider serviceProvider)
+ {
+ //This is no longer required
+ return this;
+ }
+
+ internal override bool GetState(BindableObject bindable)
+ {
+ object newValue = bindable.GetValue(_boundProperty);
+ return EqualsToValue(newValue);
+ }
+
+ internal override void SetUp(BindableObject bindable)
+ {
+ if (Binding != null)
+ bindable.SetBinding(_boundProperty, Binding.Clone());
+ }
+
+ internal override void TearDown(BindableObject bindable)
+ {
+ bindable.RemoveBinding(_boundProperty);
+ bindable.ClearValue(_boundProperty);
+ }
+
+ static IValueConverterProvider s_valueConverter = DependencyService.Get<IValueConverterProvider>();
+
+ bool EqualsToValue(object other)
+ {
+ if ((other == Value) || (other != null && other.Equals(Value)))
+ return true;
+
+ object converted = null;
+ if (s_valueConverter != null)
+ converted = s_valueConverter.Convert(Value, other != null ? other.GetType() : typeof(object), null, null);
+ else
+ return false;
+
+ return (other == converted) || (other != null && other.Equals(converted));
+ }
+
+ void OnBoundPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ bool oldState = EqualsToValue(oldValue);
+ bool newState = EqualsToValue(newValue);
+
+ if (newState == oldState)
+ return;
+
+ if (ConditionChanged != null)
+ ConditionChanged(bindable, oldState, newState);
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ internal abstract class Condition
+ {
+ Action<BindableObject, bool, bool> _conditionChanged;
+
+ bool _isSealed;
+
+ internal Condition()
+ {
+ }
+
+ internal Action<BindableObject, bool, bool> ConditionChanged
+ {
+ get { return _conditionChanged; }
+ set
+ {
+ if (_conditionChanged == value)
+ return;
+ if (_conditionChanged != null)
+ throw new InvalidOperationException("The same condition instance can not be reused");
+ _conditionChanged = value;
+ }
+ }
+
+ internal bool IsSealed
+ {
+ get { return _isSealed; }
+ set
+ {
+ if (_isSealed == value)
+ return;
+ if (!value)
+ throw new InvalidOperationException("What is sealed can not be unsealed.");
+ _isSealed = value;
+ OnSealed();
+ }
+ }
+
+ internal abstract bool GetState(BindableObject bindable);
+
+ internal virtual void OnSealed()
+ {
+ }
+
+ internal abstract void SetUp(BindableObject bindable);
+ internal abstract void TearDown(BindableObject bindable);
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Binding
+{
+ internal interface IAttachedObject
+ {
+ void AttachTo(BindableObject bindable);
+ void DetachFrom(BindableObject bindable);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Binding
+{
+ internal sealed class MultiCondition : Condition
+ {
+ readonly BindableProperty _aggregatedStateProperty;
+
+ public MultiCondition()
+ {
+ _aggregatedStateProperty = BindableProperty.CreateAttached("AggregatedState", typeof(bool), typeof(MultiCondition), false, propertyChanged: OnAggregatedStatePropertyChanged);
+ Conditions = new TriggerBase.SealedList<Condition>();
+ }
+
+ public IList<Condition> Conditions { get; }
+
+ internal override bool GetState(BindableObject bindable)
+ {
+ return (bool)bindable.GetValue(_aggregatedStateProperty);
+ }
+
+ internal override void OnSealed()
+ {
+ ((TriggerBase.SealedList<Condition>)Conditions).IsReadOnly = true;
+ foreach (Condition condition in Conditions)
+ condition.ConditionChanged = OnConditionChanged;
+ }
+
+ internal override void SetUp(BindableObject bindable)
+ {
+ foreach (Condition condition in Conditions)
+ condition.SetUp(bindable);
+ }
+
+ internal override void TearDown(BindableObject bindable)
+ {
+ foreach (Condition condition in Conditions)
+ condition.TearDown(bindable);
+ }
+
+ void OnAggregatedStatePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ if ((bool)oldValue == (bool)newValue)
+ return;
+
+ ConditionChanged?.Invoke(bindable, (bool)oldValue, (bool)newValue);
+ }
+
+ void OnConditionChanged(BindableObject bindable, bool oldValue, bool newValue)
+ {
+ var oldState = (bool)bindable.GetValue(_aggregatedStateProperty);
+ var newState = true;
+ foreach (Condition condition in Conditions)
+ {
+ if (!condition.GetState(bindable))
+ {
+ newState = false;
+ break;
+ }
+ }
+ if (newState != oldState)
+ bindable.SetValue(_aggregatedStateProperty, newState);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.ComponentModel;
+using System.Reflection;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml
+{
+ [ProvideCompiled("Tizen.NUI.Xaml.Core.XamlC.PassthroughValueProvider")]
+ [AcceptEmptyServiceProvider]
+ internal sealed class XamlPropertyCondition : Condition, IValueProvider
+ {
+ readonly BindableProperty _stateProperty;
+
+ BindableProperty _property;
+ object _triggerValue;
+
+ public XamlPropertyCondition()
+ {
+ _stateProperty = BindableProperty.CreateAttached("State", typeof(bool), typeof(XamlPropertyCondition), false, propertyChanged: OnStatePropertyChanged);
+ }
+
+ public BindableProperty Property
+ {
+ get { return _property; }
+ set
+ {
+ if (_property == value)
+ return;
+ if (IsSealed)
+ throw new InvalidOperationException("Can not change Property once the Trigger has been applied.");
+ _property = value;
+
+ //convert the value
+ if (_property != null && s_valueConverter != null)
+ {
+ Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
+ Value = s_valueConverter.Convert(Value, Property.ReturnType, minforetriever, null);
+ }
+ }
+ }
+
+ public object Value
+ {
+ get { return _triggerValue; }
+ set
+ {
+ if (_triggerValue == value)
+ return;
+ if (IsSealed)
+ throw new InvalidOperationException("Can not change Value once the Trigger has been applied.");
+
+ //convert the value
+ if (_property != null && s_valueConverter != null)
+ {
+ Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
+ value = s_valueConverter.Convert(value, Property.ReturnType, minforetriever, null);
+ }
+ _triggerValue = value;
+ }
+ }
+
+ object IValueProvider.ProvideValue(IServiceProvider serviceProvider)
+ {
+ //This is no longer required
+ return this;
+ }
+
+ internal override bool GetState(BindableObject bindable)
+ {
+ return (bool)bindable.GetValue(_stateProperty);
+ }
+
+ static IValueConverterProvider s_valueConverter = DependencyService.Get<IValueConverterProvider>();
+
+ internal override void SetUp(BindableObject bindable)
+ {
+ object newvalue = bindable.GetValue(Property);
+ bool newState = (newvalue == Value) || (newvalue != null && newvalue.Equals(Value));
+ bindable.SetValue(_stateProperty, newState);
+ bindable.PropertyChanged += OnAttachedObjectPropertyChanged;
+ }
+
+ internal override void TearDown(BindableObject bindable)
+ {
+ bindable.ClearValue(_stateProperty);
+ bindable.PropertyChanged -= OnAttachedObjectPropertyChanged;
+ }
+
+ void OnAttachedObjectPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ var bindable = (BindableObject)sender;
+ var oldState = (bool)bindable.GetValue(_stateProperty);
+
+ if (Property == null)
+ return;
+ if (e.PropertyName != Property.PropertyName)
+ return;
+ object newvalue = bindable.GetValue(Property);
+ bool newstate = (newvalue == Value) || (newvalue != null && newvalue.Equals(Value));
+ if (oldState != newstate)
+ bindable.SetValue(_stateProperty, newstate);
+ }
+
+ void OnStatePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ if ((bool)oldValue == (bool)newValue)
+ return;
+
+ ConditionChanged?.Invoke(bindable, (bool)oldValue, (bool)newValue);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ internal abstract class TriggerAction
+ {
+ internal TriggerAction(Type associatedType)
+ {
+ if (associatedType == null)
+ throw new ArgumentNullException("associatedType");
+ AssociatedType = associatedType;
+ }
+
+ protected Type AssociatedType { get; private set; }
+
+ protected abstract void Invoke(object sender);
+
+ internal virtual void DoInvoke(object sender)
+ {
+ Invoke(sender);
+ }
+ }
+
+ internal abstract class TriggerAction<T> : TriggerAction where T : BindableObject
+ {
+ protected TriggerAction() : base(typeof(T))
+ {
+ }
+
+ protected override void Invoke(object sender)
+ {
+ Invoke((T)sender);
+ }
+
+ protected abstract void Invoke(T sender);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Reflection;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Binding
+{
+ internal abstract class TriggerBase : BindableObject, IAttachedObject
+ {
+ bool _isSealed;
+
+ internal TriggerBase(Type targetType)
+ {
+ if (targetType == null)
+ throw new ArgumentNullException("targetType");
+ TargetType = targetType;
+
+ EnterActions = new SealedList<TriggerAction>();
+ ExitActions = new SealedList<TriggerAction>();
+ }
+
+ internal TriggerBase(Condition condition, Type targetType) : this(targetType)
+ {
+ Setters = new SealedList<Setter>();
+ Condition = condition;
+ Condition.ConditionChanged = OnConditionChanged;
+ }
+
+ public IList<TriggerAction> EnterActions { get; }
+
+ public IList<TriggerAction> ExitActions { get; }
+
+ public bool IsSealed
+ {
+ get { return _isSealed; }
+ private set
+ {
+ if (_isSealed == value)
+ return;
+ if (!value)
+ throw new InvalidOperationException("What is sealed can not be unsealed.");
+ _isSealed = value;
+ OnSeal();
+ }
+ }
+
+ public Type TargetType { get; }
+
+ internal Condition Condition { get; }
+
+ //Setters and Condition are used by Trigger, DataTrigger and MultiTrigger
+ internal IList<Setter> Setters { get; }
+
+ void IAttachedObject.AttachTo(BindableObject bindable)
+ {
+ IsSealed = true;
+
+ if (bindable == null)
+ throw new ArgumentNullException("bindable");
+ if (!TargetType.IsInstanceOfType(bindable))
+ throw new InvalidOperationException("bindable not an instance of AssociatedType");
+ OnAttachedTo(bindable);
+ }
+
+ void IAttachedObject.DetachFrom(BindableObject bindable)
+ {
+ if (bindable == null)
+ throw new ArgumentNullException("bindable");
+ OnDetachingFrom(bindable);
+ }
+
+ internal virtual void OnAttachedTo(BindableObject bindable)
+ {
+ if (Condition != null)
+ Condition.SetUp(bindable);
+ }
+
+ internal virtual void OnDetachingFrom(BindableObject bindable)
+ {
+ if (Condition != null)
+ Condition.TearDown(bindable);
+ }
+
+ internal virtual void OnSeal()
+ {
+ ((SealedList<TriggerAction>)EnterActions).IsReadOnly = true;
+ ((SealedList<TriggerAction>)ExitActions).IsReadOnly = true;
+ if (Setters != null)
+ ((SealedList<Setter>)Setters).IsReadOnly = true;
+ if (Condition != null)
+ Condition.IsSealed = true;
+ }
+
+ void OnConditionChanged(BindableObject bindable, bool oldValue, bool newValue)
+ {
+ if (newValue)
+ {
+ foreach (TriggerAction action in EnterActions)
+ action.DoInvoke(bindable);
+ foreach (Setter setter in Setters)
+ setter.Apply(bindable);
+ }
+ else
+ {
+ foreach (Setter setter in Setters)
+ setter.UnApply(bindable);
+ foreach (TriggerAction action in ExitActions)
+ action.DoInvoke(bindable);
+ }
+ }
+
+ internal class SealedList<T> : IList<T>
+ {
+ readonly IList<T> _actual;
+
+ bool _isReadOnly;
+
+ public SealedList()
+ {
+ _actual = new List<T>();
+ }
+
+ public void Add(T item)
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException("This list is ReadOnly");
+ _actual.Add(item);
+ }
+
+ public void Clear()
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException("This list is ReadOnly");
+ _actual.Clear();
+ }
+
+ public bool Contains(T item)
+ {
+ return _actual.Contains(item);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ _actual.CopyTo(array, arrayIndex);
+ }
+
+ public int Count
+ {
+ get { return _actual.Count; }
+ }
+
+ public bool IsReadOnly
+ {
+ get { return _isReadOnly; }
+ set
+ {
+ if (_isReadOnly == value)
+ return;
+ if (!value)
+ throw new InvalidOperationException("Can't change this back to non readonly");
+ _isReadOnly = value;
+ }
+ }
+
+ public bool Remove(T item)
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException("This list is ReadOnly");
+ return _actual.Remove(item);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return ((IEnumerable)_actual).GetEnumerator();
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ return _actual.GetEnumerator();
+ }
+
+ public int IndexOf(T item)
+ {
+ return _actual.IndexOf(item);
+ }
+
+ public void Insert(int index, T item)
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException("This list is ReadOnly");
+ _actual.Insert(index, item);
+ }
+
+ public T this[int index]
+ {
+ get { return _actual[index]; }
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException("This list is ReadOnly");
+ _actual[index] = value;
+ }
+ }
+
+ public void RemoveAt(int index)
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException("This list is ReadOnly");
+ _actual.RemoveAt(index);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.ComponentModel;
+using System.Reflection;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ [ProvideCompiled("Tizen.NUI.Core.XamlC.PassthroughValueProvider")]
+ [AcceptEmptyServiceProvider]
+ internal sealed class XamlPropertyCondition : Condition, IValueProvider
+ {
+ readonly BindableProperty _stateProperty;
+
+ BindableProperty _property;
+ object _triggerValue;
+
+ public XamlPropertyCondition()
+ {
+ _stateProperty = BindableProperty.CreateAttached("State", typeof(bool), typeof(XamlPropertyCondition), false, propertyChanged: OnStatePropertyChanged);
+ }
+
+ public BindableProperty Property
+ {
+ get { return _property; }
+ set
+ {
+ if (_property == value)
+ return;
+ if (IsSealed)
+ throw new InvalidOperationException("Can not change Property once the Trigger has been applied.");
+ _property = value;
+
+ //convert the value
+ if (_property != null && s_valueConverter != null)
+ {
+ Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
+ Value = s_valueConverter.Convert(Value, Property.ReturnType, minforetriever, null);
+ }
+ }
+ }
+
+ public object Value
+ {
+ get { return _triggerValue; }
+ set
+ {
+ if (_triggerValue == value)
+ return;
+ if (IsSealed)
+ throw new InvalidOperationException("Can not change Value once the Trigger has been applied.");
+
+ //convert the value
+ if (_property != null && s_valueConverter != null)
+ {
+ Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
+ value = s_valueConverter.Convert(value, Property.ReturnType, minforetriever, null);
+ }
+ _triggerValue = value;
+ }
+ }
+
+ object IValueProvider.ProvideValue(IServiceProvider serviceProvider)
+ {
+ //This is no longer required
+ return this;
+ }
+
+ internal override bool GetState(BindableObject bindable)
+ {
+ return (bool)bindable.GetValue(_stateProperty);
+ }
+
+ static IValueConverterProvider s_valueConverter = DependencyService.Get<IValueConverterProvider>();
+
+ internal override void SetUp(BindableObject bindable)
+ {
+ object newvalue = bindable.GetValue(Property);
+ bool newState = (newvalue == Value) || (newvalue != null && newvalue.Equals(Value));
+ bindable.SetValue(_stateProperty, newState);
+ bindable.PropertyChanged += OnAttachedObjectPropertyChanged;
+ }
+
+ internal override void TearDown(BindableObject bindable)
+ {
+ bindable.ClearValue(_stateProperty);
+ bindable.PropertyChanged -= OnAttachedObjectPropertyChanged;
+ }
+
+ void OnAttachedObjectPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ var bindable = (BindableObject)sender;
+ var oldState = (bool)bindable.GetValue(_stateProperty);
+
+ if (Property == null)
+ return;
+ if (e.PropertyName != Property.PropertyName)
+ return;
+ object newvalue = bindable.GetValue(Property);
+ bool newstate = (newvalue == Value) || (newvalue != null && newvalue.Equals(Value));
+ if (oldState != newstate)
+ bindable.SetValue(_stateProperty, newstate);
+ }
+
+ void OnStatePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ if ((bool)oldValue == (bool)newValue)
+ return;
+
+ ConditionChanged?.Invoke(bindable, (bool)oldValue, (bool)newValue);
+ }
+ }
+}
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class DynamicResource
+ {
+ public DynamicResource(string key)
+ {
+ Key = key;
+ }
+
+ public string Key { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IDataTemplate
+ {
+ Func<object> LoadTemplate { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.ComponentModel;
+using System.Xml;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface INameScope
+ {
+ object FindByName(string name);
+ void RegisterName(string name, object scopedElement);
+ void UnregisterName(string name);
+ [Obsolete]void RegisterName(string name, object scopedElement, IXmlLineInfo xmlLineInfo);
+ }
+}
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ interface INameScopeProvider
+ {
+ INameScope NameScope { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Xml;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class NameScope : INameScope
+ {
+ public static readonly BindableProperty NameScopeProperty = BindableProperty.CreateAttached("NameScope", typeof(INameScope), typeof(NameScope), default(INameScope));
+
+ readonly Dictionary<string, object> _names = new Dictionary<string, object>();
+
+ object INameScope.FindByName(string name)
+ {
+ if (_names.ContainsKey(name))
+ return _names[name];
+ return null;
+ }
+
+ void INameScope.RegisterName(string name, object scopedElement)
+ {
+ if (_names.ContainsKey(name))
+ throw new ArgumentException("An element with the same key already exists in NameScope", "name");
+
+ _names[name] = scopedElement;
+ }
+
+ [Obsolete]
+ void INameScope.RegisterName(string name, object scopedElement, IXmlLineInfo xmlLineInfo)
+ {
+ try
+ {
+ ((INameScope)this).RegisterName(name, scopedElement);
+ }
+ catch (ArgumentException)
+ {
+ throw new XamlParseException(string.Format("An element with the name \"{0}\" already exists in this NameScope", name), xmlLineInfo);
+ }
+ }
+
+ void INameScope.UnregisterName(string name)
+ {
+ _names.Remove(name);
+ }
+
+ public static INameScope GetNameScope(BindableObject bindable)
+ {
+ return (INameScope)bindable.GetValue(NameScopeProperty);
+ }
+
+ public static void SetNameScope(BindableObject bindable, INameScope value)
+ {
+ bindable.SetValue(NameScopeProperty, value);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ [AttributeUsage(AttributeTargets.All)]
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class PreserveAttribute : Attribute
+ {
+ public bool AllMembers;
+ public bool Conditional;
+
+ public PreserveAttribute(bool allMembers, bool conditional)
+ {
+ AllMembers = allMembers;
+ Conditional = conditional;
+ }
+
+ public PreserveAttribute()
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Reflection;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ internal static class ResourceLoader
+ {
+ static Func<AssemblyName, string, string> resourceProvider = (asmName, path) =>
+ {
+ return null;
+ //string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+ //path = resource + path;
+
+ //string ret = File.ReadAllText(path);
+ //return ret;
+ };
+
+ //takes a resource path, returns string content
+ public static Func<AssemblyName, string, string> ResourceProvider123
+ {
+ get => resourceProvider;
+ internal set
+ {
+ DesignMode.IsDesignModeEnabled = true;
+ resourceProvider = value;
+ }
+ }
+
+ //takes a resource path, returns string content
+ public static Func<AssemblyName, string, string> ResourceProvider {
+ get => resourceProvider;
+ internal set {
+ DesignMode.IsDesignModeEnabled = true;
+ resourceProvider = value;
+ }
+ }
+
+ internal static Action<Exception> ExceptionHandler { get; set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal abstract class Ticker
+ {
+ static Ticker s_ticker;
+ readonly Stopwatch _stopwatch;
+ readonly List<Tuple<int, Func<long, bool>>> _timeouts;
+
+ int _count;
+ bool _enabled;
+
+ protected Ticker()
+ {
+ _count = 0;
+ _timeouts = new List<Tuple<int, Func<long, bool>>>();
+
+ _stopwatch = new Stopwatch();
+ }
+
+ public static void SetDefault(Ticker ticker) => Default = ticker;
+ public static Ticker Default
+ {
+ internal set { s_ticker = value; }
+ get { return s_ticker ?? (s_ticker = Device.PlatformServices.CreateTicker()); }
+ }
+
+ public virtual int Insert(Func<long, bool> timeout)
+ {
+ _count++;
+ _timeouts.Add(new Tuple<int, Func<long, bool>>(_count, timeout));
+
+ if (!_enabled)
+ {
+ _enabled = true;
+ Enable();
+ }
+
+ return _count;
+ }
+
+ public virtual void Remove(int handle)
+ {
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ _timeouts.RemoveAll(t => t.Item1 == handle);
+
+ if (!_timeouts.Any())
+ {
+ _enabled = false;
+ Disable();
+ }
+ });
+ }
+
+ protected abstract void DisableTimer();
+
+ protected abstract void EnableTimer();
+
+ protected void SendSignals(int timestep = -1)
+ {
+ long step = timestep >= 0 ? timestep : _stopwatch.ElapsedMilliseconds;
+ _stopwatch.Reset();
+ _stopwatch.Start();
+
+ var localCopy = new List<Tuple<int, Func<long, bool>>>(_timeouts);
+ foreach (Tuple<int, Func<long, bool>> timeout in localCopy)
+ {
+ bool remove = !timeout.Item2(step);
+ if (remove)
+ _timeouts.RemoveAll(t => t.Item1 == timeout.Item1);
+ }
+
+ if (!_timeouts.Any())
+ {
+ _enabled = false;
+ Disable();
+ }
+ }
+
+ void Disable()
+ {
+ _stopwatch.Reset();
+ DisableTimer();
+ }
+
+ void Enable()
+ {
+ _stopwatch.Start();
+ EnableTimer();
+ }
+ }
+}
--- /dev/null
+#define DO_NOT_CHECK_FOR_BINDING_REUSE
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Collections.Generic;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Binding.Internals
+{
+ //FIXME: need a better name for this, and share with Binding, so we can share more unittests
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal abstract class TypedBindingBase : BindingBase
+ {
+ IValueConverter _converter;
+ object _converterParameter;
+ object _source;
+ string _updateSourceEventName;
+
+ public IValueConverter Converter {
+ get { return _converter; }
+ set {
+ ThrowIfApplied();
+ _converter = value;
+ }
+ }
+
+ public object ConverterParameter {
+ get { return _converterParameter; }
+ set {
+ ThrowIfApplied();
+ _converterParameter = value;
+ }
+ }
+
+ public object Source {
+ get { return _source; }
+ set {
+ ThrowIfApplied();
+ _source = value;
+ }
+ }
+
+ internal string UpdateSourceEventName {
+ get { return _updateSourceEventName; }
+ set {
+ ThrowIfApplied();
+ _updateSourceEventName = value;
+ }
+ }
+
+ internal TypedBindingBase()
+ {
+ }
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal sealed class TypedBinding<TSource, TProperty> : TypedBindingBase
+ {
+ readonly Func<TSource, TProperty> _getter;
+ readonly Action<TSource, TProperty> _setter;
+ readonly PropertyChangedProxy [] _handlers;
+
+ public TypedBinding(Func<TSource, TProperty> getter, Action<TSource, TProperty> setter, Tuple<Func<TSource, object>, string> [] handlers)
+ {
+ if (getter == null)
+ throw new ArgumentNullException(nameof(getter));
+
+ _getter = getter;
+ _setter = setter;
+
+ if (handlers == null)
+ return;
+
+ _handlers = new PropertyChangedProxy [handlers.Length];
+ for (var i = 0; i < handlers.Length; i++)
+ _handlers [i] = new PropertyChangedProxy(handlers [i].Item1, handlers [i].Item2, this);
+ }
+
+ readonly WeakReference<object> _weakSource = new WeakReference<object>(null);
+ readonly WeakReference<BindableObject> _weakTarget = new WeakReference<BindableObject>(null);
+ BindableProperty _targetProperty;
+
+ // Applies the binding to a previously set source and target.
+ internal override void Apply(bool fromTarget = false)
+ {
+ base.Apply(fromTarget);
+
+ BindableObject target;
+#if DO_NOT_CHECK_FOR_BINDING_REUSE
+ if (!_weakTarget.TryGetTarget(out target))
+ throw new InvalidOperationException();
+#else
+ if (!_weakTarget.TryGetTarget(out target) || target == null) {
+ Unapply();
+ return;
+ }
+#endif
+ object source;
+ if (_weakSource.TryGetTarget(out source) && source != null)
+ ApplyCore(source, target, _targetProperty, fromTarget);
+ }
+
+ // Applies the binding to a new source or target.
+ internal override void Apply(object context, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
+ {
+ _targetProperty = targetProperty;
+ var source = Source ?? Context ?? context;
+ var isApplied = IsApplied;
+
+ if (Source != null && isApplied && fromBindingContextChanged)
+ return;
+
+ base.Apply(source, bindObj, targetProperty, fromBindingContextChanged);
+
+#if (!DO_NOT_CHECK_FOR_BINDING_REUSE)
+ BindableObject prevTarget;
+ if (_weakTarget.TryGetTarget(out prevTarget) && !ReferenceEquals(prevTarget, bindObj))
+ throw new InvalidOperationException("Binding instances can not be reused");
+
+ object previousSource;
+ if (_weakSource.TryGetTarget(out previousSource) && !ReferenceEquals(previousSource, source))
+ throw new InvalidOperationException("Binding instances can not be reused");
+#endif
+ _weakSource.SetTarget(source);
+ _weakTarget.SetTarget(bindObj);
+
+ ApplyCore(source, bindObj, targetProperty);
+ }
+
+ internal override BindingBase Clone()
+ {
+ Tuple<Func<TSource, object>, string> [] handlers = _handlers == null ? null : new Tuple<Func<TSource, object>, string> [_handlers.Length];
+ if (handlers != null) {
+ for (var i = 0; i < _handlers.Length; i++)
+ handlers [i] = new Tuple<Func<TSource, object>, string>(_handlers [i].PartGetter, _handlers [i].PropertyName);
+ }
+ return new TypedBinding<TSource, TProperty>(_getter, _setter, handlers) {
+ Mode = Mode,
+ Converter = Converter,
+ ConverterParameter = ConverterParameter,
+ StringFormat = StringFormat,
+ Source = Source,
+ UpdateSourceEventName = UpdateSourceEventName,
+ };
+ }
+
+ internal override object GetSourceValue(object value, Type targetPropertyType)
+ {
+ if (Converter != null)
+ value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
+
+ //return base.GetSourceValue(value, targetPropertyType);
+ if (StringFormat != null)
+ return string.Format(StringFormat, value);
+
+ return value;
+ }
+
+ internal override object GetTargetValue(object value, Type sourcePropertyType)
+ {
+ if (Converter != null)
+ value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
+
+ //return base.GetTargetValue(value, sourcePropertyType);
+ return value;
+ }
+
+ internal override void Unapply(bool fromBindingContextChanged = false)
+ {
+ if (Source != null && fromBindingContextChanged && IsApplied)
+ return;
+
+#if (!DO_NOT_CHECK_FOR_BINDING_REUSE)
+ base.Unapply(fromBindingContextChanged:fromBindingContextChanged);
+#endif
+ if (_handlers != null)
+ Unsubscribe();
+
+#if (!DO_NOT_CHECK_FOR_BINDING_REUSE)
+ _weakSource.SetTarget(null);
+ _weakTarget.SetTarget(null);
+#endif
+ }
+
+ // ApplyCore is as slim as it should be:
+ // Setting 100000 values : 17ms.
+ // ApplyCore 100000 (w/o INPC, w/o unnapply) : 20ms.
+ internal void ApplyCore(object sourceObject, BindableObject target, BindableProperty property, bool fromTarget = false)
+ {
+ var isTSource = sourceObject != null && sourceObject is TSource;
+ var mode = this.GetRealizedMode(property);
+ if ((mode == BindingMode.OneWay || mode == BindingMode.OneTime) && fromTarget)
+ return;
+
+ var needsGetter = (mode == BindingMode.TwoWay && !fromTarget) || mode == BindingMode.OneWay || mode == BindingMode.OneTime;
+
+ if (isTSource && (mode == BindingMode.OneWay || mode == BindingMode.TwoWay) && _handlers != null)
+ Subscribe((TSource)sourceObject);
+
+ if (needsGetter) {
+ var value = property.DefaultValue;
+ if (isTSource) {
+ try {
+ value = GetSourceValue(_getter((TSource)sourceObject), property.ReturnType);
+ } catch (Exception ex) when (ex is NullReferenceException || ex is KeyNotFoundException) {
+ }
+ }
+ if (!TryConvert(ref value, property, property.ReturnType, true)) {
+ // Log.Warning("Binding", "{0} can not be converted to type '{1}'", value, property.ReturnType);
+ return;
+ }
+ target.SetValueCore(property, value, SetValueFlags.ClearDynamicResource, BindableObject.SetValuePrivateFlags.Default | BindableObject.SetValuePrivateFlags.Converted, false);
+ return;
+ }
+
+ var needsSetter = (mode == BindingMode.TwoWay && fromTarget) || mode == BindingMode.OneWayToSource;
+ if (needsSetter && _setter != null && isTSource) {
+ var value = GetTargetValue(target.GetValue(property), typeof(TProperty));
+ if (!TryConvert(ref value, property, typeof(TProperty), false)) {
+ // Log.Warning("Binding", "{0} can not be converted to type '{1}'", value, typeof(TProperty));
+ return;
+ }
+ _setter((TSource)sourceObject, (TProperty)value);
+ }
+ }
+
+ static bool TryConvert(ref object value, BindableProperty targetProperty, Type convertTo, bool toTarget)
+ {
+ if (value == null)
+ return true;
+ if ((toTarget && targetProperty.TryConvert(ref value)) || (!toTarget && convertTo.IsInstanceOfType(value)))
+ return true;
+
+ object original = value;
+ try {
+ value = Convert.ChangeType(value, convertTo, CultureInfo.InvariantCulture);
+ return true;
+ } catch (Exception ex ) when (ex is InvalidCastException || ex is FormatException||ex is OverflowException) {
+ value = original;
+ return false;
+ }
+ }
+
+ class PropertyChangedProxy
+ {
+ public Func<TSource, object> PartGetter { get; }
+ public string PropertyName { get; }
+ public BindingExpression.WeakPropertyChangedProxy Listener { get; }
+ WeakReference<INotifyPropertyChanged> _weakPart = new WeakReference<INotifyPropertyChanged>(null);
+ readonly BindingBase _binding;
+
+ public INotifyPropertyChanged Part {
+ get {
+ INotifyPropertyChanged target;
+ if (_weakPart.TryGetTarget(out target))
+ return target;
+ return null;
+ }
+ set {
+ _weakPart.SetTarget(value);
+ Listener.SubscribeTo(value, OnPropertyChanged);
+ }
+ }
+
+ public PropertyChangedProxy(Func<TSource, object> partGetter, string propertyName, BindingBase binding)
+ {
+ PartGetter = partGetter;
+ PropertyName = propertyName;
+ _binding = binding;
+ Listener = new BindingExpression.WeakPropertyChangedProxy();
+ }
+
+ void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(e.PropertyName) && string.CompareOrdinal(e.PropertyName, PropertyName) != 0)
+ return;
+ Device.BeginInvokeOnMainThread(() => _binding.Apply(false));
+ }
+ }
+
+ void Subscribe(TSource sourceObject)
+ {
+ for (var i = 0; i < _handlers.Length; i++) {
+ var part = _handlers [i].PartGetter(sourceObject);
+ if (part == null)
+ break;
+ var inpc = part as INotifyPropertyChanged;
+ if (inpc == null)
+ continue;
+ _handlers [i].Part = (inpc);
+ }
+ }
+
+ void Unsubscribe()
+ {
+ for (var i = 0; i < _handlers.Length; i++)
+ _handlers [i].Listener.Unsubscribe();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Tizen.NUI.Binding
+{
+ [Xaml.ProvideCompiled("Tizen.NUI.Core.XamlC.ListStringTypeConverter")]
+ [Xaml.TypeConversion(typeof(List<string>))]
+ internal class ListStringTypeConverter : TypeConverter
+ {
+ public override object ConvertFromInvariantString(string value)
+ {
+ if (value == null)
+ return null;
+
+ return value.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToList();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.ComponentModel;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class NameScopeExtensions
+ {
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static T FindByName<T>(this Element element, string name)
+ {
+ return ((INameScope)element).FindByName<T>(name);
+ }
+
+ internal static T FindByName<T>(this INameScope namescope, string name)
+ {
+ return (T)namescope.FindByName(name);
+ }
+
+ private static Stack<Element> elementStack = new Stack<Element>();
+
+ internal static void PushElement(object element)
+ {
+ elementStack.Push((Element)element);
+ }
+
+ internal static void PopElement()
+ {
+ elementStack.Pop();
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static T FindByNameInCurrentNameScope<T>(string name)
+ {
+ return FindByName<T>(elementStack.Peek(), name);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Binding
+{
+ internal class NullEffect : Effect
+ {
+ protected override void OnAttached()
+ {
+ }
+
+ protected override void OnDetached()
+ {
+ }
+ }
+}
--- /dev/null
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Binding
+{
+ internal class OnIdiom<T>
+ {
+ public T Phone { get; set; }
+
+ public T Tablet { get; set; }
+
+ public T Desktop { get; set; }
+
+ public T TV { get; set; }
+
+ public T Watch { get; set; }
+
+ public static implicit operator T(OnIdiom<T> onIdiom)
+ {
+ switch (Device.Idiom)
+ {
+ default:
+ case TargetIdiom.Phone:
+ return onIdiom.Phone;
+ case TargetIdiom.Tablet:
+ return onIdiom.Tablet;
+ case TargetIdiom.Desktop:
+ return onIdiom.Desktop;
+ case TargetIdiom.TV:
+ return onIdiom.TV;
+ case TargetIdiom.Watch:
+ return onIdiom.Watch;
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ [ContentProperty("Platforms")]
+ internal class OnPlatform<T>
+ {
+ public OnPlatform()
+ {
+ Platforms = new List<On>();
+ }
+
+ bool useLegacyFallback;
+ T android;
+ [Obsolete]
+ public T Android {
+ get { return android; }
+ set {
+ useLegacyFallback = true;
+ android = value;
+ }
+ }
+
+ T ios;
+ [Obsolete]
+ public T iOS {
+ get { return ios; }
+ set {
+ useLegacyFallback = true;
+ ios = value;
+ }
+ }
+
+ T winPhone;
+ [Obsolete]
+ public T WinPhone {
+ get { return winPhone; }
+ set {
+ useLegacyFallback = true;
+ winPhone = value;
+ }
+ }
+
+ bool hasDefault;
+ T @default;
+ public T Default {
+ get { return @default; }
+ set {
+ hasDefault = true;
+ @default = value;
+ }
+ }
+
+ public IList<On> Platforms { get; private set; }
+
+#pragma warning disable RECS0108 // Warns about static fields in generic types
+ static readonly IValueConverterProvider s_valueConverter = DependencyService.Get<IValueConverterProvider>();
+#pragma warning restore RECS0108 // Warns about static fields in generic types
+
+ public static implicit operator T(OnPlatform<T> onPlatform)
+ {
+ foreach (var onPlat in onPlatform.Platforms) {
+ if (onPlat.Platform == null)
+ continue;
+ if (!onPlat.Platform.Contains(Device.RuntimePlatform))
+ continue;
+ if (s_valueConverter == null)
+ continue;
+ return (T)s_valueConverter.Convert(onPlat.Value, typeof(T), null, null);
+ }
+
+ if (!onPlatform.useLegacyFallback)
+ return onPlatform.hasDefault ? onPlatform.@default : default(T);
+
+ //legacy fallback
+#pragma warning disable 0618, 0612
+ return Device.OnPlatform(iOS: onPlatform.iOS, Android: onPlatform.Android, WinPhone: onPlatform.WinPhone);
+#pragma warning restore 0618, 0612
+ }
+ }
+
+ [ContentProperty("Value")]
+ internal class On
+ {
+ [TypeConverter(typeof(ListStringTypeConverter))]
+ public IList<string> Platform { get; set; }
+ public object Value { get; set; }
+ }
+}
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.Parameter)]
+ internal sealed class ParameterAttribute : Attribute
+ {
+ public ParameterAttribute(string name)
+ {
+ Name = name;
+ }
+
+ public string Name { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using System;
+using System.Threading;
+
+namespace Tizen.NUI
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal interface IPerformanceProvider
+ {
+ void Stop(string reference, string tag, string path, string member);
+
+ void Start(string reference, string tag, string path, string member);
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Binding
+{
+ // Previewer uses reflection to bind to this method; Removal or modification of visibility will break previewer.
+ internal static class Registrar
+ {
+ internal static void RegisterAll(Type[] attrTypes) => Internals.Registrar.RegisterAll(attrTypes);
+ }
+}
+
+namespace Tizen.NUI.Binding.Internals
+{
+ /// <summary>
+ /// For internal use.
+ /// </summary>
+ /// <typeparam name="TRegistrable"></typeparam>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class Registrar<TRegistrable> where TRegistrable : class
+ {
+ readonly Dictionary<Type, Type> _handlers = new Dictionary<Type, Type>();
+
+ /// <summary>
+ /// Register.
+ /// </summary>
+ /// <param name="tview">The type of the view</param>
+ /// <param name="trender">The type of the render.</param>
+ public void Register(Type tview, Type trender)
+ {
+ //avoid caching null renderers
+ if (trender == null)
+ return;
+ _handlers[tview] = trender;
+ }
+
+ internal TRegistrable GetHandler(Type type)
+ {
+ Type handlerType = GetHandlerType(type);
+ if (handlerType == null)
+ return null;
+
+ object handler = DependencyResolver.ResolveOrCreate(handlerType);
+
+ return (TRegistrable)handler;
+ }
+
+ internal TRegistrable GetHandler(Type type, params object[] args)
+ {
+ if (args.Length == 0)
+ {
+ return GetHandler(type);
+ }
+
+ Type handlerType = GetHandlerType(type);
+ if (handlerType == null)
+ return null;
+
+ return (TRegistrable)DependencyResolver.ResolveOrCreate(handlerType, args);
+ }
+
+ /// <summary>
+ /// For internal use. Returns handler.
+ /// </summary>
+ /// <typeparam name="TOut">The type of the handler</typeparam>
+ /// <param name="type">The type.</param>
+ /// <returns>The handler instance.</returns>
+ public TOut GetHandler<TOut>(Type type) where TOut : TRegistrable
+ {
+ return (TOut)GetHandler(type);
+ }
+
+ /// <summary>
+ /// For internal use. Returns handler.
+ /// </summary>
+ /// <typeparam name="TOut">The type of the handler</typeparam>
+ /// <param name="type">The type.</param>
+ /// <param name="args">The args of the type</param>
+ /// <returns>The handler instance.</returns>
+ public TOut GetHandler<TOut>(Type type, params object[] args) where TOut : TRegistrable
+ {
+ return (TOut)GetHandler(type, args);
+ }
+
+ /// <summary>
+ /// For internal use. Return the handler of the object.
+ /// </summary>
+ /// <typeparam name="TOut">Thetype</typeparam>
+ /// <param name="obj">The object instance.</param>
+ /// <returns>The handle of the obj.</returns>
+ public TOut GetHandlerForObject<TOut>(object obj) where TOut : TRegistrable
+ {
+ if (obj == null)
+ throw new ArgumentNullException(nameof(obj));
+
+ var reflectableType = obj as IReflectableType;
+ var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
+
+ return (TOut)GetHandler(type);
+ }
+
+ /// <summary>
+ /// For inetrnal use. Return the handler of the object.
+ /// </summary>
+ /// <typeparam name="TOut">The type</typeparam>
+ /// <param name="obj">The object instance</param>
+ /// <param name="args">The args of the type</param>
+ /// <returns>The handler of the object.</returns>
+ public TOut GetHandlerForObject<TOut>(object obj, params object[] args) where TOut : TRegistrable
+ {
+ if (obj == null)
+ throw new ArgumentNullException(nameof(obj));
+
+ var reflectableType = obj as IReflectableType;
+ var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
+
+ return (TOut)GetHandler(type, args);
+ }
+
+ /// <summary>
+ /// For internal use. Returns the handle type.
+ /// </summary>
+ /// <param name="viewType">The view type.</param>
+ /// <returns>The type of the handle.</returns>
+ public Type GetHandlerType(Type viewType)
+ {
+ Type type;
+ if (LookupHandlerType(viewType, out type))
+ return type;
+
+ // lazy load render-view association with RenderWithAttribute (as opposed to using ExportRenderer)
+ var attribute = viewType.GetTypeInfo().GetCustomAttribute<RenderWithAttribute>();
+ if (attribute == null)
+ {
+ Register(viewType, null); // Cache this result so we don't have to do GetCustomAttribute again
+ return null;
+ }
+
+ type = attribute.Type;
+
+ 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("_", StringComparison.Ordinal))
+ {
+ Register(viewType, null); // Cache this result so we don't work through this chain again
+ return null;
+ }
+ }
+
+ Register(viewType, type); // Register this so we don't have to look for the RenderWith Attibute again in the future
+
+ return type;
+ }
+
+ /// <summary>
+ /// For internal use. Return the handle type of the object
+ /// </summary>
+ /// <param name="obj">The object instance.</param>
+ /// <returns>The type of the handler.</returns>
+ public Type GetHandlerTypeForObject(object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException(nameof(obj));
+
+ var reflectableType = obj as IReflectableType;
+ var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
+
+ return GetHandlerType(type);
+ }
+
+ bool LookupHandlerType(Type viewType, out Type handlerType)
+ {
+ Type type = viewType;
+
+ while (type != null)
+ {
+ if (_handlers.ContainsKey(type))
+ {
+ handlerType = _handlers[type];
+ return true;
+ }
+
+ type = type.GetTypeInfo().BaseType;
+ }
+
+ handlerType = null;
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// For internal use
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class Registrar
+ {
+ static Registrar()
+ {
+ Registered = new Registrar<IRegisterable>();
+ }
+
+ 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; }
+
+ public static Registrar<IRegisterable> Registered { get; internal set; }
+
+ public static void RegisterAll(Type[] attrTypes)
+ {
+ 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);
+
+ if (indexOfExecuting > 0)
+ {
+ assemblies[indexOfExecuting] = assemblies[0];
+ assemblies[0] = defaultRendererAssembly;
+ }
+
+ // Don't use LINQ for performance reasons
+ // Naive implementation can easily take over a second to run
+ foreach (Assembly assembly in assemblies)
+ {
+ foreach (Type attrType in attrTypes)
+ {
+ Attribute[] attributes;
+ try
+ {
+ attributes = assembly.GetCustomAttributes(attrType).ToArray();
+ }
+ catch (System.IO.FileNotFoundException)
+ {
+ // Sometimes the previewer doesn't actually have everything required for these loads to work
+ Console.WriteLine(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
+ continue;
+ }
+ 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();
+ var exportEffectsLength = effectAttributes.Length;
+ for (var i = 0; i < exportEffectsLength;i++)
+ {
+ var effect = (ExportEffectAttribute)effectAttributes[i];
+ 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);
+ }
+ }
+}
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ internal sealed class RenderWithAttribute : Attribute
+ {
+ public RenderWithAttribute(Type type)
+ {
+ Type = type;
+ }
+
+ public Type Type { get; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.Assembly)]
+ internal class ResolutionGroupNameAttribute : Attribute
+ {
+ public ResolutionGroupNameAttribute(string name)
+ {
+ ShortName = name;
+ }
+
+ internal string ShortName { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class ResourceDictionary : IResourceDictionary, IDictionary<string, object>
+ {
+ static ConditionalWeakTable<Type, ResourceDictionary> s_instances = new ConditionalWeakTable<Type, ResourceDictionary>();
+ readonly Dictionary<string, object> _innerDictionary = new Dictionary<string, object>();
+ ResourceDictionary _mergedInstance;
+ Type _mergedWith;
+ Uri _source;
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ResourceDictionary()
+ {
+ DependencyService.Register<IResourcesLoader, ResourcesLoader>();
+ }
+
+ [TypeConverter(typeof(TypeTypeConverter))]
+ [Obsolete("Use Source")]
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Type MergedWith {
+ get { return _mergedWith; }
+ set {
+ if (_mergedWith == value)
+ return;
+
+ if (_source != null)
+ throw new ArgumentException("MergedWith can not be used with Source");
+
+ if (!typeof(ResourceDictionary).GetTypeInfo().IsAssignableFrom(value.GetTypeInfo()))
+ throw new ArgumentException("MergedWith should inherit from ResourceDictionary");
+
+ _mergedWith = value;
+ if (_mergedWith == null)
+ return;
+
+ _mergedInstance = s_instances.GetValue(_mergedWith, (key) => (ResourceDictionary)Activator.CreateInstance(key));
+ OnValuesChanged(_mergedInstance.ToArray());
+ }
+ }
+
+ [TypeConverter(typeof(RDSourceTypeConverter))]
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Uri Source {
+ get { return _source; }
+ set {
+ if (_source == value)
+ return;
+ throw new InvalidOperationException("Source can only be set from XAML."); //through the RDSourceTypeConverter
+ }
+ }
+
+ //Used by the XamlC compiled converter
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SetAndLoadSource(Uri value, string resourcePath, Assembly assembly, System.Xml.IXmlLineInfo lineInfo)
+ {
+ _source = value;
+ if (_mergedWith != null)
+ throw new ArgumentException("Source can not be used with MergedWith");
+
+ //this will return a type if the RD as an x:Class element, and codebehind
+ var type = XamlResourceIdAttribute.GetTypeForPath(assembly, resourcePath);
+ if (type != null)
+ _mergedInstance = s_instances.GetValue(type, (key) => (ResourceDictionary)Activator.CreateInstance(key));
+ else
+ _mergedInstance = DependencyService.Get<IResourcesLoader>().CreateFromResource<ResourceDictionary>(resourcePath, assembly, lineInfo);
+ OnValuesChanged(_mergedInstance.ToArray());
+ }
+
+ ICollection<ResourceDictionary> _mergedDictionaries;
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ICollection<ResourceDictionary> MergedDictionaries {
+ get {
+ if (_mergedDictionaries == null) {
+ var col = new ObservableCollection<ResourceDictionary>();
+ col.CollectionChanged += MergedDictionaries_CollectionChanged;
+ _mergedDictionaries = col;
+ }
+ return _mergedDictionaries;
+ }
+ }
+
+ 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)
+ {
+ // Move() isn't exposed by ICollection
+ if (e.Action == NotifyCollectionChangedAction.Move)
+ return;
+
+ _collectionTrack = _collectionTrack ?? new List<ResourceDictionary>();
+ // Collection has been cleared
+ if (e.Action == NotifyCollectionChangedAction.Reset) {
+ foreach (var dictionary in _collectionTrack)
+ dictionary.ValuesChanged -= Item_ValuesChanged;
+
+ _collectionTrack.Clear();
+ return;
+ }
+
+ // New Items
+ if (e.NewItems != null)
+ {
+ foreach (var item in e.NewItems)
+ {
+ var rd = (ResourceDictionary)item;
+ _collectionTrack.Add(rd);
+ rd.ValuesChanged += Item_ValuesChanged;
+ OnValuesChanged(rd.ToArray());
+ }
+ }
+
+ // Old Items
+ if (e.OldItems != null)
+ {
+ foreach (var item in e.OldItems)
+ {
+ var rd = (ResourceDictionary)item;
+ rd.ValuesChanged -= Item_ValuesChanged;
+ _collectionTrack.Remove(rd);
+ }
+ }
+ }
+
+ void Item_ValuesChanged(object sender, ResourcesChangedEventArgs e)
+ {
+ OnValuesChanged(e.Values.ToArray());
+ }
+
+ void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
+ {
+ ((ICollection<KeyValuePair<string, object>>)_innerDictionary).Add(item);
+ OnValuesChanged(item);
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Clear()
+ {
+ _innerDictionary.Clear();
+ }
+
+ bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
+ {
+ return ((ICollection<KeyValuePair<string, object>>)_innerDictionary).Contains(item)
+ || (_mergedInstance != null && _mergedInstance.Contains(item));
+ }
+
+ void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
+ {
+ ((ICollection<KeyValuePair<string, object>>)_innerDictionary).CopyTo(array, arrayIndex);
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int Count
+ {
+ get { return _innerDictionary.Count; }
+ }
+
+ bool ICollection<KeyValuePair<string, object>>.IsReadOnly
+ {
+ get { return ((ICollection<KeyValuePair<string, object>>)_innerDictionary).IsReadOnly; }
+ }
+
+ bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)
+ {
+ return ((ICollection<KeyValuePair<string, object>>)_innerDictionary).Remove(item);
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Add(string key, object value)
+ {
+ if (ContainsKey(key))
+ throw new ArgumentException($"A resource with the key '{key}' is already present in the ResourceDictionary.");
+ _innerDictionary.Add(key, value);
+ OnValueChanged(key, value);
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool ContainsKey(string key)
+ {
+ return _innerDictionary.ContainsKey(key);
+ }
+
+ [IndexerName("Item")]
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public object this[string index]
+ {
+ get
+ {
+ if (_innerDictionary.ContainsKey(index))
+ return _innerDictionary[index];
+ if (_mergedInstance != null && _mergedInstance.ContainsKey(index))
+ return _mergedInstance[index];
+ if (MergedDictionaries != null)
+ foreach (var dict in MergedDictionaries.Reverse())
+ if (dict.ContainsKey(index))
+ return dict[index];
+ throw new KeyNotFoundException($"The resource '{index}' is not present in the dictionary.");
+ }
+ set
+ {
+ _innerDictionary[index] = value;
+ OnValueChanged(index, value);
+ }
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ICollection<string> Keys
+ {
+ get { return _innerDictionary.Keys; }
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool Remove(string key)
+ {
+ return _innerDictionary.Remove(key);
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ICollection<object> Values
+ {
+ get { return _innerDictionary.Values; }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
+ {
+ return _innerDictionary.GetEnumerator();
+ }
+
+ internal IEnumerable<KeyValuePair<string, object>> MergedResources {
+ get {
+ if (MergedDictionaries != null)
+ foreach (var r in MergedDictionaries.Reverse().SelectMany(x => x.MergedResources))
+ yield return r;
+ if (_mergedInstance != null)
+ foreach (var r in _mergedInstance.MergedResources)
+ yield return r;
+ foreach (var r in _innerDictionary)
+ yield return r;
+ }
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool TryGetValue(string key, out object value)
+ {
+ return _innerDictionary.TryGetValue(key, out value)
+ || (_mergedInstance != null && _mergedInstance.TryGetValue(key, out value))
+ || (MergedDictionaries != null && TryGetMergedDictionaryValue(key, out value));
+ }
+
+ bool TryGetMergedDictionaryValue(string key, out object value)
+ {
+ foreach (var dictionary in MergedDictionaries.Reverse())
+ if (dictionary.TryGetValue(key, out value))
+ return true;
+
+ value = null;
+ return false;
+ }
+
+ event EventHandler<ResourcesChangedEventArgs> IResourceDictionary.ValuesChanged
+ {
+ add { ValuesChanged += value; }
+ remove { ValuesChanged -= value; }
+ }
+
+ public void Add(Style style)
+ {
+ if (string.IsNullOrEmpty(style.Class))
+ Add(style.TargetType.FullName, style);
+ else
+ {
+ IList<Style> classes;
+ object outclasses;
+ if (!TryGetValue(Style.StyleClassPrefix + style.Class, out outclasses) || (classes = outclasses as IList<Style>) == null)
+ classes = new List<Style>();
+ classes.Add(style);
+ this[Style.StyleClassPrefix + style.Class] = classes;
+ }
+ }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Add(ResourceDictionary mergedResourceDictionary)
+ {
+ 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));
+ }
+
+ void OnValuesChanged(params KeyValuePair<string, object>[] values)
+ {
+ if (values == null || values.Length == 0)
+ return;
+ ValuesChanged?.Invoke(this, new ResourcesChangedEventArgs(values));
+ }
+
+ event EventHandler<ResourcesChangedEventArgs> ValuesChanged;
+
+ [Xaml.ProvideCompiled("Tizen.NUI.Xaml.Core.XamlC.RDSourceTypeConverter")]
+ public class RDSourceTypeConverter : TypeConverter, IExtendedTypeConverter
+ {
+ object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ throw new ArgumentNullException(nameof(serviceProvider));
+
+ var targetRD = (serviceProvider.GetService(typeof(Xaml.IProvideValueTarget)) as Xaml.IProvideValueTarget)?.TargetObject as ResourceDictionary;
+ if (targetRD == null)
+ return null;
+
+ var rootObjectType = (serviceProvider.GetService(typeof(Xaml.IRootObjectProvider)) as Xaml.IRootObjectProvider)?.RootObject.GetType();
+ if (rootObjectType == null)
+ return null;
+
+ var lineInfo = (serviceProvider.GetService(typeof(Xaml.IXmlLineInfoProvider)) as Xaml.IXmlLineInfoProvider)?.XmlLineInfo;
+ var rootTargetPath = XamlResourceIdAttribute.GetPathForType(rootObjectType);
+ var uri = new Uri(value, UriKind.Relative); //we don't want file:// uris, even if they start with '/'
+ var resourcePath = GetResourcePath(uri, rootTargetPath);
+
+ targetRD.SetAndLoadSource(uri, resourcePath, rootObjectType.GetTypeInfo().Assembly, lineInfo);
+ return uri;
+ }
+
+ internal static string GetResourcePath(Uri uri, string rootTargetPath)
+ {
+ //need a fake scheme so it's not seen as file:// uri, and the forward slashes are valid on all plats
+ var resourceUri = uri.OriginalString.StartsWith("/", StringComparison.Ordinal)
+ ? new Uri($"pack://{uri.OriginalString}", UriKind.Absolute)
+ : new Uri($"pack:///{rootTargetPath}/../{uri.OriginalString}", UriKind.Absolute);
+
+ //drop the leading '/'
+ return resourceUri.AbsolutePath.Substring(1);
+ }
+
+ object IExtendedTypeConverter.ConvertFrom(CultureInfo culture, object value, IServiceProvider serviceProvider)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object ConvertFromInvariantString(string value)
+ {
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal class ResourcesChangedEventArgs : EventArgs
+ {
+ public static readonly ResourcesChangedEventArgs StyleSheets = new ResourcesChangedEventArgs(null);
+
+ public ResourcesChangedEventArgs(IEnumerable<KeyValuePair<string, object>> values)
+ {
+ Values = values;
+ }
+
+ public IEnumerable<KeyValuePair<string, object>> Values { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Binding
+{
+ internal class Application : Element, IResourcesProvider
+ {
+ static Application s_current;
+
+ public delegate void resChangeCb(object sender, ResourcesChangedEventArgs e);
+
+ static private Dictionary<object, Dictionary<resChangeCb, int>> resourceChangeCallbackDict = new Dictionary<object, Dictionary<resChangeCb, int>>();
+
+ static public void AddResourceChangedCallback(object handle, resChangeCb cb)
+ {
+ Dictionary<resChangeCb, int> cbDict;
+ resourceChangeCallbackDict.TryGetValue(handle, out cbDict);
+
+ if (null == cbDict)
+ {
+ cbDict = new Dictionary<resChangeCb, int>();
+ resourceChangeCallbackDict.Add(handle, cbDict);
+ }
+
+ if (false == cbDict.ContainsKey(cb))
+ {
+ cbDict.Add(cb, 0);
+ }
+ }
+
+ public Application()
+ {
+ SystemResources = DependencyService.Get<ISystemResourcesProvider>().GetSystemResources();
+ SystemResources.ValuesChanged += OnParentResourcesChanged;
+ }
+
+ public static bool IsApplicationOrNull(Element element)
+ {
+ return element == null || element is Application;
+ }
+
+ internal virtual void OnParentResourcesChanged(object sender, ResourcesChangedEventArgs e)
+ {
+ // if (e == ResourcesChangedEventArgs.StyleSheets)
+ // ApplyStyleSheetsOnParentSet();
+ // else
+ // OnParentResourcesChanged(e.Values);
+ }
+
+ internal IResourceDictionary SystemResources { get; }
+
+ public static Application Current
+ {
+ get
+ {
+ if (null == s_current)
+ {
+ s_current = new Application();
+ }
+
+ return s_current;
+ }
+
+ set
+ {
+ if (s_current == value)
+ return;
+ if (value == null)
+ s_current = null; //Allow to reset current for unittesting
+ s_current = value;
+ }
+ }
+
+ ResourceDictionary _resources;
+ bool IResourcesProvider.IsResourcesCreated => _resources != null;
+
+ public ResourceDictionary Resources
+ {
+ get
+ {
+ if (_resources != null)
+ return _resources;
+
+ _resources = new ResourceDictionary();
+ ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+ return _resources;
+ }
+ set
+ {
+ if (_resources == value)
+ return;
+ OnPropertyChanging();
+ if (_resources != null)
+ ((IResourceDictionary)_resources).ValuesChanged -= OnResourcesChanged;
+ _resources = value;
+ OnResourcesChanged(value);
+ if (_resources != null)
+ ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+ OnPropertyChanged();
+ }
+ }
+
+ internal virtual void OnResourcesChanged(object sender, ResourcesChangedEventArgs e)
+ {
+ OnResourcesChanged(e.Values);
+ }
+ }
+ internal static class ResourcesExtensions
+ {
+ public static IEnumerable<KeyValuePair<string, object>> GetMergedResources(this IElement element)
+ {
+ Dictionary<string, object> resources = null;
+ while (element != null)
+ {
+ var ve = element as IResourcesProvider;
+ if (ve != null && ve.IsResourcesCreated)
+ {
+ resources = resources ?? new Dictionary<string, object>();
+ foreach (KeyValuePair<string, object> res in ve.Resources.MergedResources)
+ if (!resources.ContainsKey(res.Key))
+ resources.Add(res.Key, res.Value);
+ else if (res.Key.StartsWith(Style.StyleClassPrefix, StringComparison.Ordinal))
+ {
+ var mergedClassStyles = new List<Style>(resources[res.Key] as List<Style>);
+ mergedClassStyles.AddRange(res.Value as List<Style>);
+ resources[res.Key] = mergedClassStyles;
+ }
+ }
+ var app = element as Application;
+ if (app != null && app.SystemResources != null)
+ {
+ resources = resources ?? new Dictionary<string, object>(8);
+ foreach (KeyValuePair<string, object> res in app.SystemResources)
+ if (!resources.ContainsKey(res.Key))
+ resources.Add(res.Key, res.Value);
+ else if (res.Key.StartsWith(Style.StyleClassPrefix, StringComparison.Ordinal))
+ {
+ var mergedClassStyles = new List<Style>(resources[res.Key] as List<Style>);
+ mergedClassStyles.AddRange(res.Value as List<Style>);
+ resources[res.Key] = mergedClassStyles;
+ }
+ }
+ element = element.Parent;
+ }
+ return resources;
+ }
+
+ public static bool TryGetResource(this IElement element, string key, out object value)
+ {
+ while (element != null)
+ {
+ var ve = element as IResourcesProvider;
+ if (ve != null && ve.IsResourcesCreated && ve.Resources.TryGetValue(key, out value))
+ return true;
+ var app = element as Application;
+ if (app != null && app.SystemResources != null && app.SystemResources.TryGetValue(key, out value))
+ return true;
+ element = element.Parent;
+ }
+
+ //Fallback for the XF previewer
+ if (Application.Current != null && ((IResourcesProvider)Application.Current).IsResourcesCreated && Application.Current.Resources.TryGetValue(key, out value))
+ return true;
+
+ value = null;
+ return false;
+ }
+ }
+}
--- /dev/null
+using System.ComponentModel;
+
+namespace Tizen.NUI.Binding
+{
+ internal class RoutingEffect : Effect
+ {
+ internal readonly Effect Inner;
+
+ protected RoutingEffect(string effectId)
+ {
+ Inner = Resolve(effectId);
+ }
+
+ protected override void OnAttached()
+ {
+ }
+
+ protected override void OnDetached()
+ {
+ }
+
+ internal override void ClearEffect()
+ {
+ Inner?.ClearEffect();
+ }
+
+ internal override void SendAttached()
+ {
+ Inner?.SendAttached();
+ }
+
+ internal override void SendDetached()
+ {
+ Inner?.SendDetached();
+ }
+
+ internal override void SendOnElementPropertyChanged(PropertyChangedEventArgs args)
+ {
+ Inner?.SendOnElementPropertyChanged(args);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Xml;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ [ContentProperty("Value")]
+ [ProvideCompiled("Tizen.NUI.Core.XamlC.SetterValueProvider")]
+ internal sealed class Setter : IValueProvider
+ {
+ readonly ConditionalWeakTable<BindableObject, object> _originalValues = new ConditionalWeakTable<BindableObject, object>();
+
+ public BindableProperty Property { get; set; }
+
+ public object Value { get; set; }
+
+ object IValueProvider.ProvideValue(IServiceProvider serviceProvider)
+ {
+ if (Property == null)
+ {
+ var lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ IXmlLineInfo lineInfo = lineInfoProvider != null ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
+ throw new XamlParseException("Property not set", lineInfo);
+ }
+ var valueconverter = serviceProvider.GetService(typeof(IValueConverterProvider)) as IValueConverterProvider;
+
+ Func<MemberInfo> minforetriever =
+ () =>
+ (MemberInfo)Property.DeclaringType.GetRuntimeProperty(Property.PropertyName) ?? (MemberInfo)Property.DeclaringType.GetRuntimeMethod("Get" + Property.PropertyName, new[] { typeof(BindableObject) });
+
+ object value = valueconverter.Convert(Value, Property.ReturnType, minforetriever, serviceProvider);
+ Value = value;
+ return this;
+ }
+
+ internal void Apply(BindableObject target, bool fromStyle = false)
+ {
+ if (target == null)
+ throw new ArgumentNullException("target");
+ if (Property == null)
+ return;
+
+ object originalValue = target.GetValue(Property);
+ if (!Equals(originalValue, Property.DefaultValue))
+ {
+ _originalValues.Remove(target);
+ _originalValues.Add(target, originalValue);
+ }
+
+ var dynamicResource = Value as DynamicResource;
+ var binding = Value as BindingBase;
+ if (binding != null)
+ target.SetBinding(Property, binding.Clone(), fromStyle);
+ else if (dynamicResource != null)
+ target.SetDynamicResource(Property, dynamicResource.Key, fromStyle);
+ else
+ {
+ if (Value is IList<VisualStateGroup> visualStateGroupCollection)
+ target.SetValue(Property, visualStateGroupCollection.Clone(), fromStyle);
+ else
+ target.SetValue(Property, Value, fromStyle);
+ }
+ }
+
+ internal void UnApply(BindableObject target, bool fromStyle = false)
+ {
+ if (target == null)
+ throw new ArgumentNullException(nameof(target));
+ if (Property == null)
+ return;
+
+ object actual = target.GetValue(Property);
+ if (!Equals(actual, Value) && !(Value is Tizen.NUI.Binding.Binding) && !(Value is DynamicResource))
+ {
+ //Do not reset default value if the value has been changed
+ _originalValues.Remove(target);
+ return;
+ }
+
+ object defaultValue;
+ if (_originalValues.TryGetValue(target, out defaultValue))
+ {
+ //reset default value, unapply bindings and dynamicResource
+ target.SetValue(Property, defaultValue, fromStyle);
+ _originalValues.Remove(target);
+ }
+ else
+ target.ClearValue(Property);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Tizen.NUI.StyleSheets;
+
+namespace Tizen.NUI.Binding
+{
+ [ContentProperty("Setters")]
+ internal sealed class Style : IStyle
+ {
+ internal const string StyleClassPrefix = "Tizen.NUI.Binding.StyleClass.";
+
+ readonly BindableProperty _basedOnResourceProperty = BindableProperty.CreateAttached("BasedOnResource", typeof(Style), typeof(Style), default(Style),
+ propertyChanged: OnBasedOnResourceChanged);
+
+ readonly List<WeakReference<BindableObject>> _targets = new List<WeakReference<BindableObject>>(4);
+
+ Style _basedOnStyle;
+
+ string _baseResourceKey;
+
+ IList<Behavior> _behaviors;
+
+ IList<TriggerBase> _triggers;
+
+ public Style([TypeConverter(typeof(TypeTypeConverter))] [Parameter("TargetType")] Type targetType)
+ {
+ if (targetType == null)
+ throw new ArgumentNullException("targetType");
+
+ TargetType = targetType;
+ Setters = new List<Setter>();
+ }
+
+ public bool ApplyToDerivedTypes { get; set; }
+
+ public Style BasedOn
+ {
+ get { return _basedOnStyle; }
+ set
+ {
+ if (_basedOnStyle == value)
+ return;
+ if (!ValidateBasedOn(value))
+ throw new ArgumentException("BasedOn.TargetType is not compatible with TargetType");
+ Style oldValue = _basedOnStyle;
+ _basedOnStyle = value;
+ BasedOnChanged(oldValue, value);
+ if (value != null)
+ BaseResourceKey = null;
+ }
+ }
+
+ public string BaseResourceKey
+ {
+ get { return _baseResourceKey; }
+ set
+ {
+ if (_baseResourceKey == value)
+ return;
+ _baseResourceKey = value;
+ //update all DynamicResources
+ foreach (WeakReference<BindableObject> bindableWr in _targets)
+ {
+ BindableObject target;
+ if (!bindableWr.TryGetTarget(out target))
+ continue;
+ target.RemoveDynamicResource(_basedOnResourceProperty);
+ if (value != null)
+ target.SetDynamicResource(_basedOnResourceProperty, value);
+ }
+ if (value != null)
+ BasedOn = null;
+ }
+ }
+
+ public IList<Behavior> Behaviors
+ {
+ get { return _behaviors ?? (_behaviors = new AttachedCollection<Behavior>()); }
+ }
+
+ public bool CanCascade { get; set; }
+
+ public string Class { get; set; }
+
+ public IList<Setter> Setters { get; }
+
+ public IList<TriggerBase> Triggers
+ {
+ get { return _triggers ?? (_triggers = new AttachedCollection<TriggerBase>()); }
+ }
+
+ void IStyle.Apply(BindableObject bindable)
+ {
+ _targets.Add(new WeakReference<BindableObject>(bindable));
+ if (BaseResourceKey != null)
+ bindable.SetDynamicResource(_basedOnResourceProperty, BaseResourceKey);
+ ApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
+ }
+
+ public Type TargetType { get; }
+
+ void IStyle.UnApply(BindableObject bindable)
+ {
+ UnApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
+ bindable.RemoveDynamicResource(_basedOnResourceProperty);
+ _targets.RemoveAll(wr =>
+ {
+ BindableObject target;
+ return wr.TryGetTarget(out target) && target == bindable;
+ });
+ }
+
+ internal bool CanBeAppliedTo(Type targetType)
+ {
+ if (TargetType == targetType)
+ return true;
+ if (!ApplyToDerivedTypes)
+ return false;
+ do
+ {
+ targetType = targetType.GetTypeInfo().BaseType;
+ if (TargetType == targetType)
+ return true;
+ } while (targetType != typeof(Element));
+ return false;
+ }
+
+ void ApplyCore(BindableObject bindable, Style basedOn)
+ {
+ if (basedOn != null)
+ ((IStyle)basedOn).Apply(bindable);
+
+ foreach (Setter setter in Setters)
+ setter.Apply(bindable, true);
+ ((AttachedCollection<Behavior>)Behaviors).AttachTo(bindable);
+ ((AttachedCollection<TriggerBase>)Triggers).AttachTo(bindable);
+ }
+
+ void BasedOnChanged(Style oldValue, Style newValue)
+ {
+ foreach (WeakReference<BindableObject> bindableRef in _targets)
+ {
+ BindableObject bindable;
+ if (!bindableRef.TryGetTarget(out bindable))
+ continue;
+
+ UnApplyCore(bindable, oldValue);
+ ApplyCore(bindable, newValue);
+ }
+ }
+
+ Style GetBasedOnResource(BindableObject bindable)
+ {
+ return (Style)bindable.GetValue(_basedOnResourceProperty);
+ }
+
+ static void OnBasedOnResourceChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ // Style style = (bindable as /*VisualElement*/BaseHandle).Style;
+ // if (style == null)
+ // return;
+ // style.UnApplyCore(bindable, (Style)oldValue);
+ // style.ApplyCore(bindable, (Style)newValue);
+ }
+
+ void UnApplyCore(BindableObject bindable, Style basedOn)
+ {
+ ((AttachedCollection<TriggerBase>)Triggers).DetachFrom(bindable);
+ ((AttachedCollection<Behavior>)Behaviors).DetachFrom(bindable);
+ foreach (Setter setter in Setters)
+ setter.UnApply(bindable, true);
+
+ if (basedOn != null)
+ ((IStyle)basedOn).UnApply(bindable);
+ }
+
+ bool ValidateBasedOn(Style value)
+ {
+ if (value == null)
+ return true;
+ return value.TargetType.IsAssignableFrom(TargetType);
+ }
+ }
+}
--- /dev/null
+using System.Runtime.CompilerServices;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal interface IStyle
+ {
+ Type TargetType { get; }
+
+ void Apply(BindableObject bindable);
+ void UnApply(BindableObject bindable);
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal interface IStyleSelectable
+ {
+ string[] NameAndBases { get; }
+ string Id { get; }
+ IStyleSelectable Parent { get; }
+ IList<string> Classes { get; }
+ IEnumerable<IStyleSelectable> Children { get; }
+ }
+
+ internal interface IStylable
+ {
+ BindableProperty GetProperty(string key, bool inheriting);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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(Element styleable, bool inheriting = false)
+ {
+ if (styleable == null)
+ throw new ArgumentNullException(nameof(styleable));
+
+ foreach (var decl in Declarations) {
+ var property = ((IStylable)styleable).GetProperty(decl.Key, inheriting);
+ 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 Element;
+ if (ve == null)
+ continue;
+ Apply(ve, inheriting: true);
+ }
+ }
+
+ // [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);
+ return null;
+ }
+
+ public void UnApply(IStylable styleable)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
--- /dev/null
+using System;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.StyleSheets
+{
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = true)]
+ internal 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 bool Inherited { get; set; } = false;
+
+
+ public StylePropertyAttribute(string cssPropertyName, Type targetType, string bindablePropertyName)
+ {
+ CssPropertyName = cssPropertyName;
+ BindablePropertyName = bindablePropertyName;
+ TargetType = targetType;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Xml;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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(Element);
+
+ void IStyle.Apply(BindableObject bindable)
+ {
+ var styleable = bindable as Element;
+ if (styleable == null)
+ return;
+ Apply(styleable);
+ }
+
+ void Apply(Element styleable)
+ {
+ ApplyCore(styleable);
+ foreach (var child in styleable.LogicalChildrenInternal)
+ ((IStyle)this).Apply(child);
+ }
+
+ void ApplyCore(Element styleable)
+ {
+ var visualStylable = styleable as Element;
+ if (visualStylable == null)
+ return;
+ foreach (var kvp in Styles) {
+ var selector = kvp.Key;
+ var style = kvp.Value;
+ // if (!selector.Matches(styleable))
+ // continue;
+ style.Apply(visualStylable);
+ }
+ }
+
+ void IStyle.UnApply(BindableObject bindable)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Tizen.NUI.StyleSheets
+{
+ internal 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();
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Tizen.NUI.Binding
+{
+ internal enum TargetIdiom
+ {
+ Unsupported,
+ Phone,
+ Tablet,
+ Desktop,
+ TV,
+ Watch
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [Obsolete]
+ internal enum TargetPlatform
+ {
+ Other,
+ iOS,
+ Android,
+ WinPhone,
+ Windows
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Globalization;
+
+namespace Tizen.NUI.Binding
+{
+ internal class TemplateBinding : BindingBase
+ {
+ internal const string SelfPath = ".";
+ IValueConverter _converter;
+ object _converterParameter;
+
+ BindingExpression _expression;
+ string _path;
+
+ public TemplateBinding()
+ {
+ }
+
+ public TemplateBinding(string path, BindingMode mode = BindingMode.Default, IValueConverter converter = null, object converterParameter = null, string stringFormat = null)
+ {
+ if (path == null)
+ throw new ArgumentNullException("path");
+ if (string.IsNullOrWhiteSpace(path))
+ throw new ArgumentException("path can not be an empty string", "path");
+
+ AllowChaining = true;
+ Path = path;
+ Converter = converter;
+ ConverterParameter = converterParameter;
+ Mode = mode;
+ StringFormat = stringFormat;
+ }
+
+ public IValueConverter Converter
+ {
+ get { return _converter; }
+ set
+ {
+ ThrowIfApplied();
+
+ _converter = value;
+ }
+ }
+
+ public object ConverterParameter
+ {
+ get { return _converterParameter; }
+ set
+ {
+ ThrowIfApplied();
+
+ _converterParameter = value;
+ }
+ }
+
+ public string Path
+ {
+ get { return _path; }
+ set
+ {
+ ThrowIfApplied();
+
+ _path = value;
+ _expression = GetBindingExpression(value);
+ }
+ }
+
+ internal override void Apply(bool fromTarget)
+ {
+ base.Apply(fromTarget);
+
+ if (_expression == null)
+ _expression = new BindingExpression(this, SelfPath);
+
+ _expression.Apply(fromTarget);
+ }
+
+ internal override async void Apply(object newContext, BindableObject bindObj, BindableProperty targetProperty, bool fromBindingContextChanged = false)
+ {
+ var view = bindObj as Element;
+ if (view == null)
+ throw new InvalidOperationException();
+
+ base.Apply(newContext, bindObj, targetProperty, fromBindingContextChanged);
+
+ Element templatedParent = await TemplateUtilities.FindTemplatedParentAsync(view);
+ ApplyInner(templatedParent, bindObj, targetProperty);
+ }
+
+ internal override BindingBase Clone()
+ {
+ return new TemplateBinding(Path, Mode) { Converter = Converter, ConverterParameter = ConverterParameter, StringFormat = StringFormat };
+ }
+
+ internal override object GetSourceValue(object value, Type targetPropertyType)
+ {
+ if (Converter != null)
+ value = Converter.Convert(value, targetPropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
+
+ return base.GetSourceValue(value, targetPropertyType);
+ }
+
+ internal override object GetTargetValue(object value, Type sourcePropertyType)
+ {
+ if (Converter != null)
+ value = Converter.ConvertBack(value, sourcePropertyType, ConverterParameter, CultureInfo.CurrentUICulture);
+
+ return base.GetTargetValue(value, sourcePropertyType);
+ }
+
+ internal override void Unapply(bool fromBindingContextChanged = false)
+ {
+ base.Unapply(fromBindingContextChanged: fromBindingContextChanged);
+
+ if (_expression != null)
+ _expression.Unapply();
+ }
+
+ void ApplyInner(Element templatedParent, BindableObject bindableObject, BindableProperty targetProperty)
+ {
+ if (_expression == null && templatedParent != null)
+ _expression = new BindingExpression(this, SelfPath);
+
+ _expression?.Apply(templatedParent, bindableObject, targetProperty);
+ }
+
+ BindingExpression GetBindingExpression(string path)
+ {
+ return new BindingExpression(this, !string.IsNullOrWhiteSpace(path) ? path : SelfPath);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+
+namespace Tizen.NUI.Binding
+{
+ internal static class TemplateUtilities
+ {
+ public static async Task<Element> FindTemplatedParentAsync(Element element)
+ {
+ //if (element.RealParent is Application)
+ // return null;
+
+ //var skipCount = 0;
+ //element = await GetRealParentAsync(element);
+ //while (!Application.IsApplicationOrNull(element))
+ //{
+ // var controlTemplated = element as IControlTemplated;
+ // //if (controlTemplated?.ControlTemplate != null)
+ // //{
+ // // if (skipCount == 0)
+ // // return element;
+ // // skipCount--;
+ // //}
+ // // if (element is ContentPresenter)
+ // // skipCount++;
+ // element = await GetRealParentAsync(element);
+ //}
+
+ return null;
+ }
+
+ public static Task<Element> GetRealParentAsync(Element element)
+ {
+ Element parent = element.RealParent;
+ if (parent is Application)
+ return Task.FromResult<Element>(null);
+
+ if (parent != null)
+ return Task.FromResult(parent);
+
+ var tcs = new TaskCompletionSource<Element>();
+ EventHandler handler = null;
+ handler = (sender, args) =>
+ {
+ tcs.TrySetResult(element.RealParent);
+ element.ParentSet -= handler;
+ };
+ element.ParentSet += handler;
+
+ return tcs.Task;
+ }
+
+ public static void OnContentChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var self = (IControlTemplated)bindable;
+ var newElement = (Element)newValue;
+ //if (self.ControlTemplate == null)
+ //{
+ // while (self.InternalChildren.Count > 0)
+ // {
+ // self.InternalChildren.RemoveAt(self.InternalChildren.Count - 1);
+ // }
+
+ // if (newValue != null)
+ // self.InternalChildren.Add(newElement);
+ //}
+ //else
+ //{
+ // if (newElement != null)
+ // {
+ // BindableObject.SetInheritedBindingContext(newElement, bindable.BindingContext);
+ // }
+ //}
+ }
+
+ public static void OnControlTemplateChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var self = (IControlTemplated)bindable;
+
+ // First make sure any old ContentPresenters are no longer bound up. This MUST be
+ // done before we attempt to make the new template.
+ if (oldValue != null)
+ {
+ var queue = new Queue<Element>(16);
+ queue.Enqueue((Element)self);
+
+ while (queue.Count > 0)
+ {
+ ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
+ for (var i = 0; i < children.Count; i++)
+ {
+ Element child = children[i];
+ var controlTemplated = child as IControlTemplated;
+
+ // var presenter = child as ContentPresenter;
+ // if (presenter != null)
+ // presenter.Clear();
+ // else if (controlTemplated == null || controlTemplated.ControlTemplate == null)
+ // queue.Enqueue(child);
+ }
+ }
+ }
+
+ // Now remove all remnants of any other children just to be sure
+ while (self.InternalChildren.Count > 0)
+ {
+ self.InternalChildren.RemoveAt(self.InternalChildren.Count - 1);
+ }
+
+ //ControlTemplate template = self.ControlTemplate;
+ //if (template == null)
+ //{
+ // // do nothing for now
+ //}
+ //else
+ //{
+ // var content = template.CreateContent() as View;
+ // if (content == null)
+ // {
+ // throw new NotSupportedException("ControlTemplate must return a type derived from View.");
+ // }
+
+ // self.InternalChildren.Add(content);
+ // ((IControlTemplated)bindable).OnControlTemplateChanged((ControlTemplate)oldValue, (ControlTemplate)newValue);
+ //}
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.ObjectModel;
+
+namespace Tizen.NUI.Binding
+{
+ internal class TrackableCollection<T> : ObservableCollection<T>
+ {
+ public event EventHandler Clearing;
+
+ protected override void ClearItems()
+ {
+ Clearing?.Invoke(this, EventArgs.Empty);
+ base.ClearItems();
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Globalization;
+
+namespace Tizen.NUI.Binding
+{
+ internal abstract class TypeConverter
+ {
+ public virtual bool CanConvertFrom(Type sourceType)
+ {
+ if (sourceType == null)
+ throw new ArgumentNullException(nameof(sourceType));
+
+ return sourceType == typeof(string);
+ }
+
+ [Obsolete("ConvertFrom is obsolete as of version 2.2.0. Please use ConvertFromInvariantString (string) instead.")]
+ public virtual object ConvertFrom(object o)
+ {
+ return null;
+ }
+
+ [Obsolete("ConvertFrom is obsolete as of version 2.2.0. Please use ConvertFromInvariantString (string) instead.")]
+ public virtual object ConvertFrom(CultureInfo culture, object o)
+ {
+ return null;
+ }
+
+ public virtual object ConvertFromInvariantString(string value)
+ {
+#pragma warning disable 0618 // retain until ConvertFrom removed
+ return ConvertFrom(CultureInfo.InvariantCulture, value);
+#pragma warning restore
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+//
+// System.ComponentModel.TypeConverterAttribute
+//
+// Authors:
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Andreas Nahr (ClassDevelopment@A-SoftTech.com)
+//
+// (C) 2002 Ximian, Inc (http://www.ximian.com)
+// (C) 2003 Andreas Nahr
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace Tizen.NUI.Binding
+{
+ [AttributeUsage(AttributeTargets.All)]
+ internal sealed class TypeConverterAttribute : Attribute
+ {
+ internal static string[] TypeConvertersType = { "Tizen.NUI.Binding.TypeConverterAttribute", "System.ComponentModel.TypeConverterAttribute" };
+
+ public static readonly TypeConverterAttribute Default = new TypeConverterAttribute();
+
+ public TypeConverterAttribute()
+ {
+ ConverterTypeName = "";
+ }
+
+ public TypeConverterAttribute(string typeName)
+ {
+ ConverterTypeName = typeName;
+ }
+
+ public TypeConverterAttribute(Type type)
+ {
+ ConverterTypeName = type.AssemblyQualifiedName;
+ }
+
+ public string ConverterTypeName { get; }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is TypeConverterAttribute))
+ return false;
+
+ return ((TypeConverterAttribute)obj).ConverterTypeName == ConverterTypeName;
+ }
+
+ public override int GetHashCode()
+ {
+ return ConverterTypeName.GetHashCode();
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Globalization;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Binding
+{
+ [Xaml.ProvideCompiled("Tizen.NUI.Xaml.Core.XamlC.TypeTypeConverter")]
+ [Xaml.TypeConversion(typeof(Type))]
+ internal sealed class TypeTypeConverter : TypeConverter, IExtendedTypeConverter
+ {
+ [Obsolete("IExtendedTypeConverter.ConvertFrom is obsolete as of version 2.2.0. Please use ConvertFromInvariantString (string, IServiceProvider) instead.")]
+ object IExtendedTypeConverter.ConvertFrom(CultureInfo culture, object value, IServiceProvider serviceProvider)
+ {
+ return ((IExtendedTypeConverter)this).ConvertFromInvariantString((string)value, serviceProvider);
+ }
+
+ object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceProvider serviceProvider)
+ {
+ if (serviceProvider == null)
+ throw new ArgumentNullException("serviceProvider");
+ var typeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
+ if (typeResolver == null)
+ throw new ArgumentException("No IXamlTypeResolver in IServiceProvider");
+
+ return typeResolver.Resolve(value, serviceProvider);
+ }
+
+ public override object ConvertFromInvariantString(string value)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Diagnostics;
+using System.ComponentModel;
+
+namespace Tizen.NUI
+{
+ [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+ [DebuggerDisplay("{XmlNamespace}, {ClrNamespace}, {AssemblyName}")]
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal sealed class XmlnsDefinitionAttribute : Attribute
+ {
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string XmlNamespace { get; }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string ClrNamespace { get; }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string AssemblyName { get; set; }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int Level { get; set; }
+
+ /// This will be public opened in tizen_5.0 after ACR done. Before ACR, need to be hidden as inhouse API.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public XmlnsDefinitionAttribute(string xmlNamespace, string clrNamespace, int level)
+ {
+ if (xmlNamespace == null)
+ throw new ArgumentNullException(nameof(xmlNamespace));
+ if (clrNamespace == null)
+ throw new ArgumentNullException(nameof(clrNamespace));
+
+ ClrNamespace = clrNamespace;
+ XmlNamespace = xmlNamespace;
+ Level = level;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use ##
+ internal class EXamlAddEvent : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (false == Instance.IsValid)
+ {
+ return "";
+ }
+
+ string ret = "";
+
+ ret += String.Format("({0} ({1} {2} {3} {4}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.AddEvent),
+ eXamlContext.GetValueString(Instance.Index),
+ eXamlContext.GetValueString(Element.Index),
+ eXamlContext.GetValueString(eXamlContext.definedEvents.GetIndex(eventDef.DeclaringType, eventDef)),
+ eXamlContext.GetValueString(eXamlContext.definedMethods.GetIndex(Value.DeclaringType, Value)));
+
+ return ret;
+ }
+
+ public EXamlAddEvent(EXamlContext context, EXamlCreateObject instance, EXamlCreateObject element, string eventName, MethodDefinition value)
+ : base(context)
+ {
+ TypeReference typeref;
+ var eventDef = instance.Type.GetEvent(fi=>fi.Name==eventName, out typeref);
+ if (null != eventDef)
+ {
+ Instance = instance;
+ Element = element;
+ Value = value;
+ DeclaringType = typeref;
+
+ this.eventDef = eventDef;
+
+ Instance.AddEvent(DeclaringType, eventDef);
+
+ eXamlContext.eXamlOperations.Add(this);
+ eXamlContext.eXamlAddEventList.Add(this);
+ }
+ else
+ {
+ throw new Exception("Property is not element");
+ }
+ }
+
+ internal EXamlCreateObject Instance
+ {
+ get;
+ }
+
+ internal EXamlCreateObject Element
+ {
+ get;
+ }
+
+ internal TypeReference DeclaringType
+ {
+ get;
+ }
+
+ internal MethodDefinition Value
+ {
+ get;
+ }
+
+ private EventDefinition eventDef;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use ^^
+ internal class EXamlAddObject : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (false == Parent.IsValid || false == (Child as EXamlCreateObject)?.IsValid)
+ {
+ return "";
+ }
+
+ string ret = String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.AddObject),
+ eXamlContext.GetValueString(Parent.Index),
+ eXamlContext.GetValueString(Child),
+ eXamlContext.GetValueString(eXamlContext.definedMethods.GetIndex(Method.DeclaringType, Method)));
+ return ret;
+ }
+
+ public EXamlAddObject(EXamlContext context, EXamlCreateObject parent, object child, MethodDefinition addMethod)
+ : base(context)
+ {
+ Parent = parent;
+ Child = child;
+ Method = addMethod;
+
+ eXamlContext.eXamlOperations.Add(this);
+ eXamlContext.eXamlAddObjectList.Add(this);
+ }
+
+ public EXamlCreateObject Parent
+ {
+ get;
+ }
+
+ public object Child
+ {
+ get;
+ }
+
+ public MethodDefinition Method
+ {
+ get;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use ~~
+ internal class EXamlAddToCollectionInstance : EXamlOperation
+ {
+ internal override string Write()
+ {
+ string ret = String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.AddToCollectionObject),
+ eXamlContext.GetValueString(instance.Index),
+ eXamlContext.GetValueString(value));
+
+ return ret;
+ }
+
+ public EXamlAddToCollectionInstance(EXamlContext context, EXamlCreateObject instance, object value)
+ : base(context)
+ {
+ this.instance = instance;
+ this.value = value;
+
+ eXamlContext.eXamlOperations.Add(this);
+ }
+
+ private EXamlCreateObject instance;
+ private object value;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use ~~
+ internal class EXamlAddToCollectionProperty : EXamlOperation
+ {
+ internal override string Write()
+ {
+ string ret = String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.AddToCollectionProperty),
+ eXamlContext.GetValueString(instance),
+ eXamlContext.GetValueString(value));
+
+ return ret;
+ }
+
+ public EXamlAddToCollectionProperty(EXamlContext context, EXamlGetObjectByProperty instance, object value)
+ : base(context)
+ {
+ this.instance = instance;
+ this.value = value;
+
+ eXamlContext.eXamlOperations.Add(this);
+ }
+
+ private EXamlGetObjectByProperty instance;
+ private object value;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use %%
+ internal class EXamlAddToResourceDictionary : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (instance.IsValid)
+ {
+ string ret = "";
+ if (null != key)
+ {
+ ret = String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.AddToResourceDictionary),
+ eXamlContext.GetValueString(instance.Index),
+ eXamlContext.GetValueString(key),
+ eXamlContext.GetValueString(value));
+ }
+
+ return ret;
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ public EXamlAddToResourceDictionary(EXamlContext context, EXamlCreateObject @object, string key, object value)
+ : base(context)
+ {
+ instance = @object;
+ this.key = key;
+ this.value = value;
+ eXamlContext.eXamlOperations.Add(this);
+
+ eXamlContext.resourceDictionary.Add(key, value);
+ }
+
+ public EXamlAddToResourceDictionary(EXamlContext context, EXamlCreateObject @object, EXamlCreateObject value)
+ : base(context)
+ {
+ eXamlContext.eXamlOperations.Add(this);
+ }
+
+ private EXamlCreateObject instance;
+ private string key;
+ private object value;
+ }
+}
--- /dev/null
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ internal class EXamlCreateArrayObject : EXamlCreateObject
+ {
+ public EXamlCreateArrayObject(EXamlContext context, TypeReference type, List<object> items) : base(context, null, type)
+ {
+ this.items = items;
+ }
+
+ internal override string Write()
+ {
+ if (false == IsValid)
+ {
+ return "";
+ }
+
+ string itemsString = "";
+ if (0 < items.Count)
+ {
+ itemsString += "(";
+
+ foreach (var item in items)
+ {
+ itemsString += $"{eXamlContext.GetValueString(item)} ";
+ }
+
+ itemsString += ")";
+ }
+
+ string ret = String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.CreateArrayObject),
+ eXamlContext.GetValueString(eXamlContext.GetTypeIndex(Type)),
+ itemsString);
+
+ return ret;
+ }
+
+ private List<object> items;
+ }
+}
--- /dev/null
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ internal class EXamlCreateDPObject : EXamlCreateObject
+ {
+ public EXamlCreateDPObject(EXamlContext context, object value, TypeReference type, string prefix) : base(context, null, type)
+ {
+ this.value = value;
+ this.prefix = prefix;
+ }
+
+ internal override string Write()
+ {
+ if (false == IsValid)
+ {
+ return "";
+ }
+
+ string ret = String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.CreateDPObject),
+ eXamlContext.GetValueString(value.ToString() + prefix),
+ eXamlContext.GetValueString(eXamlContext.GetTypeIndex(Type)));
+
+ return ret;
+ }
+
+ private object value;
+ private string prefix;
+ }
+}
--- /dev/null
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ internal class EXamlCreateDataTemplate : EXamlCreateObject
+ {
+ public EXamlCreateDataTemplate(EXamlContext context, TypeReference type, string content) : base(context, null, type)
+ {
+ indexRangeOfContent = eXamlContext.GetLongStringIndexs(content);
+ }
+
+ private (int, int) indexRangeOfContent;
+
+ internal override string Write()
+ {
+ if (false == IsValid)
+ {
+ return "";
+ }
+
+ string ret = String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.CreateDataTemplate),
+ eXamlContext.GetValueString(eXamlContext.GetTypeIndex(Type)),
+ eXamlContext.GetValueString(indexRangeOfContent.Item1),
+ eXamlContext.GetValueString(indexRangeOfContent.Item2));
+
+ return ret;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use {}
+ internal class EXamlCreateObject : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (false == IsValid)
+ {
+ return "";
+ }
+
+ string ret = "";
+
+ if (true == isStaticInstance)
+ {
+ int typeIndex = eXamlContext.GetTypeIndex(Type);
+
+ if (0 > typeIndex)
+ {
+ throw new Exception($"Can't get type index of {Type.FullName}");
+ }
+
+
+ if (MemberOfStaticInstance is FieldReference field)
+ {
+ ret += String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.GetStaticObject),
+ eXamlContext.GetValueString(typeIndex),
+ eXamlContext.GetValueString(null),
+ eXamlContext.GetValueString(field.Name));
+ }
+ else if (MemberOfStaticInstance is PropertyReference property)
+ {
+ ret += String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.GetStaticObject),
+ eXamlContext.GetValueString(typeIndex),
+ eXamlContext.GetValueString(property.Name),
+ eXamlContext.GetValueString(null));
+ }
+ }
+ else if (true == isTypeObject)
+ {
+ int typeIndex = eXamlContext.GetTypeIndex(Type);
+
+ if (0 > typeIndex)
+ {
+ throw new Exception($"Can't get type index of {Type.FullName}");
+ }
+
+ ret += String.Format("({0} ({1}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.GetTypeObject),
+ eXamlContext.GetValueString(typeIndex));
+ }
+ else
+ {
+ if (Instance is EXamlValueConverterFromString valueConverterFromString)
+ {
+ ret += String.Format("({0} ({1}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.GetObjectConvertedFromString),
+ valueConverterFromString.GetString());
+ }
+ else if (true == Type.Resolve()?.IsEnum)
+ {
+ ret += String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.GetEnumObject),
+ eXamlContext.GetValueString(eXamlContext.GetTypeIndex(Type)),
+ eXamlContext.GetValueString(Instance));
+ }
+ else
+ {
+ int typeIndex = eXamlContext.GetTypeIndex(Type);
+ int xFactoryMethodIndex = -1;
+
+ if (null != XFactoryMethod)
+ {
+ xFactoryMethodIndex = eXamlContext.definedMethods.IndexOf((XFactoryMethod.DeclaringType, XFactoryMethod));
+ }
+
+ if (-1 == typeIndex)
+ {
+ string message = String.Format("Can't find type {0}\n", Type.FullName);
+ throw new Exception(message);
+ }
+
+ string paramsStr = "";
+ if (0 < paramsList.Count)
+ {
+ paramsStr += "(";
+
+ foreach (var param in paramsList)
+ {
+ paramsStr += eXamlContext.GetValueString(param);
+ }
+
+ paramsStr += ")";
+ }
+
+ if (0 < paramsStr.Length)
+ {
+ ret += String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.CreateObject),
+ eXamlContext.GetValueString(typeIndex),
+ eXamlContext.GetValueString(xFactoryMethodIndex),
+ paramsStr);
+ }
+ else
+ {
+ ret += String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.CreateObject),
+ eXamlContext.GetValueString(typeIndex),
+ eXamlContext.GetValueString(xFactoryMethodIndex));
+ }
+ }
+ }
+ return ret;
+ }
+
+ internal new TypeReference GetType()
+ {
+ if (isStaticInstance)
+ {
+ if (MemberOfStaticInstance is FieldReference field)
+ {
+ return field.FieldType;
+ }
+ else if (MemberOfStaticInstance is PropertyReference property)
+ {
+ return property.PropertyType;
+ }
+ else
+ {
+ throw new Exception($"Invalid static instance, type is {Type.FullName}");
+ }
+ }
+ else
+ {
+ return Type;
+ }
+ }
+
+ public EXamlCreateObject(EXamlContext context, object instance, TypeReference type, object[] @params = null)
+ : base(context)
+ {
+ if (null == type?.Resolve())
+ {
+ throw new Exception("Type can't be null when create object");
+ }
+
+ Instance = instance;
+ Type = type;
+
+ if (null != @params)
+ {
+ foreach (var obj in @params)
+ {
+ paramsList.Add(obj);
+ }
+ }
+
+ eXamlContext.eXamlOperations.Add(this);
+
+ Index = eXamlContext.eXamlCreateObjects.Count;
+ eXamlContext.eXamlCreateObjects.Add(this);
+ }
+
+ public EXamlCreateObject(EXamlContext context, TypeReference type) : base(context)
+ {
+ isTypeObject = true;
+ Type = type;
+
+ eXamlContext.eXamlOperations.Add(this);
+
+ Index = eXamlContext.eXamlCreateObjects.Count;
+ eXamlContext.eXamlCreateObjects.Add(this);
+ }
+
+ public EXamlCreateObject(EXamlContext context, object instance, TypeReference type, MethodDefinition xFactoryMethod, object[] @params = null)
+ : base(context)
+ {
+ if (null == type.Resolve())
+ {
+ throw new Exception("Type can't be null when create object");
+ }
+
+ Instance = instance;
+ Type = type;
+
+ if (null != @params)
+ {
+ foreach (var obj in @params)
+ {
+ paramsList.Add(obj);
+ }
+ }
+
+ eXamlContext.eXamlOperations.Add(this);
+
+ Index = eXamlContext.eXamlCreateObjects.Count;
+ XFactoryMethod = xFactoryMethod;
+ eXamlContext.eXamlCreateObjects.Add(this);
+ }
+
+ public static EXamlCreateObject GetStaticInstance(EXamlContext context, TypeReference type, FieldReference field, PropertyReference property)
+ {
+ MemberReference memberRef = null;
+
+ if (null != field)
+ {
+ memberRef = field;
+ }
+ else if (null != property)
+ {
+ memberRef = property;
+ }
+
+ if (null == memberRef)
+ {
+ return null;
+ }
+
+ if (context.StaticInstances.ContainsKey((type, memberRef)))
+ {
+ return context.StaticInstances[(type, memberRef)];
+ }
+ else
+ {
+ var staticInstance = new EXamlCreateObject(context, type, field, property);
+ context.StaticInstances.Add((type, memberRef), staticInstance);
+ return staticInstance;
+ }
+ }
+
+ public EXamlCreateObject(EXamlContext context, TypeReference type, FieldReference field, PropertyReference property)
+ : base(context)
+ {
+ MemberReference memberRef = null;
+
+ if (null != field)
+ {
+ memberRef = field;
+ }
+ else if (null != property)
+ {
+ memberRef = property;
+ }
+
+ Type = type;
+ MemberOfStaticInstance = memberRef;
+ isStaticInstance = true;
+
+ eXamlContext.eXamlOperations.Add(this);
+
+ Index = eXamlContext.eXamlCreateObjects.Count;
+ eXamlContext.eXamlCreateObjects.Add(this);
+ }
+
+ internal bool IsValid
+ {
+ get;
+ set;
+ } = true;
+
+ internal object Instance
+ {
+ get;
+ private set;
+ }
+
+ internal TypeReference Type
+ {
+ get;
+ }
+
+ internal int Index
+ {
+ get;
+ set;
+ }
+
+ internal MethodDefinition XFactoryMethod
+ {
+ get;
+ set;
+ }
+
+ internal MemberReference MemberOfStaticInstance
+ {
+ get;
+ set;
+ }
+
+ internal List<object> paramsList
+ {
+ get;
+ } = new List<object>();
+
+ internal EXamlDefinitionList<PropertyDefinition> PropertyList
+ {
+ get;
+ } = new EXamlDefinitionList<PropertyDefinition>();
+
+ internal EXamlDefinitionList<EventDefinition> EventList
+ {
+ get;
+ } = new EXamlDefinitionList<EventDefinition>();
+
+ internal HashSet<IMemberDefinition> BindableProperties
+ {
+ get;
+ } = new HashSet<IMemberDefinition>();
+
+ internal void AddProperty(TypeReference declareTypeRef, PropertyDefinition property)
+ {
+ PropertyList.Add(declareTypeRef, property);
+ }
+
+ internal void AddEvent(TypeReference declareTypeRef, EventDefinition eventDefinition)
+ {
+ EventList.Add(declareTypeRef, eventDefinition);
+ }
+
+ internal void AddBindableProperty(MemberReference bindalbeProperty)
+ {
+ if (!BindableProperties.Contains(bindalbeProperty.Resolve()))
+ {
+ BindableProperties.Add(bindalbeProperty.Resolve());
+ }
+ }
+
+ private bool isStaticInstance = false;
+
+ private bool isTypeObject = false;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use ``
+ internal class EXamlGetObjectByProperty : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (instance.IsValid)
+ {
+ string ret = String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.GetObjectByProperty),
+ eXamlContext.GetValueString(instance.Index),
+ eXamlContext.GetValueString(propertyName));
+
+ return ret;
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ internal EXamlGetObjectByProperty(EXamlContext context, EXamlCreateObject instance, string propertyName)
+ : base(context)
+ {
+ this.instance = instance;
+ this.propertyName = propertyName;
+ eXamlContext.objectsAccordingToProperty.Add(this);
+
+ eXamlContext.eXamlOperations.Add(this);
+ }
+
+ private EXamlCreateObject instance;
+ private string propertyName;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.EXaml
+{
+ internal abstract class EXamlOperation
+ {
+ public EXamlOperation(EXamlContext eXamlContext)
+ {
+ this.eXamlContext = eXamlContext;
+ }
+
+ internal EXamlContext eXamlContext;
+
+ internal static void WriteOpertions(string filePath, EXamlContext eXamlContext)
+ {
+ var ret = eXamlContext.GenerateEXamlString();
+ if(string.IsNullOrEmpty(filePath))
+ {
+ throw new Exception("filePath is empty or null!");
+ }
+ /*Avoid the difference of '/' in file path on windows and linux*/
+ filePath = filePath.Replace("\\", "/");
+ if (filePath.Contains("/"))
+ {
+ OutputDir = filePath.Substring(0, filePath.LastIndexOf("/"));
+ }
+ if (!Directory.Exists(OutputDir))
+ {
+ Directory.CreateDirectory(OutputDir);
+ }
+
+ var stream = File.CreateText(filePath);
+ stream.Write(ret);
+ stream.Close();
+ }
+
+ public static string OutputDir
+ {
+ get;
+ private set;
+ }
+
+ internal abstract string Write();
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use &&
+ internal class EXamlRegisterXName : EXamlOperation
+ {
+ internal override string Write()
+ {
+ string ret = String.Format("({0} ({1} {2}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.RegisterXName),
+ eXamlContext.GetValueString(Instance),
+ eXamlContext.GetValueString(XName));
+
+ return ret;
+ }
+
+ public EXamlRegisterXName(EXamlContext context, object @object, string xName)
+ : base(context)
+ {
+ Instance = @object;
+ XName = xName;
+ eXamlContext.eXamlOperations.Add(this);
+
+ eXamlContext.xNameToInstance.Add(xName, @object);
+ }
+
+ public object Instance
+ {
+ get;
+ }
+
+ public string XName
+ {
+ get;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use !!
+ internal class EXamlSetBindalbeProperty : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (false == Instance.IsValid)
+ {
+ return "";
+ }
+
+ string ret = String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.SetBindableProperty),
+ eXamlContext.GetValueString(Instance.Index),
+ eXamlContext.GetValueString(eXamlContext.definedBindableProperties.IndexOf(BindableProperty.Resolve())),
+ eXamlContext.GetValueString(Value));
+
+ return ret;
+ }
+
+ public EXamlSetBindalbeProperty(EXamlContext context, EXamlCreateObject @object, MemberReference bindableProperty, object value)
+ : base(context)
+ {
+ Instance = @object;
+ BindableProperty = bindableProperty;
+ Value = value;
+
+ Instance.AddBindableProperty(bindableProperty);
+
+ eXamlContext.eXamlOperations.Add(this);
+ }
+
+ public EXamlCreateObject Instance
+ {
+ get;
+ private set;
+ }
+
+ public MemberReference BindableProperty
+ {
+ get;
+ private set;
+ }
+
+ public object Value
+ {
+ get;
+ private set;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use **
+ internal class EXamlSetBinding : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (Instance.IsValid)
+ {
+ string ret = String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.SetBinding),
+ eXamlContext.GetValueString(Instance.Index),
+ eXamlContext.GetValueString(eXamlContext.definedBindableProperties.IndexOf(BindableProperty.Resolve())),
+ eXamlContext.GetValueString(Value.Index));
+
+ return ret;
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ public EXamlSetBinding(EXamlContext context, EXamlCreateObject @object, MemberReference bindableProperty, object binding)
+ : base(context)
+ {
+ Instance = @object;
+ BindableProperty = bindableProperty;
+ Value = binding as EXamlCreateObject;
+ if (null == Value)
+ {
+ throw new Exception($"Can't set binding {binding.ToString()} to {bindableProperty.FullName}");
+ }
+ eXamlContext.eXamlOperations.Add(this);
+
+ Instance.AddBindableProperty(bindableProperty);
+ }
+
+ public EXamlCreateObject Instance
+ {
+ get;
+ }
+
+ public MemberReference BindableProperty
+ {
+ get;
+ }
+
+ public EXamlCreateObject Value
+ {
+ get;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use $$
+ internal class EXamlSetDynamicResource : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (@object.IsValid)
+ {
+ string ret = String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.SetDynamicResource),
+ eXamlContext.GetValueString(@object.Index),
+ eXamlContext.GetValueString(eXamlContext.definedBindableProperties.IndexOf(bindableProperty.Resolve())),
+ eXamlContext.GetValueString(key));
+ return ret;
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+ public EXamlSetDynamicResource(EXamlContext context, EXamlCreateObject @object, MemberReference bindalbeProperty, string key)
+ : base(context)
+ {
+ this.@object = @object;
+ this.bindableProperty = bindalbeProperty;
+ this.key = key;
+ eXamlContext.eXamlOperations.Add(this);
+
+ @object.AddBindableProperty(bindableProperty);
+ }
+
+ private EXamlCreateObject @object;
+ private MemberReference bindableProperty;
+ private string key;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ //use []
+ internal class EXamlSetProperty : EXamlOperation
+ {
+ internal override string Write()
+ {
+ if (false == instance.IsValid)
+ {
+ return "";
+ }
+
+ string ret = String.Format("({0} ({1} {2} {3}))\n",
+ eXamlContext.GetValueString((int)EXamlOperationType.SetProperty),
+ eXamlContext.GetValueString(instance.Index),
+ eXamlContext.GetValueString(eXamlContext.definedProperties.GetIndex(property.DeclaringType, property)),
+ eXamlContext.GetValueString(value));
+
+ return ret;
+ }
+
+ public EXamlSetProperty(EXamlContext context, EXamlCreateObject instance, string propertyName, object value)
+ : base(context)
+ {
+ var property = instance.Type.GetProperty(fi=>fi.Name==propertyName, out declareTypeRef);
+ if (null != property)
+ {
+ this.instance = instance;
+ this.property = property;
+ this.value = value;
+
+ if (null != this.instance.Instance)
+ {
+ var propertyInfo = this.instance.Instance.GetType().GetProperty(property.Name);
+
+ if (value is EXamlCreateObject eXamlCreateObject && null != eXamlCreateObject.Instance)
+ {
+ if (this.instance.Instance is BindingExtension bindingExtension
+ &&
+ eXamlCreateObject.Type.FullName == typeof(BindingMode).FullName)
+ {
+ bindingExtension.ModeInEXaml = eXamlCreateObject;
+ }
+ else if (eXamlCreateObject.Type.ResolveCached().IsEnum)
+ {
+ if (eXamlCreateObject.Type.FullName == typeof(BindingMode).FullName)
+ {
+ var realValue = Enum.Parse(typeof(BindingMode), eXamlCreateObject.Instance as string);
+ propertyInfo.SetMethod.Invoke(this.instance.Instance, new object[] { realValue });
+ }
+ }
+ else
+ {
+ if (instance.GetType().FullName == typeof(Xaml.Build.Tasks.ArrayExtension).FullName
+ &&
+ "Type" == propertyName)
+ {
+ eXamlCreateObject.IsValid = false;
+ }
+
+ propertyInfo.SetMethod.Invoke(this.instance.Instance, new object[] { eXamlCreateObject.Instance });
+ }
+ }
+ else
+ {
+ propertyInfo.SetMethod.Invoke(this.instance.Instance, new object[] { value });
+ }
+ }
+
+ this.instance.AddProperty(declareTypeRef, property);
+
+ eXamlContext.eXamlOperations.Add(this);
+ }
+ else
+ {
+ throw new Exception("Property is not element");
+ }
+ }
+
+ private EXamlCreateObject instance;
+ private TypeReference declareTypeRef;
+ private PropertyDefinition property;
+ private object value;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml
+{
+ internal class EXamlValueConverterFromString
+ {
+ private EXamlContext context;
+
+ internal string GetString()
+ {
+ string ret = "";
+ ret += String.Format("{0} {1}", context.GetValueString(converterInstance), context.GetValueString(Value));
+ return ret;
+ }
+
+ internal EXamlValueConverterFromString(EXamlContext context, TypeDefinition converterType, string value)
+ {
+ this.context = context;
+
+ ConverterType = converterType;
+ Value = value;
+
+ if (!context.typeToInstance.ContainsKey(converterType))
+ {
+ converterInstance = new EXamlCreateObject(context, null, converterType);
+ context.typeToInstance.Add(converterType, converterInstance);
+ }
+ else
+ {
+ converterInstance = context.typeToInstance[converterType];
+ }
+ }
+
+ internal TypeDefinition ConverterType
+ {
+ get;
+ private set;
+ }
+
+ internal string Value
+ {
+ get;
+ private set;
+ }
+
+ private EXamlCreateObject converterInstance;
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ internal class EXamlContext
+ {
+ public EXamlContext(TypeDefinition type, ModuleDefinition module, FieldDefinition parentContextValues = null)
+ {
+ Values = new Dictionary<INode, object>();
+ Variables = new Dictionary<IElementNode, VariableDefinition>();
+ Scopes = new Dictionary<INode, Tuple<VariableDefinition, IList<string>>>();
+ TypeExtensions = new Dictionary<INode, TypeReference>();
+ ParentContextValues = parentContextValues;
+ Type = type;
+ Module = module;
+ }
+
+ public Dictionary<INode, object> Values { get; private set; }
+
+ public Dictionary<IElementNode, VariableDefinition> Variables { get; private set; }
+
+ public Dictionary<INode, Tuple<VariableDefinition, IList<string>>> Scopes { get; private set; }
+
+ public Dictionary<INode, TypeReference> TypeExtensions { get; }
+
+ public FieldDefinition ParentContextValues { get; private set; }
+
+ public object Root { get; set; } //FieldDefinition or VariableDefinition
+
+ public INode RootNode { get; set; }
+
+ public TypeDefinition Type { get; set; }
+
+ public ModuleDefinition Module { get; private set; }
+
+ public List<EXamlOperation> eXamlOperations = new List<EXamlOperation>();
+
+ private string GetAssemblyName(AssemblyDefinition assembly)
+ {
+ string assemblyName = "";
+ if (assembly.FullName.StartsWith("Tizen.NUI.XamlBuild"))
+ {
+ assemblyName = "Tizen.NUI";
+ }
+ else
+ {
+ assemblyName = assembly.FullName;
+
+ if (assemblyName.EndsWith(".dll"))
+ {
+ assemblyName = assemblyName.Substring(0, assemblyName.Length - ".dll".Length);
+ }
+ else if (assemblyName.EndsWith(".exe"))
+ {
+ assemblyName = assemblyName.Substring(0, assemblyName.Length - ".exe".Length);
+ }
+ else
+ {
+ int firstIndex = assemblyName.IndexOf(',');
+ assemblyName = assemblyName.Substring(0, firstIndex);
+ }
+
+ if ("Tizen.NUI.Xaml" == assemblyName)
+ {
+ assemblyName = "Tizen.NUI";
+ }
+ }
+
+ return assemblyName + ", ";
+ }
+
+ private string GetAssemblyName(Assembly assembly)
+ {
+ string assemblyName = "";
+ if (assembly.FullName == typeof(EXamlOperation).Assembly.FullName)
+ {
+ assemblyName = "Tizen.NUI";
+ }
+ else
+ {
+ assemblyName = assembly.FullName;
+
+ if (assemblyName.Substring(assemblyName.Length - ".dll".Length) == ".dll")
+ {
+ assemblyName = assemblyName.Substring(0, assemblyName.Length - ".dll".Length);
+ }
+ else if (assemblyName.Substring(assemblyName.Length - ".exe".Length) == ".exe")
+ {
+ assemblyName = assemblyName.Substring(0, assemblyName.Length - ".exe".Length);
+ }
+
+ if ("Tizen.NUI.Xaml" == assemblyName)
+ {
+ assemblyName = "Tizen.NUI";
+ }
+ }
+
+ return assemblyName + ", ";
+ }
+
+ private List<string> definedAssemblies
+ {
+ get;
+ } = new List<string>();
+
+ private List<TypeData> definedTypes
+ {
+ get;
+ } = new List<TypeData>();
+
+ internal EXamlDefinitionList<PropertyDefinition> definedProperties
+ {
+ get;
+ } = new EXamlDefinitionList<PropertyDefinition>();
+
+ internal EXamlDefinitionList<EventDefinition> definedEvents
+ {
+ get;
+ } = new EXamlDefinitionList<EventDefinition>();
+
+ internal List<IMemberDefinition> definedBindableProperties
+ {
+ get;
+ } = new List<IMemberDefinition>();
+
+ internal EXamlDefinitionList<MethodDefinition> definedMethods
+ {
+ get;
+ } = new EXamlDefinitionList<MethodDefinition>();
+
+ #region Data of CreateObject
+ internal List<EXamlCreateObject> eXamlCreateObjects
+ {
+ get;
+ } = new List<EXamlCreateObject>();
+
+ internal Dictionary<(TypeReference, MemberReference), EXamlCreateObject> StaticInstances
+ {
+ get;
+ } = new Dictionary<(TypeReference, MemberReference), EXamlCreateObject>();
+ #endregion
+
+ #region Data of AddObject
+ internal List<EXamlAddObject> eXamlAddObjectList
+ {
+ get;
+ } = new List<EXamlAddObject>();
+ #endregion
+
+ #region ConvertValue
+ internal Dictionary<TypeDefinition, EXamlCreateObject> typeToInstance
+ {
+ get;
+ } = new Dictionary<TypeDefinition, EXamlCreateObject>();
+ #endregion
+
+ #region Data of AddEvent
+ internal List<EXamlAddEvent> eXamlAddEventList
+ {
+ get;
+ } = new List<EXamlAddEvent>();
+ #endregion
+
+ #region Data of Register XName
+ internal Dictionary<string, object> xNameToInstance
+ {
+ get;
+ } = new Dictionary<string, object>();
+
+ internal object GetObjectByXName(string xName)
+ {
+ object ret = null;
+ xNameToInstance.TryGetValue(xName, out ret);
+ return ret;
+ }
+ #endregion
+
+ #region Data of Add Resource to Dictionary
+ internal Dictionary<string, object> resourceDictionary
+ {
+ get;
+ } = new Dictionary<string, object>();
+ #endregion
+
+ #region Data of Get object by property
+ internal List<EXamlGetObjectByProperty> objectsAccordingToProperty = new List<EXamlGetObjectByProperty>();
+
+ private int GetIndex(EXamlGetObjectByProperty eXamlObjectFromProperty)
+ {
+ return objectsAccordingToProperty.IndexOf(eXamlObjectFromProperty);
+ }
+ #endregion
+
+ public string GenerateEXamlString()
+ {
+ string ret = "";
+
+ int objectIndex = 0;
+
+ foreach (var examlOp in eXamlCreateObjects)
+ {
+ if (examlOp.IsValid)
+ {
+ examlOp.Index = objectIndex++;
+ }
+ }
+
+ foreach (var examlOp in eXamlCreateObjects)
+ {
+ if (examlOp.IsValid)
+ {
+ GatherType(examlOp.Type);
+
+ foreach (var property in examlOp.PropertyList)
+ {
+ GatherType(property.Item1);
+
+ definedProperties.Add(property.Item1, property.Item2);
+
+ if (true == property.Item1.Resolve()?.IsEnum)
+ {
+ GatherType(property.Item1.Resolve());
+ }
+ }
+
+ foreach (var eventDef in examlOp.EventList)
+ {
+ GatherType(eventDef.Item1);
+
+ definedEvents.Add(eventDef.Item1, eventDef.Item2);
+ }
+
+ foreach (var property in examlOp.BindableProperties)
+ {
+ if (!definedBindableProperties.Contains(property))
+ {
+ definedBindableProperties.Add(property);
+ }
+
+ var typeDef = property.DeclaringType;
+ if (-1 == GetTypeIndex(typeDef))
+ {
+ GatherType(property.DeclaringType);
+ }
+ }
+
+ foreach (var param in examlOp.paramsList)
+ {
+ if (null != param && param.GetType().IsEnum)
+ {
+ GatherType(param.GetType());
+ }
+ }
+
+ if (null != examlOp.XFactoryMethod)
+ {
+ GatherMethod((examlOp.XFactoryMethod.DeclaringType, examlOp.XFactoryMethod));
+ }
+ }
+ }
+
+ foreach (var op in eXamlAddObjectList)
+ {
+ if (op.Parent.IsValid && (!(op.Child is EXamlCreateObject eXamlCreateObject) || eXamlCreateObject.IsValid))
+ {
+ GatherMethod((op.Method.DeclaringType, op.Method));
+ }
+ }
+
+ foreach (var op in eXamlAddEventList)
+ {
+ if (op.Instance.IsValid)
+ {
+ GatherMethod((op.Value.DeclaringType, op.Value));
+ }
+ }
+
+ foreach (var ass in definedAssemblies)
+ {
+ ret += String.Format("({0} ({1}))\n",
+ GetValueString((int)EXamlOperationType.GatherAssembly),
+ GetValueString(ass));
+ }
+
+ foreach (var type in definedTypes)
+ {
+ ret += String.Format("({0} {1})\n",
+ GetValueString((int)EXamlOperationType.GatherType),
+ type.ConvertToString(definedAssemblies, definedTypes));
+ }
+
+ foreach (var property in definedProperties)
+ {
+ var typeDef = property.Item1;
+ int typeIndex = GetTypeIndex(typeDef);
+ ret += String.Format("({0} ({1} {2}))\n",
+ GetValueString((int)EXamlOperationType.GatherProperty),
+ GetValueString(typeIndex),
+ GetValueString(property.Item2.Name));
+ }
+
+ foreach (var eventDef in definedEvents)
+ {
+ var typeDef = eventDef.Item1;
+ int typeIndex = GetTypeIndex(typeDef);
+ ret += String.Format("({0} ({1} {2}))\n",
+ GetValueString((int)EXamlOperationType.GatherEvent),
+ GetValueString(typeIndex),
+ GetValueString(eventDef.Item2.Name));
+ }
+
+ foreach (var method in definedMethods)
+ {
+ var typeDef = method.Item1;
+ int typeIndex = GetTypeIndex(typeDef);
+
+ string strForParam = "(";
+ foreach (var param in method.Item2.Parameters)
+ {
+ int paramTypeIndex = GetTypeIndex(param.ParameterType);
+
+ if (-1 == paramTypeIndex)
+ {
+ throw new Exception($"Can't find index of param type {param.ParameterType.FullName}");
+ }
+
+ strForParam += GetValueString(paramTypeIndex) + " ";
+ }
+ strForParam += ")";
+
+ ret += String.Format("({0} ({1} {2} {3}))\n",
+ GetValueString((int)EXamlOperationType.GatherMethod),
+ GetValueString(typeIndex),
+ GetValueString(method.Item2.Name),
+ strForParam);
+ }
+
+ foreach (var property in definedBindableProperties)
+ {
+ var typeDef = property.DeclaringType;
+ int typeIndex = GetTypeIndex(typeDef);
+ ret += String.Format("({0} ({1} {2}))\n",
+ GetValueString((int)EXamlOperationType.GatherBindableProperty),
+ GetValueString(typeIndex),
+ GetValueString(property.Name));
+ }
+
+ foreach (var op in eXamlOperations)
+ {
+ ret += op.Write();
+ }
+
+ if (0 < longStrings.Length)
+ {
+ ret += String.Format("({0} ({1}))\n",
+ GetValueString((int)EXamlOperationType.GetLongString),
+ GetValueString(longStrings));
+ }
+
+ return ret;
+ }
+
+ private void GatherType(TypeReference typeRef)
+ {
+ if (-1 == GetTypeIndex(typeRef))
+ {
+ var assemblyName = GetAssemblyName(typeRef.Resolve().Module.Assembly);
+ if (!definedAssemblies.Contains(assemblyName))
+ {
+ definedAssemblies.Add(assemblyName);
+ }
+
+ var typeData = new TypeData(typeRef, GetAssemblyName(typeRef.Resolve().Module.Assembly));
+
+ if (typeRef is GenericInstanceType genericType)
+ {
+ foreach (var type in genericType.GenericArguments)
+ {
+ GatherType(type);
+ }
+ }
+ definedTypes.Add(typeData);
+ }
+ }
+
+ private void GatherType(Type type)
+ {
+ var assemblyName = GetAssemblyName(type.Assembly);
+ if (!definedAssemblies.Contains(assemblyName))
+ {
+ definedAssemblies.Add(assemblyName);
+ }
+
+ if (-1 == GetTypeIndex(type))
+ {
+ definedTypes.Add(new TypeData(type, GetAssemblyName(type.Assembly)));
+ }
+ }
+
+ private void GatherMethod((TypeReference, MethodDefinition) methodInfo)
+ {
+ GatherType(methodInfo.Item1);
+
+ foreach (var param in methodInfo.Item2.Parameters)
+ {
+ GatherType(param.ParameterType);
+ }
+
+ definedMethods.Add(methodInfo.Item1, methodInfo.Item2);
+ }
+
+ private int GetTypeIndex(TypeData typeData)
+ {
+ if (null != typeData.TypeReference)
+ {
+ return GetTypeIndex(typeData.TypeReference);
+ }
+
+ if (null != typeData.Type)
+ {
+ return GetTypeIndex(typeData.Type);
+ }
+
+ return -1;
+ }
+
+ internal int GetTypeIndex(TypeReference typeReference)
+ {
+ for (int i = 0; i < definedTypes.Count; i++)
+ {
+ if (EXamlUtility.IsSameTypeReference(typeReference, definedTypes[i].TypeReference))
+ {
+ return i;
+ }
+ }
+
+ int ret = -1;
+ switch (typeReference.FullName)
+ {
+ case "System.SByte":
+ ret = -2;
+ break;
+ case "System.Int16":
+ ret = -3;
+ break;
+ case "System.Int32":
+ ret = -4;
+ break;
+ case "System.Int64":
+ ret = -5;
+ break;
+ case "System.Byte":
+ ret = -6;
+ break;
+ case "System.UInt16":
+ ret = -7;
+ break;
+ case "System.UInt32":
+ ret = -8;
+ break;
+ case "System.UInt64":
+ ret = -9;
+ break;
+ case "System.Boolean":
+ ret = -10;
+ break;
+ case "System.String":
+ ret = -11;
+ break;
+ case "System.Object":
+ ret = -12;
+ break;
+ case "System.Char":
+ ret = -13;
+ break;
+ case "System.Decimal":
+ ret = -14;
+ break;
+ case "System.Single":
+ ret = -15;
+ break;
+ case "System.Double":
+ ret = -16;
+ break;
+ case "System.TimeSpan":
+ ret = -17;
+ break;
+ case "System.Uri":
+ ret = -18;
+ break;
+ }
+
+ return ret;
+ }
+
+ internal static int GetTypeIndex(TypeData type, List<TypeData> definedTypes)
+ {
+ for (int i = 0; i < definedTypes.Count; i++)
+ {
+ if (EXamlUtility.IsSameTypeReference(type.TypeReference, definedTypes[i].TypeReference))
+ {
+ return i;
+ }
+ }
+
+ int ret = -1;
+ switch (type.TypeReference.FullName)
+ {
+ case "System.SByte":
+ ret = -2;
+ break;
+ case "System.Int16":
+ ret = -3;
+ break;
+ case "System.Int32":
+ ret = -4;
+ break;
+ case "System.Int64":
+ ret = -5;
+ break;
+ case "System.Byte":
+ ret = -6;
+ break;
+ case "System.UInt16":
+ ret = -7;
+ break;
+ case "System.UInt32":
+ ret = -8;
+ break;
+ case "System.UInt64":
+ ret = -9;
+ break;
+ case "System.Boolean":
+ ret = -10;
+ break;
+ case "System.String":
+ ret = -11;
+ break;
+ case "System.Object":
+ ret = -12;
+ break;
+ case "System.Char":
+ ret = -13;
+ break;
+ case "System.Decimal":
+ ret = -14;
+ break;
+ case "System.Single":
+ ret = -15;
+ break;
+ case "System.Double":
+ ret = -16;
+ break;
+ case "System.TimeSpan":
+ ret = -17;
+ break;
+ case "System.Uri":
+ ret = -18;
+ break;
+ }
+
+ return ret;
+ }
+
+ private int GetTypeIndex(Type type)
+ {
+ for (int i = 0; i < definedTypes.Count; i++)
+ {
+ if (type == definedTypes[i].Type)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ internal (int, int) GetLongStringIndexs(string longString)
+ {
+ if (longStringToIndexPair.ContainsKey(longString))
+ {
+ return longStringToIndexPair[longString];
+ }
+ else
+ {
+ var indexPair = (longStrings.Length, 0);
+ longStrings += longString;
+ indexPair.Item2 = longStrings.Length - 1;
+
+ longStringToIndexPair.Add(longString, indexPair);
+ return indexPair;
+ }
+ }
+
+ private string longStrings = "";
+ private Dictionary<string, (int, int)> longStringToIndexPair = new Dictionary<string, (int, int)>();
+
+ internal string GetValueString(object valueObject)
+ {
+ //Fang: How to deal the Enum
+ string ret = "";
+
+ if (null == valueObject)
+ {
+ ret += "zz ";
+ }
+ else if (valueObject is List<object> listObjects)
+ {
+ ret += "(";
+
+ foreach (var obj in listObjects)
+ {
+ ret += GetValueString(obj);
+ ret += " ";
+ }
+
+ ret += ")";
+ }
+ else
+ {
+ //Fang
+ var paramType = valueObject.GetType();
+
+ string signBegin = "a", signEnd = "a";
+ string value = "";
+
+ if (valueObject is EXamlCreateObject)
+ {
+ signBegin = signEnd = "a";
+ value = (valueObject as EXamlCreateObject).Index.ToString();
+ }
+ else if (valueObject is EXamlGetObjectByProperty)
+ {
+ return GetValueString(GetIndex(valueObject as EXamlGetObjectByProperty));
+ }
+ else if (paramType == typeof(string) || paramType == typeof(Uri))
+ {
+ signBegin = signEnd = "\"";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(char))
+ {
+ signBegin = signEnd = "\'";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(SByte))
+ {
+ signBegin = signEnd = "b";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(Int16))
+ {
+ signBegin = signEnd = "c";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(Int32))
+ {
+ signBegin = signEnd = "d";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(Int64))
+ {
+ signBegin = signEnd = "e";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(Byte))
+ {
+ signBegin = signEnd = "f";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(UInt16))
+ {
+ signBegin = signEnd = "g";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(UInt32))
+ {
+ signBegin = signEnd = "h";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(UInt64))
+ {
+ signBegin = signEnd = "i";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(Single))
+ {
+ signBegin = signEnd = "j";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(Double))
+ {
+ signBegin = signEnd = "k";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(TimeSpan))
+ {
+ signBegin = signEnd = "l";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(Boolean))
+ {
+ signBegin = signEnd = "m";
+ value = valueObject.ToString();
+ }
+ else if (paramType == typeof(decimal))
+ {
+ signBegin = signEnd = "n";
+ value = valueObject.ToString();
+ }
+ else if (paramType.IsEnum)
+ {
+ signBegin = "o(";
+ int typeIndex = GetTypeIndex(paramType);
+ value = String.Format("d{0}d \"{1}\"", typeIndex, valueObject.ToString());
+ signEnd = ")o";
+ }
+ else if (valueObject is EXamlValueConverterFromString)
+ {
+ signBegin = "q(";
+ signEnd = ")q";
+ value = (valueObject as EXamlValueConverterFromString).GetString();
+ }
+
+ ret += String.Format("{0}{1}{2} ", signBegin, value, signEnd);
+ }
+
+ return ret;
+ }
+ }
+
+ internal class TypeData
+ {
+ internal TypeData(Type type, string assemblyName)
+ {
+ Type = type;
+ AssemblyName = assemblyName;
+
+ if (type.IsNested)
+ {
+ FullName = type.FullName.Replace('/', '+');
+ }
+ else
+ {
+ FullName = type.FullName;
+ }
+ }
+
+ internal TypeData(TypeReference typeReference, string assemblyName)
+ {
+ TypeReference = typeReference;
+
+ AssemblyName = assemblyName;
+
+ if (typeReference is GenericInstanceType genericType)
+ {
+ GenericArgumentTypes = new List<TypeData>();
+ foreach (var type in genericType.GenericArguments)
+ {
+ GenericArgumentTypes.Add(new TypeData(type, AssemblyName));
+ }
+ FullName = typeReference.Resolve().FullName;
+ }
+ else
+ {
+ FullName = typeReference.FullName;
+ }
+
+ if (typeReference.IsNested)
+ {
+ FullName = FullName.Replace('/', '+');
+ }
+ }
+
+ public string ConvertToString(List<string> definedAssemblies, List<TypeData> typeDatas)
+ {
+ string ret = "";
+ int assemblyIndex = definedAssemblies.IndexOf(AssemblyName);
+
+ if (null == GenericArgumentTypes)
+ {
+ ret += String.Format("(d{0}d \"{1}\")", assemblyIndex, FullName);
+ }
+ else
+ {
+ string strForGenericTypes = "(";
+
+ foreach (var type in GenericArgumentTypes)
+ {
+ strForGenericTypes += "d" + EXamlContext.GetTypeIndex(type, typeDatas) + "d ";
+ }
+
+ strForGenericTypes += ")";
+
+ ret += String.Format("(d{0}d \"{1}\" {2})", assemblyIndex, FullName, strForGenericTypes);
+ }
+
+ return ret;
+ }
+
+ internal TypeReference TypeReference
+ {
+ get;
+ }
+
+ internal Type Type
+ {
+ get;
+ }
+
+ internal string AssemblyName
+ {
+ get;
+ }
+
+ internal string FullName
+ {
+ get;
+ }
+
+ internal List<TypeData> GenericArgumentTypes
+ {
+ get;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using System.Xml;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+using Tizen.NUI.Xaml.Build.Tasks;
+using ArrayExtension = Tizen.NUI.Xaml.Build.Tasks.ArrayExtension;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ class EXamlCreateObjectVisitor : IXamlNodeVisitor
+ {
+ public EXamlCreateObjectVisitor(EXamlContext context)
+ {
+ Context = context;
+ Module = context.Module;
+ }
+
+ public EXamlContext Context { get; }
+
+ ModuleDefinition Module { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ Context.Values[node] = node.Value;
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ //At this point, all MarkupNodes are expanded to ElementNodes
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ var typeref = Module.ImportReference(node.XmlType.GetTypeReference(Module, node));
+
+ if (IsXaml2009LanguagePrimitive(node))
+ {
+ var vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+
+ var value = GetValueFromLanguagePrimitive(typeref, node);
+
+ Context.Values[node] = value;
+ return;
+ }
+
+ TypeDefinition typedef = typeref.ResolveCached();
+
+ //if this is a MarkupExtension that can be compiled directly, compile and returns the value
+ var compiledMarkupExtensionName = typeref
+ .GetCustomAttribute(Module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "ProvideCompiledAttribute"))
+ ?.ConstructorArguments?[0].Value as string;
+ Type compiledMarkupExtensionType;
+ ICompiledMarkupExtension markupProvider;
+ if (compiledMarkupExtensionName != null &&
+ (compiledMarkupExtensionType = Type.GetType(compiledMarkupExtensionName)) != null &&
+ (markupProvider = Activator.CreateInstance(compiledMarkupExtensionType) as ICompiledMarkupExtension) != null)
+ {
+
+ Context.Values[node] = markupProvider.ProvideValue(node, Module, Context);
+
+ VariableDefinition vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+
+ //clean the node as it has been fully exhausted
+ foreach (var prop in node.Properties)
+ if (!node.SkipProperties.Contains(prop.Key))
+ node.SkipProperties.Add(prop.Key);
+ node.CollectionItems.Clear();
+ return;
+ }
+
+ MethodDefinition factoryCtorInfo = null;
+ MethodDefinition factoryMethodInfo = null;
+ MethodDefinition parameterizedCtorInfo = null;
+ MethodDefinition ctorInfo = null;
+
+ if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod))
+ {
+ factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
+ !md.IsStatic &&
+ md.HasParameters &&
+ md.MatchXArguments(node, typeref, Module, Context));
+ if (factoryCtorInfo == null)
+ {
+ throw new XamlParseException(
+ string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
+ }
+ ctorInfo = factoryCtorInfo;
+ if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
+ {
+ VariableDefinition vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+
+ var argumentList = GetCtorXArguments(node, factoryCtorInfo.Parameters.Count);
+ Context.Values[node] = new EXamlCreateObject(Context, null, typedef, argumentList.ToArray());
+ return;
+ }
+ }
+ else if (node.Properties.ContainsKey(XmlName.xFactoryMethod))
+ {
+ var factoryMethod = (string)(node.Properties[XmlName.xFactoryMethod] as ValueNode).Value;
+ factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
+ md.Name == factoryMethod &&
+ md.IsStatic &&
+ md.MatchXArguments(node, typeref, Module, Context));
+
+ if (factoryMethodInfo == null)
+ {
+ var typeExtensionRef = Module.ImportReference(node.XmlType.GetTypeExtensionReference(Module, node));
+ typeExtensionRef = typeExtensionRef?.ResolveCached();
+
+ if (null != typeExtensionRef)
+ {
+ factoryMethodInfo = typeExtensionRef.ResolveCached().AllMethods().FirstOrDefault(md => !md.IsConstructor &&
+ md.Name == factoryMethod &&
+ md.IsStatic &&
+ md.MatchXArguments(node, typeExtensionRef, Module, Context));
+ }
+ }
+
+ if (factoryMethodInfo == null)
+ {
+ throw new XamlParseException(
+ String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
+ }
+
+ VariableDefinition vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+
+ var argumentList = GetCtorXArguments(node, factoryMethodInfo.Parameters.Count);
+ Context.Values[node] = new EXamlCreateObject(Context, null, typedef, factoryMethodInfo, argumentList?.ToArray());
+ return;
+ }
+
+ if (ctorInfo == null && factoryMethodInfo == null)
+ {
+ parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
+ !md.IsStatic &&
+ md.HasParameters &&
+ md.Parameters.All(
+ pd =>
+ pd.CustomAttributes.Any(
+ ca =>
+ ca.AttributeType.FullName ==
+ "Tizen.NUI.Binding.ParameterAttribute")));
+ }
+ string missingCtorParameter = null;
+ List<object> parameterizedCtorParams = null;
+
+ if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node, out missingCtorParameter))
+ {
+ ctorInfo = parameterizedCtorInfo;
+ parameterizedCtorParams = GetCtorArguments(parameterizedCtorInfo, node, Context);
+ //Fang
+ //IL_0000: ldstr "foo"
+ //Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
+ }
+
+ ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
+
+ if (null == ctorInfo)
+ {
+ foreach (var method in typedef.Methods)
+ {
+ if (method.IsConstructor && !method.IsStatic)
+ {
+ bool areAllParamsDefault = true;
+
+ foreach (var param in method.Parameters)
+ {
+ if (!param.HasDefault)
+ {
+ areAllParamsDefault = false;
+ break;
+ }
+ }
+
+ if (areAllParamsDefault)
+ {
+ if (null == ctorInfo)
+ {
+ ctorInfo = method;
+ }
+ else
+ {
+ throw new XamlParseException($"{typedef.FullName} has more than one constructor which params are all default.", node);
+ }
+ }
+ }
+ }
+
+ if (null == ctorInfo && !typedef.IsValueType)
+ {
+ throw new XamlParseException($"{typedef.FullName} has no constructor which params are all default.", node);
+ }
+ }
+
+ if (parameterizedCtorInfo != null && ctorInfo == null)
+ //there was a parameterized ctor, we didn't use it
+ throw new XamlParseException($"The Property '{missingCtorParameter}' is required to create a '{typedef.FullName}' object.", node);
+ var ctorinforef = ctorInfo?.ResolveGenericParameters(typeref, Module);
+
+ var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(typeref, Module);
+ var implicitOperatorref = typedef.Methods.FirstOrDefault(md =>
+ md.IsPublic &&
+ md.IsStatic &&
+ md.IsSpecialName &&
+ md.Name == "op_Implicit" && md.Parameters[0].ParameterType.FullName == "System.String");
+
+ if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType)
+ {
+ VariableDefinition vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+
+ ValueNode vnode = null;
+ if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
+ vardef.VariableType.IsValueType)
+ {
+ Context.Values[node] = vnode.GetBaseValue(Context, typeref);
+ }
+ else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
+ implicitOperatorref != null)
+ {
+ var converterType = vnode.GetConverterType(new ICustomAttributeProvider[] { typeref.ResolveCached() });
+ if (null == converterType)
+ {
+ var realValue = vnode.GetBaseValue(Context, typeref);
+ Context.Values[node] = new EXamlCreateObject(Context, realValue, typeref);
+ }
+ else
+ {
+ var converterValue = new EXamlValueConverterFromString(Context, converterType.Resolve(), vnode.Value as string);
+ Context.Values[node] = new EXamlCreateObject(Context, converterValue, typeref);
+ }
+ }
+ else if (factorymethodinforef != null)
+ {
+ //Fang
+ //Context.IL.Emit(OpCodes.Call, Module.ImportReference(factorymethodinforef));
+ //Context.IL.Emit(OpCodes.Stloc, vardef);
+ }
+ else if (!typedef.IsValueType)
+ {
+ var ctor = Module.ImportReference(ctorinforef);
+ //IL_0001: newobj instance void class [Tizen.NUI.Xaml.UIComponents]Tizen.NUI.Xaml.UIComponents.Button::'.ctor'()
+ //IL_0006: stloc.0
+ //Context.IL.Emit(OpCodes.Newobj, ctor);
+ //Context.IL.Emit(OpCodes.Stloc, vardef);
+ if (typeref.FullName == "Tizen.NUI.Xaml.ArrayExtension")
+ {
+ typeref = Module.ImportReference(typeof(ArrayExtension));
+ typedef = typeref.ResolveCached();
+ }
+
+ var accordingType = this.GetType().Assembly.GetType(typedef.FullName);
+
+ if (null != accordingType && accordingType != typeof(Binding.Setter))
+ {
+ Context.Values[node] = new EXamlCreateObject(Context, Activator.CreateInstance(accordingType), typeref);
+ }
+ else if (null != parameterizedCtorParams)
+ {
+ Context.Values[node] = new EXamlCreateObject(Context, null, typeref, parameterizedCtorParams.ToArray());
+ }
+ else
+ {
+ bool canConvertCollectionItem = false;
+
+ if (!typeref.InheritsFromOrImplements(Context.Module.ImportReference(typeof(List<string>)).Resolve())
+ &&
+ node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null)
+ {
+ var valueNode = node.CollectionItems.First() as ValueNode;
+
+ if (valueNode.CanConvertValue(Context.Module, typeref, (TypeReference)null))
+ {
+ var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { typeref.Resolve() });
+ if (null != converterType)
+ {
+ var converterValue = new EXamlValueConverterFromString(Context, converterType.Resolve(), valueNode.Value as string);
+ Context.Values[node] = new EXamlCreateObject(Context, converterValue, typeref);
+ }
+ else
+ {
+ var valueItem = valueNode.GetBaseValue(Context, typeref);
+ if (null == valueItem)
+ {
+ throw new XamlParseException($"Can't convert collection item \"{vnode.Value}\" to object", node);
+ }
+
+ Context.Values[node] = valueItem;
+ }
+
+ canConvertCollectionItem = true;
+ }
+ }
+
+ if (false == canConvertCollectionItem)
+ {
+ if (!ctorInfo.HasParameters)
+ {
+ Context.Values[node] = new EXamlCreateObject(Context, null, typeref);
+ }
+ else
+ {
+ object[] @params = new object[ctorInfo.Parameters.Count];
+
+ for (int i = 0; i < ctorInfo.Parameters.Count; i++)
+ {
+ var param = ctorInfo.Parameters[i];
+
+ if (ctorInfo.Parameters[i].ParameterType.ResolveCached().IsEnum)
+ {
+ @params[i] = NodeILExtensions.GetParsedEnum(Context, param.ParameterType, param.Constant.ToString());
+ }
+ else
+ {
+ @params[i] = param.Constant;
+ }
+ }
+
+ Context.Values[node] = new EXamlCreateObject(Context, null, typeref, @params);
+ }
+ }
+ }
+ }
+ else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
+ !node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, typeref, Module, Context))
+ {
+ //IL_0008: ldloca.s 1
+ //IL_000a: ldc.i4.1
+ //IL_000b: call instance void valuetype Test/Foo::'.ctor'(bool)
+
+ //Fang
+ //var ctor = Module.ImportReference(ctorinforef);
+ //Context.IL.Emit(OpCodes.Ldloca, vardef);
+ //Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
+ //Context.IL.Emit(OpCodes.Call, ctor);
+ }
+ else
+ {
+ //IL_0000: ldloca.s 0
+ //IL_0002: initobj Test/Foo
+ //Fang
+ //Context.IL.Emit(OpCodes.Ldloca, vardef);
+ //Context.IL.Emit(OpCodes.Initobj, Module.ImportReference(typedef));
+ }
+
+ if (typeref.FullName == "Tizen.NUI.Xaml.ArrayExtension")
+ {
+ //Fang
+ //var visitor = new SetPropertiesVisitor(Context);
+ //foreach (var cnode in node.Properties.Values.ToList())
+ // cnode.Accept(visitor, node);
+ //foreach (var cnode in node.CollectionItems)
+ // cnode.Accept(visitor, node);
+
+ //markupProvider = new ArrayExtension();
+
+ //var il = markupProvider.ProvideValue(node, Module, Context, out typeref);
+
+ //vardef = new VariableDefinition(typeref);
+ //Context.Variables[node] = vardef;
+ //Context.Body.Variables.Add(vardef);
+
+ //Context.IL.Append(il);
+ //Context.IL.Emit(OpCodes.Stloc, vardef);
+
+ ////clean the node as it has been fully exhausted
+ //foreach (var prop in node.Properties)
+ // if (!node.SkipProperties.Contains(prop.Key))
+ // node.SkipProperties.Add(prop.Key);
+ //node.CollectionItems.Clear();
+
+ return;
+ }
+ }
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ //IL_0013: ldarg.0
+ //IL_0014: stloc.3
+
+ var ilnode = (ILRootNode)node;
+ var typeref = ilnode.TypeReference;
+ var vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+ Context.Root = vardef;
+ Context.RootNode = node;
+ //Context.IL.Emit(OpCodes.Ldarg_0);
+ //Context.IL.Emit(OpCodes.Stloc, vardef);
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ XmlName name;
+ if (EXamlSetPropertiesVisitor.TryGetPropertyName(node, parentNode, out name))
+ node.XmlName = name;
+ }
+
+ bool ValidateCtorArguments(MethodDefinition ctorinfo, ElementNode enode, out string firstMissingProperty)
+ {
+ firstMissingProperty = null;
+ foreach (var parameter in ctorinfo.Parameters)
+ {
+ var propname =
+ parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
+ .ConstructorArguments.First()
+ .Value as string;
+ if (!enode.Properties.ContainsKey(new XmlName("", propname)))
+ {
+ firstMissingProperty = propname;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ List<object> GetCtorXArguments(ElementNode enode, int paramsCount)
+ {
+ if (!enode.Properties.ContainsKey(XmlName.xArguments))
+ {
+ return null;
+ }
+
+ List<object> argumentList = new List<object>();
+
+ var arguments = new List<INode>();
+ var node = enode.Properties[XmlName.xArguments] as ElementNode;
+ if (node != null)
+ {
+ node.Accept(new EXamlSetPropertiesVisitor(Context, true), null);
+ arguments.Add(node);
+ }
+
+ var list = enode.Properties[XmlName.xArguments] as ListNode;
+ if (list != null)
+ {
+ foreach (var n in list.CollectionItems)
+ arguments.Add(n);
+ }
+
+ for (int i = 0; i < arguments.Count; i++)
+ {
+ argumentList.Add(Context.Values[arguments[i]]);
+ }
+
+ for (int i = arguments.Count; i < paramsCount; i++)
+ {
+ argumentList.Add(null);
+ }
+
+ return argumentList;
+ }
+
+ static bool IsXaml2009LanguagePrimitive(IElementNode node)
+ {
+ if (node.NamespaceURI == XamlParser.X2009Uri)
+ {
+ var n = node.XmlType.Name.Split(':')[1];
+ return n != "Array";
+ }
+ if (node.NamespaceURI != "clr-namespace:System;assembly=mscorlib")
+ return false;
+ var name = node.XmlType.Name.Split(':')[1];
+ if (name == "SByte" ||
+ name == "Int16" ||
+ name == "Int32" ||
+ name == "Int64" ||
+ name == "Byte" ||
+ name == "UInt16" ||
+ name == "UInt32" ||
+ name == "UInt64" ||
+ name == "Single" ||
+ name == "Double" ||
+ name == "Boolean" ||
+ name == "String" ||
+ name == "Char" ||
+ name == "Decimal" ||
+ name == "TimeSpan" ||
+ name == "Uri")
+ return true;
+ return false;
+ }
+
+ object GetValueFromLanguagePrimitive(TypeReference typeRef, ElementNode node)
+ {
+ var module = Context.Module;
+ var hasValue = node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode &&
+ ((ValueNode)node.CollectionItems[0]).Value is string;
+ var valueString = hasValue ? ((ValueNode)node.CollectionItems[0]).Value as string : string.Empty;
+ object ret = null;
+
+ TypeDefinition typedef = typeRef.ResolveCached();
+
+ switch (typedef.FullName)
+ {
+ case "System.SByte":
+ if (hasValue && sbyte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out sbyte outsbyte))
+ ret = outsbyte;
+ else
+ ret = 0;
+ break;
+ case "System.Int16":
+ if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outshort))
+ ret = outshort;
+ else
+ ret = 0;
+ break;
+ case "System.Int32":
+ if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out int outint))
+ ret = outint;
+ else
+ ret = 0;
+ break;
+ case "System.Int64":
+ if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outlong))
+ ret = outlong;
+ else
+ ret = 0;
+ break;
+ case "System.Byte":
+ if (hasValue && byte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out byte outbyte))
+ ret = outbyte;
+ else
+ ret = 0;
+ break;
+ case "System.UInt16":
+ if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outushort))
+ ret = outushort;
+ else
+ ret = 0;
+ break;
+ case "System.UInt32":
+ if (hasValue && uint.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out uint outuint))
+ ret = outuint;
+ else
+ ret = 0;
+ break;
+ case "System.UInt64":
+ if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outulong))
+ ret = outulong;
+ else
+ ret = 0;
+ break;
+ case "System.Boolean":
+ if (hasValue && bool.TryParse(valueString, out bool outbool))
+ ret = true;
+ else
+ ret = false;
+ break;
+ case "System.String":
+ ret = valueString;
+ break;
+ case "System.Object":
+ var ctorinfo =
+ module.TypeSystem.Object.ResolveCached()
+ .Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
+ var ctor = module.ImportReference(ctorinfo);
+ ret = Create(Newobj, ctor);
+ break;
+ case "System.Char":
+ if (hasValue && char.TryParse(valueString, out char outchar))
+ ret = outchar;
+ else
+ ret = (char)0;
+ break;
+ case "System.Decimal":
+ decimal outdecimal;
+ if (hasValue && decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
+ {
+ ret = outdecimal;
+ }
+ else
+ {
+ ret = (decimal)0;
+ }
+ break;
+ case "System.Single":
+ if (hasValue && float.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out float outfloat))
+ ret = outfloat;
+ else
+ ret = 0f;
+ break;
+ case "System.Double":
+ if (hasValue && double.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out double outdouble))
+ ret = outdouble;
+ else
+ ret = 0d;
+ break;
+ case "System.TimeSpan":
+ if (hasValue && TimeSpan.TryParse(valueString, CultureInfo.InvariantCulture, out TimeSpan outspan))
+ {
+
+ ret = outspan;
+ }
+ else
+ {
+ ret = null;
+ }
+ break;
+ case "System.Uri":
+ if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out Uri outuri))
+ {
+ ret = outuri;
+ }
+ else
+ {
+ ret = null;
+ };
+ break;
+ default:
+ ret = new EXamlCreateObject(Context, null, typeRef);
+ break;
+ }
+
+ return ret;
+ }
+
+ List<object> GetCtorArguments(MethodDefinition ctorinfo, ElementNode enode, EXamlContext context)
+ {
+ List<object> ret = null;
+
+ foreach (var parameter in ctorinfo.Parameters)
+ {
+ var propname =
+ parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
+ .ConstructorArguments.First()
+ .Value as string;
+ var node = enode.Properties[new XmlName("", propname)];
+ if (!enode.SkipProperties.Contains(new XmlName("", propname)))
+ enode.SkipProperties.Add(new XmlName("", propname));
+
+ if (node is ValueNode valueNode)
+ {
+ var valueType = parameter.ParameterType;
+
+ if ("System.Type" == valueType.FullName)
+ {
+ var typeRef = XmlTypeExtensions.GetTypeReference(valueNode.Value as string, Module, node as BaseNode);
+ context.Values[node] = new EXamlCreateObject(context, typeRef);
+ }
+ else
+ {
+ var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() });
+
+ if (null != converterType)
+ {
+ var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
+ context.Values[node] = new EXamlCreateObject(context, converterValue, valueType);
+ }
+ else
+ {
+ context.Values[node] = valueNode.GetBaseValue(context, valueType);
+ }
+ }
+
+ if (null == ret)
+ {
+ ret = new List<object>();
+ }
+
+ ret.Add(context.Values[node]);
+ }
+ }
+
+ return ret;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.Xml;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ class EXamlExpandMarkupsVisitor : IXamlNodeVisitor
+ {
+ readonly IList<XmlName> skips = new List<XmlName>
+ {
+ XmlName.xKey,
+ XmlName.xTypeArguments,
+ XmlName.xFactoryMethod,
+ XmlName.xName,
+ XmlName.xDataType
+ };
+
+ public EXamlExpandMarkupsVisitor(EXamlContext context)
+ {
+ Context = context;
+ }
+
+ EXamlContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => false;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(MarkupNode markupnode, INode parentNode)
+ {
+ XmlName propertyName;
+ if (!TryGetProperyName(markupnode, parentNode, out propertyName))
+ return;
+ if (skips.Contains(propertyName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+ var markupString = markupnode.MarkupString;
+ var node = ParseExpression(ref markupString, Context, markupnode.NamespaceResolver, markupnode) as IElementNode;
+ if (node != null)
+ {
+ ((IElementNode)parentNode).Properties[propertyName] = node;
+ node.Accept(new XamlNodeVisitor((n, parent) => n.Parent = parent), parentNode);
+ }
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ public static bool TryGetProperyName(INode node, INode parentNode, out XmlName name)
+ {
+ name = default(XmlName);
+ var parentElement = parentNode as IElementNode;
+ if (parentElement == null)
+ return false;
+ foreach (var kvp in parentElement.Properties)
+ {
+ if (kvp.Value != node)
+ continue;
+ name = kvp.Key;
+ return true;
+ }
+ return false;
+ }
+
+ static INode ParseExpression(ref string expression, EXamlContext context, IXmlNamespaceResolver nsResolver,
+ IXmlLineInfo xmlLineInfo)
+ {
+ if (expression.StartsWith("{}", StringComparison.Ordinal))
+ return new ValueNode(expression.Substring(2), null);
+
+ if (expression[expression.Length - 1] != '}')
+ throw new XamlParseException("Markup expression missing its closing tag", xmlLineInfo);
+
+ int len;
+ string match;
+ if (!MarkupExpressionParser.MatchMarkup(out match, expression, out len))
+ throw new XamlParseException("Error while parsing markup expression", xmlLineInfo);
+ expression = expression.Substring(len).TrimStart();
+ if (expression.Length == 0)
+ throw new XamlParseException("Markup expression not closed", xmlLineInfo);
+
+ var provider = new XamlServiceProvider(null, null);
+ provider.Add(typeof (ILContextProvider), new ILContextProvider(context));
+ provider.Add(typeof (IXmlNamespaceResolver), nsResolver);
+ provider.Add(typeof (IXmlLineInfoProvider), new XmlLineInfoProvider(xmlLineInfo));
+
+ return new MarkupExpansionParser().Parse(match, ref expression, provider);
+ }
+
+ class ILContextProvider
+ {
+ public ILContextProvider(EXamlContext context)
+ {
+ Context = context;
+ }
+
+ public EXamlContext Context { get; }
+ }
+
+ class MarkupExpansionParser : MarkupExpressionParser, IExpressionParser<INode>
+ {
+ IElementNode node;
+
+ object IExpressionParser.Parse(string match, ref string remaining, IServiceProvider serviceProvider)
+ {
+ return Parse(match, ref remaining, serviceProvider);
+ }
+
+ public INode Parse(string match, ref string remaining, IServiceProvider serviceProvider)
+ {
+ var nsResolver = serviceProvider.GetService(typeof (IXmlNamespaceResolver)) as IXmlNamespaceResolver;
+ if (nsResolver == null)
+ throw new ArgumentException();
+ IXmlLineInfo xmlLineInfo = null;
+ var xmlLineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ if (xmlLineInfoProvider != null)
+ xmlLineInfo = xmlLineInfoProvider.XmlLineInfo;
+ var contextProvider = serviceProvider.GetService(typeof (ILContextProvider)) as ILContextProvider;
+
+ var split = match.Split(':');
+ if (split.Length > 2)
+ throw new ArgumentException();
+
+ string prefix, name;
+ if (split.Length == 2)
+ {
+ prefix = split[0];
+ name = split[1];
+ }
+ else
+ {
+ prefix = "";
+ name = split[0];
+ }
+
+ var namespaceuri = nsResolver.LookupNamespace(prefix) ?? "";
+ if (!string.IsNullOrEmpty(prefix) && string.IsNullOrEmpty(namespaceuri))
+ throw new XamlParseException($"Undeclared xmlns prefix '{prefix}'", xmlLineInfo);
+ //The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
+ XmlType type;
+ try
+ {
+ type = new XmlType(namespaceuri, name + "Extension", null);
+ type.GetTypeReference(contextProvider.Context.Module, null);
+ }
+ catch (XamlParseException)
+ {
+ type = new XmlType(namespaceuri, name, null);
+ }
+
+ if (type == null)
+ throw new NotSupportedException();
+
+ node = xmlLineInfo == null
+ ? new ElementNode(type, "", nsResolver)
+ : new ElementNode(type, "", nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
+
+ if (remaining.StartsWith("}", StringComparison.Ordinal))
+ {
+ remaining = remaining.Substring(1);
+ return node;
+ }
+
+ char next;
+ string piece;
+ while ((piece = GetNextPiece(ref remaining, out next)) != null)
+ HandleProperty(piece, serviceProvider, ref remaining, next != '=');
+
+ return node;
+ }
+
+ protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
+ {
+ var nsResolver = serviceProvider.GetService(typeof(IXmlNamespaceResolver)) as IXmlNamespaceResolver;
+ if (prop != null)
+ {
+ var name = new XmlName(node.NamespaceURI, prop);
+ node.Properties[name] = value as INode ?? new ValueNode(strValue, nsResolver);
+ }
+ else //ContentProperty
+ node.CollectionItems.Add(value as INode ?? new ValueNode(strValue, nsResolver));
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System.Linq;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ class EXamlSetFieldVisitor : IXamlNodeVisitor
+ {
+ public EXamlSetFieldVisitor(EXamlContext context)
+ {
+ Context = context;
+ }
+
+ public EXamlContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ //Fang: Need to deal set field
+ //if (!IsXNameProperty(node, parentNode))
+ // return;
+ //var field = Context.Body.Method.DeclaringType.Fields.SingleOrDefault(fd => fd.Name == (string)node.Value);
+ //if (field == null)
+ // return;
+ //Context.IL.Emit(OpCodes.Ldarg_0);
+ //Context.IL.Emit(OpCodes.Ldloc, Context.Variables[(IElementNode)parentNode]);
+ //Context.IL.Emit(OpCodes.Stfld, field);
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ static bool IsXNameProperty(ValueNode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode xNameNode;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
+ return true;
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ class EXamlSetNamescopesAndRegisterNamesVisitor : IXamlNodeVisitor
+ {
+ public EXamlSetNamescopesAndRegisterNamesVisitor(EXamlContext context)
+ {
+ Context = context;
+ }
+
+ EXamlContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ Context.Scopes[node] = Context.Scopes[parentNode];
+ if (!IsXNameProperty(node, parentNode))
+ return;
+ new EXaml.EXamlRegisterXName(Context, Context.Values[parentNode], node.Value as string);
+ //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)
+ {
+ Context.Scopes[node] = Context.Scopes[parentNode];
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ VariableDefinition namescopeVarDef;
+ IList<string> namesInNamescope;
+ var setNameScope = false;
+ if (parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode) || IsVisualStateGroupList(node)) {
+ namescopeVarDef = CreateNamescope();
+ namesInNamescope = new List<string>();
+ setNameScope = true;
+ } else {
+ namescopeVarDef = Context.Scopes[parentNode].Item1;
+ namesInNamescope = Context.Scopes[parentNode].Item2;
+ }
+ if (setNameScope && Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))))
+ SetNameScope(node, namescopeVarDef);
+ Context.Scopes[node] = new Tuple<VariableDefinition, IList<string>>(namescopeVarDef, namesInNamescope);
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ var namescopeVarDef = CreateNamescope();
+ IList<string> namesInNamescope = new List<string>();
+ if (Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))))
+ SetNameScope(node, namescopeVarDef);
+ Context.Scopes[node] = new System.Tuple<VariableDefinition, IList<string>>(namescopeVarDef, namesInNamescope);
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ Context.Scopes[node] = Context.Scopes[parentNode];
+ }
+
+ static bool IsDataTemplate(INode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode createContent;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
+ createContent == node)
+ return true;
+ return false;
+ }
+
+ static bool IsStyle(INode node, INode parentNode)
+ {
+ var pnode = parentNode as ElementNode;
+ return pnode != null && pnode.XmlType.Name == "Style";
+ }
+
+ static bool IsVisualStateGroupList(ElementNode node)
+ {
+ return node != null && node.XmlType.Name == "VisualStateGroup" && node.Parent is IListNode;
+ }
+
+ static bool IsXNameProperty(ValueNode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode xNameNode;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
+ return true;
+ return false;
+ }
+
+ VariableDefinition CreateNamescope()
+ {
+ var module = Context.Module;
+ var vardef = new VariableDefinition(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "NameScope")));
+ //Context.IL.Emit(OpCodes.Newobj, module.ImportCtorReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "NameScope"), parameterTypes: null));
+ //Context.IL.Emit(OpCodes.Stloc, vardef);
+ return vardef;
+ }
+
+ void SetNameScope(ElementNode node, VariableDefinition ns)
+ {
+ var module = Context.Module;
+ //Context.IL.Emit(OpCodes.Ldloc, Context.Variables[node]);
+ //Context.IL.Emit(OpCodes.Ldloc, ns);
+ //Context.IL.Emit(OpCodes.Call, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "NameScope"),
+ // methodName: "SetNameScope",
+ // parameterTypes: new[] {
+ // (XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindableObject"),
+ // (XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "INameScope"),
+ // },
+ // isStatic: true));
+ }
+
+ void RegisterName(string str, VariableDefinition namescopeVarDef, IList<string> namesInNamescope, VariableDefinition element, INode node)
+ {
+ if (namesInNamescope.Contains(str))
+ throw new XamlParseException($"An element with the name \"{str}\" already exists in this NameScope", node as IXmlLineInfo);
+ namesInNamescope.Add(str);
+
+ var module = Context.Module;
+ //Context.IL.Emit(OpCodes.Ldloc, namescopeVarDef);
+ //Context.IL.Emit(OpCodes.Ldstr, str);
+ //Context.IL.Emit(OpCodes.Ldloc, element);
+ //Context.IL.Emit(OpCodes.Callvirt, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "INameScope"),
+ // methodName: "RegisterName",
+ // parameterTypes: new[] {
+ // ("mscorlib", "System", "String"),
+ // ("mscorlib", "System", "Object"),
+ // }));
+ }
+
+ void SetStyleId(string str, VariableDefinition element)
+ {
+ if (!element.VariableType.InheritsFromOrImplements(Context.Module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Element"))))
+ return;
+
+ var module = Context.Module;
+
+ var nop = Instruction.Create(OpCodes.Nop);
+ //Context.IL.Emit(OpCodes.Ldloc, element);
+ //Context.IL.Emit(OpCodes.Callvirt, module.ImportPropertyGetterReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Element"), propertyName: "StyleId"));
+ //Context.IL.Emit(OpCodes.Brtrue, nop);
+ //Context.IL.Emit(OpCodes.Ldloc, element);
+ //Context.IL.Emit(OpCodes.Ldstr, str);
+ //Context.IL.Emit(OpCodes.Callvirt, module.ImportPropertySetterReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Element"), propertyName: "StyleId"));
+ //Context.IL.Append(nop);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+using Tizen.NUI.Xaml.Core.XamlC;
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ class EXamlSetPropertiesVisitor : IXamlNodeVisitor
+ {
+ static int dtcount;
+ static int typedBindingCount;
+
+ static readonly IList<XmlName> skips = new List<XmlName>
+ {
+ XmlName.xKey,
+ XmlName.xTypeArguments,
+ XmlName.xArguments,
+ XmlName.xFactoryMethod,
+ XmlName.xName,
+ XmlName.xDataType
+ };
+
+ public EXamlSetPropertiesVisitor(EXamlContext context, bool stopOnResourceDictionary = false)
+ {
+ Context = context;
+ Module = context.Module;
+ StopOnResourceDictionary = stopOnResourceDictionary;
+ }
+
+ public EXamlContext Context { get; }
+ public bool StopOnResourceDictionary { get; }
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => true;
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Values[node] as EXamlCreateObject;
+ return null != parentVar
+ &&
+ (parentVar.GetType().FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.GetType().Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary");
+ }
+
+ ModuleDefinition Module { get; }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ //TODO support Label text as element
+ XmlName propertyName;
+ if (!TryGetPropertyName(node, parentNode, out propertyName))
+ {
+ if (!IsCollectionItem(node, parentNode))
+ return;
+ string contentProperty;
+ if (!Context.Variables.ContainsKey((IElementNode)parentNode))
+ return;
+ var parentVar = Context.Variables[(IElementNode)parentNode];
+ if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
+ propertyName = new XmlName(((IElementNode)parentNode).NamespaceURI, contentProperty);
+ else
+ return;
+ }
+
+ if (TrySetRuntimeName(propertyName, Context.Values[parentNode] as EXamlCreateObject, node))
+ return;
+ if (skips.Contains(propertyName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+ if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
+ return;
+
+ SetPropertyValue(Context.Values[parentNode] as EXamlCreateObject, propertyName, node, Context, node);
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ XmlName propertyName = XmlName.Empty;
+
+ //Simplify ListNodes with single elements
+ var pList = parentNode as ListNode;
+ if (pList != null
+ &&
+ (pList.CollectionItems.Count == 1
+ ||
+ "XamlResources" == pList.XmlName.LocalName))
+ {
+ propertyName = pList.XmlName;
+ parentNode = parentNode.Parent;
+ }
+
+ if ((propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) && skips.Contains(propertyName))
+ return;
+
+ if (propertyName == XmlName._CreateContent
+ &&
+ parentNode is ElementNode parentElementNode)
+ {
+ SetDataTemplate(parentElementNode, node, Context, node);
+ return;
+ }
+
+ //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
+ var vardef = Context.Values[node];
+
+ var localName = propertyName.LocalName;
+ TypeReference declaringTypeReference = null;
+
+ PropertyDefinition propertyRef = null;
+ if (parentNode is IElementNode && propertyName != XmlName.Empty) {
+ propertyRef = Context.Variables [(IElementNode)parentNode].VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ }
+
+ if (vardef is EXamlCreateObject)
+ {
+ var realValue = ProvideValue(vardef as EXamlCreateObject, Context, Module, node, propertyRef: propertyRef, propertyDeclaringTypeRef: declaringTypeReference);
+ if (null != realValue && vardef != realValue)
+ {
+ (vardef as EXamlCreateObject).IsValid = false;
+ Context.Values[node] = realValue;
+ vardef = realValue;
+ }
+ }
+
+ if (propertyName != XmlName.Empty) {
+ if (skips.Contains(propertyName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+
+ SetPropertyValue(Context.Values[parentNode] as EXamlCreateObject, propertyName, node, Context, node);
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
+ var parentVar = Context.Values[parentNode] as EXamlCreateObject;
+ string contentProperty;
+
+ bool isAdded = false;
+
+ if (CanAddToResourceDictionary(parentVar, parentVar.GetType(), node, node, Context))
+ {
+ var keyName = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
+ new EXamlAddToResourceDictionary(Context, parentVar, keyName, Context.Values[node]);
+ isAdded = true;
+ }
+
+ // Collection element, implicit content, or implicit collection element.
+ if (!isAdded && parentVar.GetType().GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).Any())
+ {
+ var elementType = parentVar.GetType();
+ var paramType = Context.Variables[node].VariableType;
+
+ foreach (var adderTuple in elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module))
+ {
+ var adderRef = Module.ImportReference(adderTuple.Item1);
+ adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
+
+ if (IsAddMethodOfCollection(Module, adderRef.Resolve()))
+ {
+ new EXamlAddToCollectionInstance(Context, parentVar, Context.Values[node]);
+ isAdded = true;
+ break;
+ }
+ else if (paramType.InheritsFromOrImplements(adderTuple.Item1.Parameters[0].ParameterType.FullName))
+ {
+ new EXamlAddObject(Context, parentVar, Context.Values[node], adderRef.Resolve());
+ isAdded = true;
+ break;
+ }
+ }
+ }
+
+ if (!isAdded && (contentProperty = GetContentProperty(parentVar.GetType())) != null)
+ {
+ var name = new XmlName(node.NamespaceURI, contentProperty);
+ if (skips.Contains(name))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains(propertyName))
+ return;
+
+ SetPropertyValue(Context.Values[parentNode] as EXamlCreateObject, name, node, Context, node);
+ isAdded = true;
+ }
+
+ if (!isAdded)
+ {
+ throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
+ }
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
+ {
+ var parentList = (ListNode)parentNode;
+ if (skips.Contains(parentList.XmlName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+
+ var parent = Context.Variables[((IElementNode)parentNode.Parent)];
+ var elementType = parent.VariableType;
+ localName = parentList.XmlName.LocalName;
+
+ if (Context.Values[parentList.Parent] is EXamlCreateObject)
+ {
+ if (localName.Contains('.'))
+ {
+ int index = localName.LastIndexOf('.');
+ localName = localName.Substring(index + 1);
+ }
+
+ var getObjectByProperty = new EXamlGetObjectByProperty(Context, Context.Values[parentList.Parent] as EXamlCreateObject, localName);
+ new EXamlAddToCollectionProperty(Context, getObjectByProperty, Context.Values[node]);
+ }
+ }
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ private static MethodDefinition addDefOfCollection;
+ private static bool IsAddMethodOfCollection(ModuleDefinition module, MethodDefinition methodDef)
+ {
+ return module.ImportReference(typeof(List<string>)).InheritsFromOrImplements(methodDef.DeclaringType);
+ }
+
+ public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
+ {
+ name = default(XmlName);
+ var parentElement = parentNode as IElementNode;
+ if (parentElement == null)
+ return false;
+ foreach (var kvp in parentElement.Properties)
+ {
+ if (kvp.Value != node)
+ continue;
+ name = kvp.Key;
+ return true;
+ }
+ return false;
+ }
+
+ static bool IsCollectionItem(INode node, INode parentNode)
+ {
+ var parentList = parentNode as IListNode;
+ if (parentList == null)
+ return false;
+ return parentList.CollectionItems.Contains(node);
+ }
+
+ internal static string GetContentProperty(TypeReference typeRef)
+ {
+ var typeDef = typeRef.ResolveCached();
+ var attributes = typeDef.CustomAttributes;
+ var attr =
+ attributes.FirstOrDefault(cad => ContentPropertyAttribute.ContentPropertyTypes.Contains(cad.AttributeType.FullName));
+ if (attr != null)
+ return attr.ConstructorArguments[0].Value as string;
+ if (typeDef.BaseType == null)
+ return null;
+ return GetContentProperty(typeDef.BaseType);
+ }
+
+ public static object ProvideValue(EXamlCreateObject instance, EXamlContext context,
+ ModuleDefinition module, ElementNode node,
+ PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null)
+ {
+ GenericInstanceType markupExtension;
+ IList<TypeReference> genericArguments;
+ if (instance.GetType().FullName == "Tizen.NUI.Xaml.Build.Tasks.ArrayExtension")
+ {
+ var nodeValue = context.Values[node] as EXamlCreateObject;
+
+ if (nodeValue?.Instance is Xaml.Build.Tasks.ArrayExtension arrayExtension)
+ {
+ return arrayExtension.ProvideValue(node, module, context);
+ }
+ }
+ else if (instance.GetType().ImplementsGenericInterface("Tizen.NUI.Xaml.IMarkupExtension`1", out markupExtension, out genericArguments))
+ {
+ var nodeValue = context.Values[node] as EXamlCreateObject;
+ if (nodeValue?.Instance is BindingExtension)
+ {
+ var newValue = (nodeValue.Instance as BindingExtension).ProvideValue(context, module);
+ return newValue;
+ }
+ else if (nodeValue?.Instance is DynamicResourceExtension)
+ {
+ var dynamicResExtension = nodeValue.Instance as DynamicResourceExtension;
+ var newValue = dynamicResExtension.ProvideValue();
+ var newTypeRef = module.ImportReference(newValue.GetType());
+ return new EXamlCreateObject(context, newValue, newTypeRef, new object[] { dynamicResExtension.Key });
+ }
+ }
+ else
+ {
+ var nodeValue = context.Values[node] as EXamlCreateObject;
+ if (null != nodeValue)
+ {
+ if (nodeValue.GetType().ImplementsInterface(module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IMarkupExtension"))))
+ {
+ var acceptEmptyServiceProvider = instance.GetType().GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
+ if (nodeValue.Instance is ReferenceExtension)
+ {
+ var newValue = (nodeValue.Instance as ReferenceExtension).ProvideValue(context);
+ return newValue;
+ }
+ else if (nodeValue.Instance is StaticResourceExtension)
+ {
+ var newValue = (nodeValue.Instance as StaticResourceExtension).ProvideValue(context);
+ return newValue;
+ }
+ }
+ else if (nodeValue.GetType().ImplementsInterface(module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IValueProvider"))))
+ {
+ //var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
+ //var valueProviderType = context.Variables[node].VariableType;
+ ////If the IValueProvider has a ProvideCompiledAttribute that can be resolved, shortcut this
+ //var compiledValueProviderName = valueProviderType?.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "ProvideCompiledAttribute"))?.ConstructorArguments?[0].Value as string;
+ //Type compiledValueProviderType;
+ //if (compiledValueProviderName != null && (compiledValueProviderType = Type.GetType(compiledValueProviderName)) != null)
+ //{
+ // var compiledValueProvider = Activator.CreateInstance(compiledValueProviderType);
+ // var cProvideValue = typeof(ICompiledValueProvider).GetMethods().FirstOrDefault(md => md.Name == "ProvideValue");
+ // var instructions = (IEnumerable<Instruction>)cProvideValue.Invoke(compiledValueProvider, new object[] {
+ //instance,
+ //context.Module,
+ //node as BaseNode,
+ //context});
+ //foreach (var i in instructions)
+ // yield return i;
+ //yield break;
+ //}
+ }
+ }
+
+ //instance.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
+ //yield return Create(Ldloc, context.Variables[node]);
+ //if (acceptEmptyServiceProvider)
+ // yield return Create(Ldnull);
+ //else
+ // foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
+ // yield return instruction;
+ //yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IValueProvider"),
+ // methodName: "ProvideValue",
+ // parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
+ //yield return Create(Stloc, instance.VariableDefinition);
+ }
+
+ return null;
+ }
+
+ static IList<Tuple<PropertyDefinition, string>> ParsePath(string path, TypeReference tSourceRef, IXmlLineInfo lineInfo, ModuleDefinition module)
+ {
+ if (string.IsNullOrWhiteSpace(path))
+ return null;
+ path = path.Trim(' ', '.'); //trim leading or trailing dots
+ var parts = path.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);
+ var properties = new List<Tuple<PropertyDefinition, string>>();
+
+ var previousPartTypeRef = tSourceRef;
+ TypeReference _;
+ foreach (var part in parts) {
+ var p = part;
+ string indexArg = null;
+ var lbIndex = p.IndexOf('[');
+ if (lbIndex != -1) {
+ var rbIndex = p.LastIndexOf(']');
+ if (rbIndex == -1)
+ throw new XamlParseException("Binding: Indexer did not contain closing bracket", lineInfo);
+
+ var argLength = rbIndex - lbIndex - 1;
+ if (argLength == 0)
+ throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
+
+ indexArg = p.Substring(lbIndex + 1, argLength).Trim();
+ if (indexArg.Length == 0)
+ throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
+
+ p = p.Substring(0, lbIndex);
+ p = p.Trim();
+ }
+
+ if (p.Length > 0) {
+ var property = previousPartTypeRef.GetProperty(pd => pd.Name == p && pd.GetMethod != null && pd.GetMethod.IsPublic, out _)
+ ?? throw new XamlParseException($"Binding: Property '{p}' not found on '{previousPartTypeRef}'", lineInfo);
+ properties.Add(new Tuple<PropertyDefinition, string>(property,null));
+ previousPartTypeRef = property.PropertyType;
+ }
+ if (indexArg != null) {
+ var defaultMemberAttribute = previousPartTypeRef.GetCustomAttribute(module, ("mscorlib", "System.Reflection", "DefaultMemberAttribute"));
+ var indexerName = defaultMemberAttribute?.ConstructorArguments?.FirstOrDefault().Value as string ?? "Item";
+ var indexer = previousPartTypeRef.GetProperty(pd => pd.Name == indexerName && pd.GetMethod != null && pd.GetMethod.IsPublic, out _);
+ properties.Add(new Tuple<PropertyDefinition, string>(indexer, indexArg));
+ if (indexer.PropertyType != module.TypeSystem.String && indexer.PropertyType != module.TypeSystem.Int32)
+ throw new XamlParseException($"Binding: Unsupported indexer index type: {indexer.PropertyType.FullName}", lineInfo);
+ previousPartTypeRef = indexer.PropertyType;
+ }
+ }
+ return properties;
+ }
+
+ public static void SetPropertyValue(EXamlCreateObject parent, XmlName propertyName, INode valueNode, EXamlContext context, IXmlLineInfo iXmlLineInfo)
+ {
+ var module = context.Module;
+ var localName = propertyName.LocalName;
+ bool attached;
+
+ var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, iXmlLineInfo);
+
+ //If the target is an event, connect
+ if (CanConnectEvent(parent, localName, attached))
+ {
+ ConnectEvent(parent, localName, valueNode, iXmlLineInfo, context);
+ }
+ //If Value is DynamicResource, SetDynamicResource
+ else if (CanSetDynamicResource(bpRef, valueNode, context))
+ {
+ SetDynamicResource(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
+ }
+ //If Value is a BindingBase and target is a BP, SetBinding
+ else if (CanSetBinding(bpRef, valueNode, context))
+ {
+ SetBinding(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
+ }
+ //If it's a property, set it
+ else if (CanSet(parent, localName, valueNode, context))
+ {
+ Set(parent, localName, valueNode, iXmlLineInfo, context);
+ }
+ //If it's a BP, SetValue ()
+ else if (CanSetValue(bpRef, attached, valueNode, iXmlLineInfo, context))
+ {
+ SetValue(parent, bpRef, valueNode, iXmlLineInfo, context);
+ }
+ //If it's an already initialized property, add to it
+ else if (CanAdd(parent, propertyName, valueNode, iXmlLineInfo, context))
+ {
+ Add(parent, localName, valueNode, iXmlLineInfo, context);
+ }
+ else
+ {
+ throw new XamlParseException($"No property, bindable property, or event found for '{localName}', or mismatching type between value and property.", iXmlLineInfo);
+ }
+ }
+
+ //public static IEnumerable<Instruction> GetPropertyValue(EXamlCreateObject parent, XmlName propertyName, ILContext context, IXmlLineInfo lineInfo, out TypeReference propertyType)
+ //{
+ // var module = context.Module;
+ // var localName = propertyName.LocalName;
+ // bool attached;
+ // var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
+
+ // //If it's a BP, GetValue ()
+ // if (CanGetValue(parent, bpRef, attached, lineInfo, context, out _))
+ // return GetValue(parent, bpRef, lineInfo, context, out propertyType);
+
+ // //If it's a property, set it
+ // if (CanGet(parent, localName, context, out _))
+ // return Get(parent, localName, lineInfo, context, out propertyType);
+
+ // throw new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
+ //}
+
+ static MemberReference GetBindablePropertyReference(EXamlCreateObject parent, string namespaceURI, ref string localName, out bool attached, EXamlContext context, IXmlLineInfo iXmlLineInfo)
+ {
+ var module = context.Module;
+ TypeReference declaringTypeReference;
+
+ //If it's an attached BP, update elementType and propertyName
+ var bpOwnerType = parent.GetType();
+ attached = GetNameAndTypeRef(ref bpOwnerType, namespaceURI, ref localName, context, iXmlLineInfo);
+ var name = $"{localName}Property";
+
+ PropertyReference prRef = bpOwnerType.GetProperty(p => p.Name == name &&
+ p.GetMethod.IsStatic && p.GetMethod.IsPublic,
+ out declaringTypeReference);
+
+ if (null != prRef)
+ {
+ //prRef = module.ImportReference(prRef.ResolveGenericParameters(declaringTypeReference));
+ prRef.PropertyType = module.ImportReference(prRef.PropertyType);
+ return prRef;
+ }
+
+ FieldReference bpRef = bpOwnerType.GetField(fd => fd.Name == name &&
+ fd.IsStatic &&
+ (fd.IsPublic || fd.IsAssembly), out declaringTypeReference);
+ if (bpRef != null) {
+ bpRef = module.ImportReference(bpRef.ResolveGenericParameters(declaringTypeReference));
+ bpRef.FieldType = module.ImportReference(bpRef.FieldType);
+ }
+ return bpRef;
+ }
+
+ static bool CanConnectEvent(EXamlCreateObject parent, string localName, bool attached)
+ {
+ return !attached && parent.GetType().GetEvent(ed => ed.Name == localName, out _) != null;
+ }
+
+ static void ConnectEvent(EXamlCreateObject parent, string localName, INode valueNode, IXmlLineInfo iXmlLineInfo, EXamlContext context)
+ {
+ //Fang: Need to deal connect event
+ var elementType = parent.GetType();
+ var module = context.Module;
+ TypeReference eventDeclaringTypeRef;
+
+ var eventinfo = elementType.GetEvent(ed => ed.Name == localName, out eventDeclaringTypeRef);
+
+// IL_0007: ldloc.0
+// IL_0008: ldarg.0
+//
+// IL_0009: ldftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
+//OR, if the handler is virtual
+// IL_000x: ldarg.0
+// IL_0009: ldvirtftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
+//
+// IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
+// IL_0014: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Button::add_Clicked(class [mscorlib]System.EventHandler)
+
+ var value = ((ValueNode)valueNode).Value;
+
+ //if (context.Root is VariableDefinition)
+ // yield return Create(Ldloc, context.Root as VariableDefinition);
+ //else if (context.Root is FieldDefinition)
+ //{
+ // yield return Create(Ldarg_0);
+ // yield return Create(Ldfld, context.Root as FieldDefinition);
+ //}
+ //else
+ // throw new InvalidProgramException();
+ var declaringType = context.Type;
+ while (declaringType.IsNested)
+ declaringType = declaringType.DeclaringType;
+ var handler = declaringType.AllMethods().FirstOrDefault(md => md.Name == value as string);
+
+ //check if the handler signature matches the Invoke signature;
+ var invoke = module.ImportReference(eventinfo.EventType.ResolveCached().GetMethods().First(md => md.Name == "Invoke"));
+ invoke = invoke.ResolveGenericParameters(eventinfo.EventType, module);
+ if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
+ {
+ TypeDefinition realType = eventinfo.EventType.ResolveCached();
+
+ GenericInstanceType genericInstanceType = eventinfo.EventType as GenericInstanceType;
+
+ if (null != genericInstanceType
+ && genericInstanceType.GenericArguments.Count == realType.GenericParameters.Count)
+ {
+ Dictionary<string, TypeReference> dict = new Dictionary<string, TypeReference>();
+
+ for (int i = 0; i < realType.GenericParameters.Count; i++)
+ {
+ string p = realType.GenericParameters[i].Name;
+ TypeReference type = genericInstanceType.GenericArguments[i];
+
+ dict.Add(p, type);
+ }
+
+ if (dict.ContainsKey(invoke.ReturnType.Name))
+ {
+ invoke.ReturnType = dict[invoke.ReturnType.Name];
+ }
+
+ for (int i = 0; i < invoke.Parameters.Count; i++)
+ {
+ if (dict.ContainsKey(invoke.Parameters[i].ParameterType.Name))
+ {
+ invoke.Parameters[i].ParameterType = dict[invoke.Parameters[i].ParameterType.Name];
+ }
+ }
+ }
+ }
+
+ if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
+ throw new XamlParseException($"Signature (return type) of EventHandler \"{context.Type.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
+ if (invoke.Parameters.Count != handler.Parameters.Count)
+ throw new XamlParseException($"Signature (number of arguments) of EventHandler \"{context.Type.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
+ if (!invoke.ContainsGenericParameter)
+ for (var i = 0; i < invoke.Parameters.Count; i++)
+ if (!handler.Parameters[i].ParameterType.InheritsFromOrImplements(invoke.Parameters[i].ParameterType))
+ throw new XamlParseException($"Signature (parameter {i}) of EventHandler \"{context.Type.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
+
+ new EXamlAddEvent(context, parent, context.Values[context.RootNode] as EXamlCreateObject, localName, handler);
+ }
+
+ static bool CanSetDynamicResource(MemberReference bpRef, INode valueNode, EXamlContext context)
+ {
+ if (bpRef == null)
+ return false;
+ var elementNode = valueNode as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ var valueInstance = context.Values[valueNode] as EXamlCreateObject;
+ if (null == valueInstance)
+ return false;
+
+ return valueInstance.GetType().FullName == typeof(DynamicResource).FullName;
+ }
+
+ static void SetDynamicResource(EXamlCreateObject parent, MemberReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, EXamlContext context)
+ {
+ var instance = context.Values[elementNode] as EXamlCreateObject;
+ if (null != instance)
+ {
+ var dynamicResource = instance.Instance as DynamicResource;
+
+ if (null != dynamicResource)
+ {
+ instance.IsValid = false;
+ new EXamlSetDynamicResource(context, parent, bpRef, dynamicResource.Key);
+ }
+ }
+ }
+
+ static bool CanSetBinding(MemberReference bpRef, INode valueNode, EXamlContext context)
+ {
+ var module = context.Module;
+
+ if (bpRef == null)
+ return false;
+ var elementNode = valueNode as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ var valueInstance = context.Values[valueNode] as EXamlCreateObject;
+ if (null == valueInstance)
+ return false;
+
+ var implicitOperator = valueInstance.GetType().GetImplicitOperatorTo(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindingBase")), module);
+ if (implicitOperator != null)
+ return true;
+
+ return valueInstance.GetType().InheritsFromOrImplements(XamlTask.bindingNameSpace + ".BindingBase");
+ }
+
+ static void SetBinding(EXamlCreateObject parent, MemberReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, EXamlContext context)
+ {
+ new EXamlSetBinding(context, parent, bpRef, context.Values[elementNode]);
+ }
+
+ static bool CanSetValue(MemberReference bpRef, bool attached, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
+ {
+ var module = context.Module;
+
+ if (bpRef == null)
+ return false;
+
+ var valueNode = node as ValueNode;
+ if (valueNode != null && valueNode.CanConvertValue(context.Module, bpRef))
+ return true;
+
+ var elementNode = node as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ return context.Values.ContainsKey(elementNode);
+
+ //VariableDefinition varValue;
+ //if (!context.Variables.TryGetValue(elementNode, out varValue))
+ // return false;
+
+ // var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
+ //// If it's an attached BP, there's no second chance to handle IMarkupExtensions, so we try here.
+ //// Worst case scenario ? InvalidCastException at runtime
+ //if (attached && varValue.VariableType.FullName == "System.Object")
+ // return true;
+ //var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(bpTypeRef, module);
+ //if (implicitOperator != null)
+ // return true;
+
+ ////as we're in the SetValue Scenario, we can accept value types, they'll be boxed
+ //if (varValue.VariableType.IsValueType && bpTypeRef.FullName == "System.Object")
+ // return true;
+
+ //return varValue.VariableType.InheritsFromOrImplements(bpTypeRef);
+ }
+
+ static bool CanGetValue(EXamlCreateObject parent, MemberReference bpRef, bool attached, IXmlLineInfo iXmlLineInfo, EXamlContext context, out TypeReference propertyType)
+ {
+ var module = context.Module;
+ propertyType = null;
+
+ if (bpRef == null)
+ return false;
+
+ if (!parent.GetType().InheritsFromOrImplements(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))))
+ return false;
+
+ propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
+ return true;
+ }
+
+ static void SetValue(EXamlCreateObject parent, MemberReference bpRef, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
+ {
+ var valueNode = node as ValueNode;
+
+ if (valueNode != null)
+ {
+ var valueType = bpRef.GetBindablePropertyType(null, context.Module);
+ var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { valueType.Resolve() });
+ if (null != converterType)
+ {
+ var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
+ context.Values[node] = new EXamlCreateObject(context, converterValue, valueType);
+ }
+ else
+ {
+ context.Values[node] = valueNode.GetBaseValue(context, valueType);
+ }
+ }
+
+ new EXamlSetBindalbeProperty(context, parent, bpRef, context.Values[node]);
+ }
+
+ static void GetValue(EXamlCreateObject parent, FieldReference bpRef, IXmlLineInfo iXmlLineInfo, EXamlContext context, out TypeReference propertyType)
+ {
+ var module = context.Module;
+ propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
+
+ //return new[] {
+ // Create(Ldloc, parent),
+ // Create(Ldsfld, bpRef),
+ // Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
+ // methodName: "GetValue",
+ // parameterTypes: new[] { (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty") })),
+ //};
+ }
+
+ static bool CanSet(EXamlCreateObject parent, string localName, INode node, EXamlContext context)
+ {
+ var module = context.Module;
+ TypeReference declaringTypeReference;
+ var property = parent.GetType().GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ if (property == null)
+ return false;
+ var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
+ var propertySetter = property.SetMethod;
+ if (propertySetter == null || !propertySetter.IsPublic || propertySetter.IsStatic)
+ return false;
+
+ var valueNode = node as ValueNode;
+ if (valueNode != null && valueNode.CanConvertValue(context.Module, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached()}))
+ return true;
+
+ var elementNode = node as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ var vardef = context.Variables[elementNode];
+ var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
+
+ var value = context.Values[elementNode] as EXamlCreateObject;
+
+ if (vardef.VariableType.InheritsFromOrImplements(propertyType))
+ return true;
+ if (null != value && value.GetType().InheritsFromOrImplements(propertyType))
+ return true;
+ if (implicitOperator != null)
+ return true;
+ if (propertyType.FullName == "System.Object")
+ return true;
+
+ //I'd like to get rid of this condition. This comment used to be //TODO replace latest check by a runtime type check
+ if (vardef.VariableType.FullName == "System.Object")
+ return true;
+
+ var realValue = context.Values[elementNode] as EXamlCreateObject;
+ if (null != realValue)
+ {
+ if (realValue.GetType().InheritsFromOrImplements(propertyType))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static bool CanGet(EXamlCreateObject parent, string localName, EXamlContext context, out TypeReference propertyType)
+ {
+ var module = context.Module;
+ propertyType = null;
+ TypeReference declaringTypeReference;
+ var property = parent.GetType().GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ if (property == null)
+ return false;
+ var propertyGetter = property.GetMethod;
+ if (propertyGetter == null || !propertyGetter.IsPublic || propertyGetter.IsStatic)
+ return false;
+
+ module.ImportReference(parent.GetType().ResolveCached());
+ var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertyGetterRef.ImportTypes(module);
+ propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
+
+ return true;
+ }
+
+ static void Set(EXamlCreateObject parent, string localName, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
+ {
+ var module = context.Module;
+ TypeReference declaringTypeReference;
+ var property = parent.Type.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ var propertySetter = property.SetMethod;
+
+ //// IL_0007: ldloc.0
+ //// IL_0008: ldstr "foo"
+ //// IL_000d: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Label::set_Text(string)
+
+ var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertySetterRef.ImportTypes(module);
+ var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
+ var valueNode = node as ValueNode;
+ var elementNode = node as IElementNode;
+
+ //if it's a value type, load the address so we can invoke methods on it
+ if (parent.Type.IsValueType)
+ {
+ // yield return Instruction.Create(OpCodes.Ldloca, parent);
+ }
+ else
+ {
+ // yield return Instruction.Create(OpCodes.Ldloc, parent);
+ }
+
+ if (valueNode != null)
+ {
+ if ("Tizen.NUI.Binding.BindableProperty" == propertyType.FullName)
+ {
+ var bindableProperty = BindablePropertyConverter.GetBindablePropertyFieldReference(valueNode.Value as string, module, node as BaseNode);
+ var fieldRef = bindableProperty.DeclaringType.ResolveCached().Fields.FirstOrDefault(a => a.FullName == bindableProperty.FullName);
+ context.Values[node] = new EXamlCreateObject(context, bindableProperty.DeclaringType, fieldRef, null);
+ }
+ else
+ {
+ var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { property, propertyType.ResolveCached() });
+ if (null != converterType)
+ {
+ var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
+ context.Values[node] = new EXamlCreateObject(context, converterValue, propertyType);
+ }
+ else
+ {
+ context.Values[node] = valueNode.GetBaseValue(context, property.PropertyType);
+ }
+ }
+ }
+ else if (elementNode != null)
+ {
+ var vardef = context.Variables[elementNode];
+ var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
+ //yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ if (!vardef.VariableType.InheritsFromOrImplements(propertyType) && implicitOperator != null)
+ {
+ // IL_000f: call !0 class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<bool>::op_Implicit(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<!0>)
+ //yield return Instruction.Create(OpCodes.Call, module.ImportReference(implicitOperator));
+ }
+ else if (!vardef.VariableType.IsValueType && propertyType.IsValueType)
+ {
+ //yield return Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(propertyType));
+ }
+ else if (vardef.VariableType.IsValueType && propertyType.FullName == "System.Object")
+ {
+ //yield return Instruction.Create(OpCodes.Box, vardef.VariableType);
+ }
+ if (parent.Type.IsValueType)
+ {
+ //yield return Instruction.Create(OpCodes.Call, propertySetterRef);
+ }
+ else
+ {
+ //yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
+ }
+ }
+
+ new EXamlSetProperty(context, parent, localName, context.Values[node]);
+ }
+
+ static void Get(EXamlCreateObject parent, string localName, IXmlLineInfo iXmlLineInfo, EXamlContext context, out TypeReference propertyType)
+ {
+ var module = context.Module;
+ var property = parent.GetType().GetProperty(pd => pd.Name == localName, out var declaringTypeReference);
+ var propertyGetter = property.GetMethod;
+
+ module.ImportReference(parent.GetType().ResolveCached());
+ var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertyGetterRef.ImportTypes(module);
+ propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
+
+ //if (parent.VariableType.IsValueType)
+ // return new[] {
+ // Instruction.Create(OpCodes.Ldloca, parent),
+ // Instruction.Create(OpCodes.Call, propertyGetterRef),
+ // };
+ //else
+ // return new[] {
+ // Instruction.Create(OpCodes.Ldloc, parent),
+ // Instruction.Create(OpCodes.Callvirt, propertyGetterRef),
+ // };
+ }
+
+ static bool CanAdd(EXamlCreateObject parent, XmlName propertyName, INode node, IXmlLineInfo lineInfo, EXamlContext context)
+ {
+ var module = context.Module;
+ var localName = propertyName.LocalName;
+ bool attached;
+ var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
+ TypeReference propertyType;
+
+ if ( !CanGetValue(parent, bpRef, attached, null, context, out propertyType)
+ && !CanGet(parent, localName, context, out propertyType))
+ return false;
+
+ //TODO check md.Parameters[0] type
+ var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
+ if (adderTuple == null)
+ return false;
+
+ return true;
+ }
+
+ static Dictionary<EXamlCreateObject, IList<string>> resourceNamesInUse = new Dictionary<EXamlCreateObject, IList<string>>();
+ static bool CanAddToResourceDictionary(EXamlCreateObject parent, TypeReference collectionType, IElementNode node, IXmlLineInfo lineInfo, EXamlContext context)
+ {
+ if ( collectionType.FullName != "Tizen.NUI.Binding.ResourceDictionary"
+ && collectionType.ResolveCached().BaseType?.FullName != "Tizen.NUI.Binding.ResourceDictionary")
+ return false;
+
+
+ if (node.Properties.ContainsKey(XmlName.xKey)) {
+ var key = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
+ if (!resourceNamesInUse.TryGetValue(parent, out var names))
+ resourceNamesInUse[parent] = (names = new List<string>());
+ if (names.Contains(key))
+ throw new XamlParseException($"A resource with the key '{key}' is already present in the ResourceDictionary.", lineInfo);
+ names.Add(key);
+ return true;
+ }
+
+ //is there a RD.Add() overrides that accepts this ?
+ var nodeTypeRef = context.Variables[node].VariableType;
+ var module = context.Module;
+ if (module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "ResourceDictionary"),
+ methodName: "Add",
+ parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }) != null)
+ return true;
+
+ throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
+ }
+
+ static void Add(EXamlCreateObject parent, string propertyName, INode node, IXmlLineInfo iXmlLineInfo, EXamlContext context)
+ {
+ //Fang: Need to deal
+ var module = context.Module;
+ var elementNode = node as IElementNode;
+
+ TypeReference declaringTypeReference;
+ var property = parent.Type.GetProperty(pd => pd.Name == propertyName, out declaringTypeReference);
+ TypeReference propertyType = property.PropertyType;
+
+ if (null != elementNode && CanAddToResourceDictionary(parent, propertyType, elementNode, iXmlLineInfo, context))
+ {
+ var keyName = (elementNode.Properties[XmlName.xKey] as ValueNode).Value as string;
+ new EXamlAddToResourceDictionary(context, parent, keyName, context.Values[node]);
+ return;
+ }
+
+ var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
+ var adderRef = module.ImportReference(adderTuple.Item1);
+ adderRef = module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, module));
+ var childType = GetParameterType(adderRef.Parameters[0]);
+
+ if (node is ValueNode valueNode)
+ {
+ if (true == valueNode.CanConvertValue(module, childType, (TypeReference)null))
+ {
+ var obj = new EXamlGetObjectByProperty(context, parent, propertyName);
+
+ var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { property, childType.ResolveCached() });
+ if (null != converterType)
+ {
+ var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
+ context.Values[node] = new EXamlCreateObject(context, converterValue, propertyType);
+ }
+ else
+ {
+ context.Values[node] = valueNode.GetBaseValue(context, childType);
+ }
+ new EXamlAddToCollectionProperty(context, obj, context.Values[node]);
+ }
+ }
+ else if (node is ElementNode element)
+ {
+ var obj = new EXamlGetObjectByProperty(context, parent, propertyName);
+ new EXamlAddToCollectionProperty(context, obj, context.Values[node]);
+ }
+ }
+
+ static IEnumerable<Instruction> AddToResourceDictionary(IElementNode node, IXmlLineInfo lineInfo, EXamlContext context)
+ {
+ var module = context.Module;
+
+ if (node.Properties.ContainsKey(XmlName.xKey)) {
+// IL_0014: ldstr "key"
+// IL_0019: ldstr "foo"
+// IL_001e: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.ResourceDictionary::Add(string, object)
+ yield return Create(Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
+ var varDef = context.Variables[node];
+ yield return Create(Ldloc, varDef);
+ if (varDef.VariableType.IsValueType)
+ yield return Create(Box, module.ImportReference(varDef.VariableType));
+ yield return Create(Callvirt, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "ResourceDictionary"),
+ methodName: "Add",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System", "Object"),
+ }));
+ yield break;
+ }
+
+ var nodeTypeRef = context.Variables[node].VariableType;
+ yield return Create(Ldloc, context.Variables[node]);
+ yield return Create(Callvirt, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "ResourceDictionary"),
+ methodName: "Add",
+ parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }));
+ yield break;
+ }
+
+ public static TypeReference GetParameterType(ParameterDefinition param)
+ {
+ if (!param.ParameterType.IsGenericParameter)
+ return param.ParameterType;
+ var type = (param.Method as MethodReference).DeclaringType as GenericInstanceType;
+ return type.GenericArguments [0];
+ }
+
+ static bool GetNameAndTypeRef(ref TypeReference elementType, string namespaceURI, ref string localname,
+ EXamlContext context, IXmlLineInfo lineInfo)
+ {
+ var dotIdx = localname.IndexOf('.');
+ if (dotIdx > 0)
+ {
+ var typename = localname.Substring(0, dotIdx);
+ localname = localname.Substring(dotIdx + 1);
+ elementType = new XmlType(namespaceURI, typename, null).GetTypeReference(context.Module, lineInfo);
+ return true;
+ }
+ return false;
+ }
+
+ static void SetDataTemplate(ElementNode parentNode, ElementNode rootnode, EXamlContext parentContext,
+ IXmlLineInfo xmlLineInfo)
+ {
+ var typeref = parentContext.Module.ImportReference(rootnode.XmlType.GetTypeReference(parentContext.Module, rootnode));
+ var visitorContext = new EXamlContext(typeref.ResolveCached(), typeref.Module);
+
+ rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
+ rootnode.Accept(new EXamlExpandMarkupsVisitor(visitorContext), null);
+ rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
+ rootnode.Accept(new EXamlCreateObjectVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetNamescopesAndRegisterNamesVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetFieldVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetResourcesVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetPropertiesVisitor(visitorContext, true), null);
+
+ var eXamlString = visitorContext.GenerateEXamlString();
+
+ var parentTyperef = parentContext.Module.ImportReference(parentNode.XmlType.GetTypeReference(parentContext.Module, parentNode));
+
+ if (parentContext.Values[parentNode] is EXamlCreateObject eXamlObject)
+ {
+ eXamlObject.IsValid = false;
+ parentContext.Values[parentNode] = new EXamlCreateDataTemplate(parentContext, parentTyperef, eXamlString);
+ }
+ }
+
+ bool TrySetRuntimeName(XmlName propertyName, EXamlCreateObject variableDefinition, ValueNode node)
+ {
+ if (null == variableDefinition)
+ {
+ return false;
+ }
+
+ if (propertyName != XmlName.xName)
+ return false;
+
+ var attributes = variableDefinition.GetType().ResolveCached()
+ .CustomAttributes.Where(attribute => attribute.AttributeType.FullName == "Tizen.NUI.Xaml.RuntimeNamePropertyAttribute").ToList();
+
+ if (!attributes.Any())
+ return false;
+
+ var runTimeName = attributes[0].ConstructorArguments[0].Value as string;
+
+ if (string.IsNullOrEmpty(runTimeName))
+ return false;
+
+ SetPropertyValue(variableDefinition, new XmlName("", runTimeName), node, Context, node);
+ return true;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ class EXamlSetResourcesVisitor : IXamlNodeVisitor
+ {
+ public EXamlSetResourcesVisitor(EXamlContext context)
+ {
+ Context = context;
+ Module = context.Module;
+ }
+
+ public EXamlContext Context { get; }
+ ModuleDefinition Module { get; }
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ if (!IsResourceDictionary((IElementNode)parentNode))
+ return;
+
+ node.Accept(new EXamlSetPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ XmlName propertyName;
+ //Set ResourcesDictionaries to their parents
+ if (IsResourceDictionary(node) && EXamlSetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName))
+ {
+ string realPropertyName;
+ if (propertyName.LocalName.EndsWith(".XamlResources", StringComparison.Ordinal))
+ {
+ realPropertyName = propertyName.LocalName.Substring(propertyName.LocalName.Length - ".XamlResources".Length);
+ }
+ else
+ {
+ realPropertyName = propertyName.LocalName;
+ }
+
+ if (realPropertyName == "XamlResources")
+ {
+ new EXamlSetProperty(Context, Context.Values[parentNode] as EXamlCreateObject, realPropertyName, Context.Values[node]);
+ //Context.IL.Append(SetPropertiesVisitor.SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
+ return;
+ }
+ }
+
+ //Only proceed further if the node is a keyless RD
+ if ( parentNode is IElementNode
+ && IsResourceDictionary((IElementNode)parentNode)
+ && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
+ node.Accept(new EXamlSetPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ else if ( parentNode is ListNode
+ && IsResourceDictionary((IElementNode)parentNode.Parent)
+ && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
+ node.Accept(new EXamlSetPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ public bool IsResourceDictionary(ElementNode node) => IsResourceDictionary((IElementNode)node);
+
+ bool IsResourceDictionary(IElementNode node)
+ {
+ var instance = Context.Values[node] as EXamlCreateObject;
+
+ if (null != instance)
+ {
+ return instance.Type.InheritsFromOrImplements("Tizen.NUI.Binding.ResourceDictionary");
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public bool SkipChildren(INode node, INode parentNode)
+ {
+ var enode = node as ElementNode;
+ if (enode == null)
+ return false;
+ if ( parentNode is IElementNode
+ && IsResourceDictionary((IElementNode)parentNode)
+ && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
+ return true;
+ if ( parentNode is ListNode
+ && IsResourceDictionary((IElementNode)parentNode.Parent)
+ && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
+ return true;
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System.Collections.Generic;
+using Mono.Cecil;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.EXaml.Build.Tasks
+{
+ static class MethodDefinitionExtensions
+ {
+ public static bool MatchXArguments(this MethodDefinition methodDef, ElementNode enode, TypeReference declaringTypeRef, ModuleDefinition module, EXamlContext context)
+ {
+ if (!enode.Properties.ContainsKey(XmlName.xArguments))
+ return !methodDef.HasParameters;
+
+ var arguments = new List<INode>();
+ var node = enode.Properties[XmlName.xArguments] as ElementNode;
+ if (node != null)
+ arguments.Add(node);
+ else
+ {
+ if (enode.Properties[XmlName.xArguments] is ValueNode valueNode)
+ {
+ var value = valueNode.Value as string;
+ if (value != null && value.Substring(0, "{x:Reference ".Length) == "{x:Reference ")
+ {
+ var elementName = value.Substring("{x:Reference ".Length);
+ elementName = elementName.Substring(0, elementName.Length - 1);
+ }
+ }
+ }
+
+ var list = enode.Properties[XmlName.xArguments] as ListNode;
+ if (list != null)
+ foreach (var n in list.CollectionItems)
+ arguments.Add(n);
+
+ if (methodDef.Parameters.Count < arguments.Count)
+ return false;
+
+ for (int i = arguments.Count; i < methodDef.Parameters.Count; i++)
+ {
+ if (false == methodDef.Parameters[i].HasDefault)
+ {
+ return false;
+ }
+ }
+
+ for (var i = 0; i < arguments.Count; i++)
+ {
+ var paramType = methodDef.Parameters[i].ParameterType;
+ var genParam = paramType as GenericParameter;
+ if (genParam != null) {
+ var index = genParam.DeclaringType.GenericParameters.IndexOf(genParam);
+ paramType = (declaringTypeRef as GenericInstanceType).GenericArguments[index];
+ }
+
+ var argValue = context.Values[arguments[i]];
+ TypeReference argType = null;
+ if (argValue is EXamlCreateObject eXamlCreateObject)
+ {
+ argType = eXamlCreateObject.Type;
+ }
+ else
+ {
+ argType = paramType.Module.ImportReference(argValue.GetType());
+ }
+
+ if (!argType.InheritsFromOrImplements(paramType))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static TypeReference ResolveGenericReturnType(this MethodDefinition self, TypeReference declaringTypeRef, ModuleDefinition module)
+ {
+ if (self == null)
+ throw new System.ArgumentNullException(nameof(self));
+ if (declaringTypeRef == null)
+ throw new System.ArgumentNullException(nameof(declaringTypeRef));
+ if (!self.ReturnType.IsGenericParameter)
+ return self.ReturnType;
+
+ var t = ((GenericInstanceType)declaringTypeRef).GenericArguments[((GenericParameter)self.ReturnType).Position];
+ return t;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tizen.NUI.EXaml
+{
+ internal class EXamlDefinitionList<T> : IEnumerable<(TypeReference, T)> where T : IMemberDefinition
+ {
+ internal void Clear()
+ {
+ List.Clear();
+ }
+
+ internal void Add(TypeReference declareTypeRef, T definition)
+ {
+ if (-1 == GetIndex(declareTypeRef, definition))
+ {
+ List.Add((declareTypeRef, definition));
+ }
+ }
+
+ internal int GetIndex(TypeReference declareTypeRef, T definition)
+ {
+ for (int i = 0; i < List.Count; i++)
+ {
+ if (EXamlUtility.IsSameTypeReference(declareTypeRef, List[i].Item1)
+ &&
+ definition.Equals(List[i].Item2))
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return List.GetEnumerator();
+ }
+
+ IEnumerator<(TypeReference, T)> IEnumerable<(TypeReference, T)>.GetEnumerator()
+ {
+ return List.GetEnumerator();
+ }
+
+ private List<(TypeReference, T)> List = new List<(TypeReference, T)>();
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tizen.NUI.EXaml
+{
+ internal enum EXamlOperationType
+ {
+ GatherAssembly = 0,
+ GatherType,
+ GatherProperty,
+ GatherEvent,
+ GatherMethod,
+ GatherBindableProperty,
+ CreateObject,
+ CreateArrayObject,
+ CreateDPObject,
+ CreateDataTemplate,
+ GetStaticObject,
+ GetTypeObject,
+ GetObjectConvertedFromString,
+ GetEnumObject,
+ GetObjectByProperty,
+ SetProperty,
+ SetBindableProperty,
+ SetBinding,
+ SetDynamicResource,
+ AddEvent,
+ AddObject,
+ AddToCollectionObject,
+ AddToCollectionProperty,
+ AddToResourceDictionary,
+ RegisterXName,
+ GetLongString,
+ MAX
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using Mono.Cecil;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tizen.NUI.EXaml
+{
+ internal class EXamlUtility
+ {
+ internal static bool IsSameTypeReference(TypeReference typeReference1, TypeReference typeReference2)
+ {
+ if (null == typeReference1 || null == typeReference2)
+ {
+ return typeReference1 == typeReference2;
+ }
+ else if (typeReference1.Resolve() != typeReference2.Resolve())
+ {
+ return false;
+ }
+ else if (typeReference1 is GenericInstanceType)
+ {
+ if (typeReference2 is GenericInstanceType)
+ {
+ var gType1 = typeReference1 as GenericInstanceType;
+ var gType2 = typeReference2 as GenericInstanceType;
+
+ if (gType1.GenericArguments.Count != gType2.GenericArguments.Count)
+ {
+ return false;
+ }
+ else
+ {
+ for (int i = 0; i < gType1.GenericArguments.Count; i++)
+ {
+ if (false == IsSameTypeReference(gType1.GenericArguments[i], gType2.GenericArguments[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ else
+ {
+ return true;
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class BindablePropertyReferenceExtensions
+ {
+ public static TypeReference GetBindablePropertyType(this MemberReference bpRef, IXmlLineInfo iXmlLineInfo, ModuleDefinition module)
+ {
+ if (!bpRef.Name.EndsWith("Property", StringComparison.InvariantCulture))
+ throw new XamlParseException($"The name of the bindable property {bpRef.Name} does not ends with \"Property\". This is the kind of convention the world is build upon, a bit like Planck's constant.", iXmlLineInfo);
+ var bpName = bpRef.Name.Substring(0, bpRef.Name.Length - 8);
+ var owner = bpRef.DeclaringType;
+ TypeReference declaringTypeRef = null;
+
+ var getter = owner.GetProperty(pd => pd.Name == bpName, out declaringTypeRef)?.GetMethod;
+ if (getter == null || getter.IsStatic || !getter.IsPublic)
+ getter = null;
+ getter = getter ?? owner.GetMethods(md => md.Name == $"Get{bpName}" &&
+ md.IsStatic &&
+ md.IsPublic &&
+ md.Parameters.Count == 1 &&
+ md.Parameters[0].ParameterType.InheritsFromOrImplements(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))), module).SingleOrDefault()?.Item1;
+ if (getter == null)
+ throw new XamlParseException($"Missing a public static Get{bpName} or a public instance property getter for the attached property \"{bpRef.DeclaringType}.{bpRef.Name}\"", iXmlLineInfo);
+ return getter.ResolveGenericReturnType(declaringTypeRef, module);
+ }
+
+ public static TypeReference GetBindablePropertyTypeConverter(this MemberReference bpRef, ModuleDefinition module)
+ {
+ TypeReference propertyDeclaringType;
+ var owner = bpRef.DeclaringType;
+ var bpName = bpRef.Name.EndsWith("Property", StringComparison.Ordinal) ? bpRef.Name.Substring(0, bpRef.Name.Length - 8) : bpRef.Name;
+ var property = owner.GetProperty(pd => pd.Name == bpName, out propertyDeclaringType);
+ var propertyType = property?.ResolveGenericPropertyType(propertyDeclaringType, module);
+ var staticGetter = owner.GetMethods(md => md.Name == $"Get{bpName}" &&
+ md.IsStatic &&
+ md.IsPublic &&
+ md.Parameters.Count == 1 &&
+ md.Parameters[0].ParameterType.InheritsFromOrImplements(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))), module).SingleOrDefault()?.Item1;
+
+ var attributes = new List<CustomAttribute>();
+ if (property != null && property.HasCustomAttributes)
+ attributes.AddRange(property.CustomAttributes);
+ if (propertyType != null && propertyType.ResolveCached().HasCustomAttributes)
+ attributes.AddRange(propertyType.ResolveCached().CustomAttributes);
+ if (staticGetter != null && staticGetter.HasCustomAttributes)
+ attributes.AddRange(staticGetter.CustomAttributes);
+ if (staticGetter != null && staticGetter.ReturnType.ResolveCached().HasCustomAttributes)
+ attributes.AddRange(staticGetter.ReturnType.ResolveCached().CustomAttributes);
+
+ return attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))?.ConstructorArguments [0].Value as TypeReference;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+using static System.String;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class BindablePropertyConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (IsNullOrEmpty(value)) {
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield break;
+ }
+ var bpRef = GetBindablePropertyFieldReference(value, module, node);
+ yield return Instruction.Create(OpCodes.Ldsfld, bpRef);
+ }
+
+ static public FieldReference GetBindablePropertyFieldReference(string value, ModuleDefinition module, BaseNode node)
+ {
+ FieldReference bpRef = null;
+ string typeName = null, propertyName = null;
+
+ var parts = value.Split('.');
+ if (parts.Length == 1) {
+ var parent = node.Parent?.Parent as IElementNode ?? (node.Parent?.Parent as IListNode)?.Parent as IElementNode;
+ if ( (node.Parent as ElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri
+ && ( (node.Parent as ElementNode)?.XmlType.Name == nameof(Setter)
+ || (node.Parent as ElementNode)?.XmlType.Name == nameof(XamlPropertyCondition))) {
+ if (parent.XmlType.NamespaceUri == XamlParser.XFUri &&
+ ( parent.XmlType.Name == "Trigger"
+ || parent.XmlType.Name == "DataTrigger"
+ || parent.XmlType.Name == "MultiTrigger"
+ || parent.XmlType.Name == "Style")) {
+ var ttnode = (parent as ElementNode).Properties [new XmlName("", "TargetType")];
+ if (ttnode is ValueNode)
+ typeName = (ttnode as ValueNode).Value as string;
+ else if (ttnode is IElementNode)
+ typeName = ((ttnode as IElementNode).CollectionItems.FirstOrDefault() as ValueNode)?.Value as string ?? ((ttnode as IElementNode).Properties [new XmlName("", "TypeName")] as ValueNode)?.Value as string;
+ } else if (parent.XmlType.NamespaceUri == XamlParser.XFUri && parent.XmlType.Name == nameof(VisualState)) {
+ typeName = FindTypeNameForVisualState(parent, node);
+ }
+ } else if ((node.Parent as ElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri && (node.Parent as ElementNode)?.XmlType.Name == "Trigger")
+ typeName = ((node.Parent as ElementNode).Properties [new XmlName("", "TargetType")] as ValueNode).Value as string;
+ propertyName = parts [0];
+ } else if (parts.Length == 2) {
+ typeName = parts [0];
+ propertyName = parts [1];
+ } else
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(BindableProperty)}", node);
+
+ if (typeName == null || propertyName == null)
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(BindableProperty)}", node);
+
+ var typeRef = XmlTypeExtensions.GetTypeReference(typeName, module, node);
+ if (typeRef == null)
+ throw new XamlParseException($"Can't resolve {typeName}", node);
+ bpRef = GetBindablePropertyFieldReference(typeRef, propertyName, module);
+ if (bpRef == null)
+ throw new XamlParseException($"Can't resolve {propertyName} on {typeRef.Name}", node);
+ return bpRef;
+ }
+
+ static string FindTypeNameForVisualState(IElementNode parent, IXmlLineInfo lineInfo)
+ {
+ //1. parent is VisualState, don't check that
+
+ //2. check that the VS is in a VSG
+ if (!(parent.Parent is IElementNode target) || target.XmlType.NamespaceUri != XamlParser.XFUri || target.XmlType.Name != nameof(VisualStateGroup))
+ throw new XamlParseException($"Expected {nameof(VisualStateGroup)} but found {parent.Parent}", lineInfo);
+
+ //3. if the VSG is in a VSGL, skip that as it could be implicit
+ if ( target.Parent is ListNode
+ || ( (target.Parent as IElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri
+ && (target.Parent as IElementNode)?.XmlType.Name == nameof(VisualStateGroupList)))
+ target = target.Parent.Parent as IElementNode;
+ else
+ target = target.Parent as IElementNode;
+
+ //4. target is now a Setter in a Style, or a VE
+ if (target.XmlType.NamespaceUri == XamlParser.XFUri && target.XmlType.Name == nameof(Setter))
+ return ((target?.Parent as IElementNode)?.Properties[new XmlName("", "TargetType")] as ValueNode)?.Value as string;
+ else
+ return target.XmlType.Name;
+ }
+
+ public static FieldReference GetBindablePropertyFieldReference(TypeReference typeRef, string propertyName, ModuleDefinition module)
+ {
+ TypeReference declaringTypeReference;
+ FieldReference bpRef = typeRef.GetField(fd => fd.Name == $"{propertyName}Property" && fd.IsStatic && fd.IsPublic, out declaringTypeReference);
+ if (bpRef != null) {
+ bpRef = module.ImportReference(bpRef.ResolveGenericParameters(declaringTypeReference));
+ bpRef.FieldType = module.ImportReference(bpRef.FieldType);
+ }
+ return bpRef;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml;
+
+using static System.String;
+using Tizen.NUI.Xaml.Build.Tasks;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class BindingTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (IsNullOrEmpty(value))
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Tizen.NUI.Binding.Binding)}", node);
+
+ yield return Instruction.Create(OpCodes.Ldstr, value);
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)BindingMode.Default);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Binding"), parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ (XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindingMode"),
+ (XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "IValueConverter"),
+ ("mscorlib", "System", "Object"),
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System", "Object")}));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class BoundsTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (string.IsNullOrEmpty(value))
+ throw new XamlParseException($"Cannot convert \"{value}\" into Rectangle", node);
+
+ double x = -1, y = -1, w = -1, h = -1;
+ bool hasX, hasY, hasW, hasH;
+ var xywh = value.Split(',');
+
+ foreach (var thick in xywh)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ if (xywh.Length != 2 && xywh.Length != 4)
+ throw new XamlParseException($"Cannot convert \"{value}\" into Rectangle", node);
+
+ hasX = (xywh.Length == 2 || xywh.Length == 4) && double.TryParse(xywh [0], NumberStyles.Number, CultureInfo.InvariantCulture, out x);
+ hasY = (xywh.Length == 2 || xywh.Length == 4) && double.TryParse(xywh [1], NumberStyles.Number, CultureInfo.InvariantCulture, out y);
+ hasW = xywh.Length == 4 && double.TryParse(xywh [2], NumberStyles.Number, CultureInfo.InvariantCulture, out w);
+ hasH = xywh.Length == 4 && double.TryParse(xywh [3], NumberStyles.Number, CultureInfo.InvariantCulture, out h);
+
+ if (!hasW && xywh.Length == 4 && string.Compare("AutoSize", xywh [2].Trim(), StringComparison.OrdinalIgnoreCase) == 0) {
+ hasW = true;
+ //w = AbsoluteLayout.AutoSize;
+ }
+
+ if (!hasH && xywh.Length == 4 && string.Compare("AutoSize", xywh [3].Trim(), StringComparison.OrdinalIgnoreCase) == 0) {
+ hasH = true;
+ //h = AbsoluteLayout.AutoSize;
+ }
+
+ if (hasX && hasY && xywh.Length == 2) {
+ hasW = true;
+ //w = AbsoluteLayout.AutoSize;
+ hasH = true;
+ //h = AbsoluteLayout.AutoSize;
+ }
+
+ if (!hasX || !hasY || !hasW || !hasH)
+ throw new XamlParseException($"Cannot convert \"{value}\" into Rectangle", node);
+
+ return GenerateIL(x, y, w, h, module);
+ }
+
+ IEnumerable<Instruction> GenerateIL(double x, double y, double w, double h, ModuleDefinition module)
+ {
+// IL_0000: ldc.r8 3.1000000000000001
+// IL_0009: ldc.r8 4.2000000000000002
+// IL_0012: ldc.r8 5.2999999999999998
+// IL_001b: ldc.r8 6.4000000000000004
+// IL_0024: newobj instance void valuetype Test.Rectangle::'.ctor'(float64, float64, float64, float64)
+
+ yield return Instruction.Create(OpCodes.Ldc_R8, x);
+ yield return Instruction.Create(OpCodes.Ldc_R8, y);
+ yield return Instruction.Create(OpCodes.Ldc_R8, w);
+ yield return Instruction.Create(OpCodes.Ldc_R8, h);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Rectangle"), parameterTypes: new[] {
+ ("mscorlib", "System", "Double"),
+ ("mscorlib", "System", "Double"),
+ ("mscorlib", "System", "Double"),
+ ("mscorlib", "System", "Double")}));
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class ColorTypeConverter : ICompiledTypeConverter
+ {
+ internal class Color
+ {
+ internal float r;
+ internal float g;
+ internal float b;
+ internal float a;
+
+ internal Color(float r, float g, float b, float a)
+ {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+ }
+
+ /// <summary>
+ /// Gets the black colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Black = new Color(0.0f, 0.0f, 0.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the white colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color White = new Color(1.0f, 1.0f, 1.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the red colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Red = new Color(1.0f, 0.0f, 0.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the green colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Green = new Color(0.0f, 1.0f, 0.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the blue colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Blue = new Color(0.0f, 0.0f, 1.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the yellow colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Yellow = new Color(1.0f, 1.0f, 0.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the magenta colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Magenta = new Color(1.0f, 0.0f, 1.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the cyan colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Cyan = new Color(0.0f, 1.0f, 1.0f, 1.0f);
+
+ /// <summary>
+ /// Gets the transparent colored Color class.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public static readonly Color Transparent = new Color(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params double[] args)
+ {
+ foreach (var d in args)
+ yield return Instruction.Create(OpCodes.Ldc_R8, d);
+
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Color"),
+ parameterTypes: args.Select(a => ("mscorlib", "System", "Single")).ToArray()));
+ }
+
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ Color ret = ConvertFromInvariantString(value);
+
+ if (null == ret)
+ {
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Color)}", node);
+ }
+
+ return GenerateIL(module, ret.r, ret.g, ret.b, ret.a);
+ }
+
+ private Color ConvertFromInvariantString(string value)
+ {
+ if (value != null)
+ {
+ value = value.Trim();
+ if (value.StartsWith("#", StringComparison.Ordinal))
+ {
+ return FromHex(value);
+ }
+
+ string[] parts = value.Split(',');
+ if (parts.Length == 1) //like Red or Color.Red
+ {
+ parts = value.Split('.');
+ if (parts.Length == 1 || (parts.Length == 2 && parts[0] == "Color"))
+ {
+ string color = parts[parts.Length - 1];
+ switch (color)
+ {
+ case "Black": return Color.Black;
+ case "White": return Color.White;
+ case "Red": return Color.Red;
+ case "Green": return Color.Green;
+ case "Blue": return Color.Blue;
+ case "Yellow": return Color.Yellow;
+ case "Magenta": return Color.Magenta;
+ case "Cyan": return Color.Cyan;
+ case "Transparent": return Color.Transparent;
+ }
+ }
+ }
+ else if (parts.Length == 4) //like 0.5,0.5,0.5,0.5
+ {
+ return new Color(Single.Parse(parts[0].Trim(), CultureInfo.InvariantCulture),
+ Single.Parse(parts[1].Trim(), CultureInfo.InvariantCulture),
+ Single.Parse(parts[2].Trim(), CultureInfo.InvariantCulture),
+ Single.Parse(parts[3].Trim(), CultureInfo.InvariantCulture));
+ }
+ }
+
+ return null;
+ }
+
+ static uint ToHex(char c)
+ {
+ ushort x = (ushort)c;
+ if (x >= '0' && x <= '9')
+ return (uint)(x - '0');
+
+ x |= 0x20;
+ if (x >= 'a' && x <= 'f')
+ return (uint)(x - 'a' + 10);
+ return 0;
+ }
+
+ static uint ToHexD(char c)
+ {
+ var j = ToHex(c);
+ return (j << 4) | j;
+ }
+
+ public static Color FromRgba(int r, int g, int b, int a)
+ {
+ float red = (float)r / 255;
+ float green = (float)g / 255;
+ float blue = (float)b / 255;
+ float alpha = (float)a / 255;
+ return new Color(red, green, blue, alpha);
+ }
+
+ public static Color FromRgb(int r, int g, int b)
+ {
+ return FromRgba(r, g, b, 255);
+ }
+
+ static Color FromHex(string hex)
+ {
+ // Undefined
+ if (hex.Length < 3)
+ return Color.Black;
+ int idx = (hex[0] == '#') ? 1 : 0;
+
+ switch (hex.Length - idx)
+ {
+ case 3: //#rgb => ffrrggbb
+ var t1 = ToHexD(hex[idx++]);
+ var t2 = ToHexD(hex[idx++]);
+ var t3 = ToHexD(hex[idx]);
+
+ return FromRgb((int)t1, (int)t2, (int)t3);
+
+ case 4: //#rgba => rrggbbaa
+ var f1 = ToHexD(hex[idx++]);
+ var f2 = ToHexD(hex[idx++]);
+ var f3 = ToHexD(hex[idx++]);
+ var f4 = ToHexD(hex[idx]);
+ return FromRgba((int)f1, (int)f2, (int)f3, (int)f4);
+
+ case 6: //#rrggbb => ffrrggbb
+ return FromRgb((int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
+ (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
+ (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx])));
+
+ case 8: //#rrggbbaa
+ return FromRgba((int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
+ (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
+ (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
+ (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx])));
+
+ default: //everything else will result in unexpected results
+ return Color.Black;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Data;
+using System.Globalization;
+
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class ConstraintTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ double size;
+
+ if (string.IsNullOrEmpty(value) || !double.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out size))
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Constraint)}", node);
+
+ yield return Create(Ldc_R8, size);
+ yield return Create(Call, module.ImportMethodReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Constraint"),
+ methodName: "Constant",
+ parameterTypes: new[] { ("mscorlib", "System", "Double") },
+ isStatic: true));
+ }
+ }
+}
--- /dev/null
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+
+using Tizen.NUI;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ internal class ExtentsTypeConverter : ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params ushort[] args)
+ {
+ foreach (var d in args)
+ yield return Instruction.Create(OpCodes.Ldc_I4, d);
+
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Extents"),
+ parameterTypes: args.Select(a => ("mscorlib", "System", "UInt16")).ToArray()));
+ }
+
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ var thickness = value.Split(',');
+
+ foreach (var thick in thickness)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ if (4 == thickness.Length)
+ {
+ ushort start, end, top, bottom;
+
+ if (ushort.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out start) &&
+ ushort.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out end) &&
+ ushort.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out top) &&
+ ushort.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out bottom))
+
+ return GenerateIL(module, start, end, top, bottom);
+ }
+ else if (1 == thickness.Length)
+ {
+ ushort v;
+ ushort.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out v);
+ return GenerateIL(module, v, v, v, v);
+ }
+ }
+
+ throw new XamlParseException($"Cannot convert \"{value}\" into Position", node);
+ }
+ }
+}
--- /dev/null
+using System.Collections.Generic;
+using Mono.Cecil.Cil;
+using Mono.Cecil;
+using Tizen.NUI.Xaml;
+using System;
+using Tizen.NUI.Xaml.Build.Tasks;
+using System.Linq;
+
+namespace Tizen.NUI.Xaml
+{
+ interface ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node);
+ }
+}
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ //only used in unit tests to make sure the compiled InitializeComponent is invoked
+ class IsCompiledTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ if (value != "IsCompiled?")
+ throw new Exception();
+ yield return Instruction.Create(OpCodes.Ldc_I4_1);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class LayoutOptionsConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ do {
+ if (string.IsNullOrEmpty(value))
+ break;
+
+ value = value.Trim();
+
+ var parts = value.Split('.');
+ if (parts.Length == 1 || (parts.Length == 2 && parts [0] == "LayoutOptions")) {
+ var options = parts [parts.Length - 1];
+
+ var fieldReference = module.ImportFieldReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "LayoutOptions"),
+ fieldName: options,
+ isStatic: true);
+ if (fieldReference != null) {
+ yield return Instruction.Create(OpCodes.Ldsfld, fieldReference);
+ yield break;
+ }
+ }
+ } while (false);
+
+ throw new XamlParseException(String.Format("Cannot convert \"{0}\" into LayoutOptions", value), node);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class ListStringTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (value == null) {
+ yield return Create(Ldnull);
+ yield break;
+ }
+ var parts = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToList();
+
+ yield return Create(Ldc_I4, parts.Count);
+ yield return Create(Newobj, module.ImportCtorReference(("System.Collections", "System.Collections.Generic", "List`1"),
+ parameterTypes: new[] { ("mscorlib", "System", "Int32") },
+ classArguments: new[] { ("mscorlib", "System", "String") }));
+ foreach (var part in parts) {
+ yield return Create(Dup);
+ yield return Create(Ldstr, part);
+ yield return Create(Callvirt, module.ImportMethodReference(("mscorlib", "System.Collections.Generic", "ICollection`1"),
+ methodName: "Add",
+ paramCount: 1,
+ classArguments: new[] { ("mscorlib", "System", "String") }));
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ internal class PositionTypeConverter : ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params double[] args)
+ {
+ foreach (var d in args)
+ yield return Instruction.Create(OpCodes.Ldc_R8, d);
+
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Position"),
+ parameterTypes: args.Select(a => ("mscorlib", "System", "Single")).ToArray()));
+ }
+
+ private IEnumerable<Instruction> ConvertToPoint(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ switch (value)
+ {
+ case "Top":
+ return GenerateIL(module, 0.0);
+ case "Bottom":
+ return GenerateIL(module, 1.0);
+ case "Left":
+ return GenerateIL(module, 0.0);
+ case "Right":
+ return GenerateIL(module, 1.0);
+ case "Middle":
+ return GenerateIL(module, 0.5);
+ case "TopLeft":
+ return GenerateIL(module, 0.0, 0.0, 0.5);
+ case "TopCenter":
+ return GenerateIL(module, 0.5, 0.0, 0.5);
+ case "TopRight":
+ return GenerateIL(module, 1.0, 0.0, 0.5);
+ case "CenterLeft":
+ return GenerateIL(module, 0.0, 0.5, 0.5);
+ case "Center":
+ return GenerateIL(module, 0.5, 0.5, 0.5);
+ case "CenterRight":
+ return GenerateIL(module, 1.0, 0.5, 0.5);
+ case "BottomLeft":
+ return GenerateIL(module, 0.0, 1.0, 0.5);
+ case "BottomCenter":
+ return GenerateIL(module, 0.5, 1.0, 0.5);
+ case "BottomRight":
+ return GenerateIL(module, 1.0, 1.0, 0.5);
+ }
+
+ throw new XamlParseException($"Cannot convert \"{value}\" into Position", node);
+ }
+
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ var thickness = value.Split(',');
+
+ foreach (var thick in thickness)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ if (3 == thickness.Length)
+ {
+ double x, y, z;
+
+ if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) &&
+ double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y) &&
+ double.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out z))
+ return GenerateIL(module, x, y, z);
+ }
+ else if (2 == thickness.Length)
+ {
+ double x, y;
+
+ if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) &&
+ double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y))
+ return GenerateIL(module, x, y, 0);
+ }
+ else if (1 == thickness.Length)
+ {
+ if (value.Contains("."))
+ {
+ string[] parts = value.Split('.');
+ if (parts.Length == 2 && (parts[0].Trim() == "ParentOrigin" || parts[0].Trim() == "PivotPoint"))
+ {
+ string position = parts[parts.Length - 1].Trim();
+ return ConvertToPoint(position, context, node);
+ }
+ }
+ else
+ {
+ return ConvertToPoint(value, context, node);
+ }
+ }
+
+ throw new XamlParseException($"Cannot convert \"{value}\" into Position", node);
+ }
+ }
+
+ internal class Position2DTypeConverter : ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params int[] args)
+ {
+ foreach (var d in args)
+ yield return Instruction.Create(OpCodes.Ldc_I4, d);
+
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Position2D"),
+ parameterTypes: args.Select(a => ("mscorlib", "System", "Int32")).ToArray()));
+ }
+
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ int x, y;
+ var thickness = value.Split(',');
+
+ foreach (var thick in thickness)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ if (int.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) &&
+ int.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y))
+ return GenerateIL(module, x, y);
+ }
+
+ throw new XamlParseException($"Cannot convert \"{value}\" into Position2D", node);
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+using Tizen.NUI.Xaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class RDSourceTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+ var body = context.Body;
+
+ INode rootNode = node;
+ while (!(rootNode is ILRootNode))
+ rootNode = rootNode.Parent;
+
+ var rdNode = node.Parent as IElementNode;
+
+ var rootTargetPath = XamlTask.GetPathForType(module, ((ILRootNode)rootNode).TypeReference);
+ var uri = new Uri(value, UriKind.Relative);
+
+ var resourcePath = ResourceDictionary.RDSourceTypeConverter.GetResourcePath(uri, rootTargetPath);
+
+ //fail early
+ var resourceId = XamlTask.GetResourceIdForPath(module, resourcePath);
+ if (resourceId == null)
+ throw new XamlParseException($"Resource '{value}' not found.", node);
+
+
+ //abuse the converter, produce some side effect, but leave the stack untouched
+ //public void SetAndLoadSource(Uri value, string resourceID, Assembly assembly, System.Xml.IXmlLineInfo lineInfo)
+ yield return Create(Ldloc, context.Variables[rdNode]); //the resourcedictionary
+ foreach (var instruction in (new UriTypeConverter()).ConvertFromString(value, context, node))
+ yield return instruction; //the Uri
+
+ //keep the Uri for later
+ yield return Create(Dup);
+ var uriVarDef = new VariableDefinition(module.ImportReference(("System", "System", "Uri")));
+ body.Variables.Add(uriVarDef);
+ yield return Create(Stloc, uriVarDef);
+ yield return Create(Ldstr, resourcePath); //resourcePath
+ yield return Create(Ldtoken, module.ImportReference(((ILRootNode)rootNode).TypeReference));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System.Reflection", "IntrospectionExtensions"), methodName: "GetTypeInfo", parameterTypes: new[] { ("mscorlib", "System", "Type") }, isStatic: true));
+ yield return Create(Callvirt, module.ImportPropertyGetterReference(("mscorlib", "System.Reflection", "TypeInfo"), propertyName: "Assembly", flatten: true));
+
+ foreach (var instruction in node.PushXmlLineInfo(context))
+ yield return instruction; //lineinfo
+ yield return Create(Callvirt, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "ResourceDictionary"),
+ methodName: "SetAndLoadSource",
+ parameterTypes: new[] { ("System", "System", "Uri"), ("mscorlib", "System", "String"), ("mscorlib", "System.Reflection", "Assembly"), ("System.Xml.ReaderWriter", "System.Xml", "IXmlLineInfo") }));
+ //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((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlResourceIdAttribute"))))
+ continue;
+ if (!TypeRefComparer.Default.Equals(ca.ConstructorArguments[2].Value as TypeReference, type))
+ continue;
+ return ca.ConstructorArguments[1].Value as string;
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class RectangleTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (string.IsNullOrEmpty(value))
+ throw new XamlParseException($"Cannot convert \"{value}\" into Rectangle", node);
+ double x, y, w, h;
+ var xywh = value.Split(',');
+
+ foreach (var thick in xywh)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ if (xywh.Length != 4 ||
+ !double.TryParse(xywh [0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) ||
+ !double.TryParse(xywh [1], NumberStyles.Number, CultureInfo.InvariantCulture, out y) ||
+ !double.TryParse(xywh [2], NumberStyles.Number, CultureInfo.InvariantCulture, out w) ||
+ !double.TryParse(xywh [3], NumberStyles.Number, CultureInfo.InvariantCulture, out h))
+ throw new XamlParseException($"Cannot convert \"{value}\" into Rectangle", node);
+
+ return GenerateIL(x, y, w, h, module);
+ }
+
+ IEnumerable<Instruction> GenerateIL(double x, double y, double w, double h, ModuleDefinition module)
+ {
+// IL_0000: ldc.r8 3.1000000000000001
+// IL_0009: ldc.r8 4.2000000000000002
+// IL_0012: ldc.r8 5.2999999999999998
+// IL_001b: ldc.r8 6.4000000000000004
+// IL_0024: newobj instance void valuetype Test.Rectangle::'.ctor'(int, int, int, int)
+
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)x);
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)y);
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)w);
+ yield return Instruction.Create(OpCodes.Ldc_I4, (int)h);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Rectangle"), parameterTypes: new[] {
+ ("mscorlib", "System", "Int32"),
+ ("mscorlib", "System", "Int32"),
+ ("mscorlib", "System", "Int32"),
+ ("mscorlib", "System", "Int32")}));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ internal class SizeTypeConverter : ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params float[] args)
+ {
+ foreach (var d in args)
+ yield return Instruction.Create(OpCodes.Ldc_R4, d);
+
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Size"),
+ parameterTypes: args.Select(a => ("mscorlib", "System", "Single")).ToArray()));
+ }
+
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ var thickness = value.Split(',');
+
+ foreach (var thick in thickness)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ if (3 == thickness.Length)
+ {
+ float x, y, z;
+
+ if (float.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) &&
+ float.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y) &&
+ float.TryParse(thickness[2], NumberStyles.Number, CultureInfo.InvariantCulture, out z))
+ return GenerateIL(module, x, y, z);
+ }
+ else if (2 == thickness.Length)
+ {
+ float x, y;
+
+ if (float.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) &&
+ float.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y))
+ return GenerateIL(module, x, y, 0);
+ }
+ }
+
+ throw new XamlParseException($"Cannot convert \"{value}\" into Size", node);
+ }
+ }
+
+ internal class Size2DTypeConverter : ICompiledTypeConverter
+ {
+ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params int[] args)
+ {
+ foreach (var d in args)
+ yield return Instruction.Create(OpCodes.Ldc_I4, d);
+
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.nuiAssemblyName, XamlTask.nuiNameSpace, "Size2D"),
+ parameterTypes: args.Select(a => ("mscorlib", "System", "Int32")).ToArray()));
+ }
+
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ int x, y;
+ var thickness = value.Split(',');
+
+ foreach (var thick in thickness)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ if (int.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) &&
+ int.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y))
+ return GenerateIL(module, x, y);
+ }
+
+ throw new XamlParseException($"Cannot convert \"{value}\" into Size2D", node);
+ }
+ }
+}
--- /dev/null
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class ThicknessTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (!string.IsNullOrEmpty(value)) {
+ double l, t, r, b;
+ var thickness = value.Split(',');
+
+ foreach (var thick in thickness)
+ {
+ if (thick.EndsWith("dp") || thick.EndsWith("px"))
+ {
+ return null;
+ }
+ }
+
+ switch (thickness.Length) {
+ case 1:
+ if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l))
+ return GenerateIL(module, l);
+ break;
+ case 2:
+ if (double.TryParse(thickness[0], NumberStyles.Number, CultureInfo.InvariantCulture, out l) &&
+ double.TryParse(thickness[1], NumberStyles.Number, CultureInfo.InvariantCulture, out t))
+ return GenerateIL(module, l, t);
+ 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))
+ return GenerateIL(module, l, t, r, b);
+ break;
+ }
+ }
+ throw new XamlParseException($"Cannot convert \"{value}\" into Thickness", node);
+ }
+
+ IEnumerable<Instruction> GenerateIL(ModuleDefinition module, params double[] args)
+ {
+ foreach (var d in args)
+ yield return Instruction.Create(OpCodes.Ldc_R8, d);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Thickness"), parameterTypes: args.Select(a => ("mscorlib", "System", "Double")).ToArray()));
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Xml;
+
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class TypeTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (string.IsNullOrEmpty(value))
+ goto error;
+
+ var split = value.Split(':');
+ if (split.Length > 2)
+ goto error;
+
+ XmlType xmlType;
+ if (split.Length == 2)
+ xmlType = new XmlType(node.NamespaceResolver.LookupNamespace(split[0]), split[1], null);
+ else
+ xmlType = new XmlType(node.NamespaceResolver.LookupNamespace(""), split[0], null);
+
+ var typeRef = xmlType.GetTypeReference(module, (IXmlLineInfo)node, true);
+ if (typeRef == null)
+ goto error;
+
+ yield return Create(Ldtoken, module.ImportReference(typeRef));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"),
+ methodName: "GetTypeFromHandle",
+ parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") },
+ isStatic: true));
+
+ yield break;
+
+ error:
+ throw new XamlParseException($"Cannot convert \"{value}\" into {typeof(Type)}", node);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class UriTypeConverter : ICompiledTypeConverter
+ {
+ public IEnumerable<Instruction> ConvertFromString(string value, ILContext context, BaseNode node)
+ {
+ var module = context.Body.Method.Module;
+
+ if (string.IsNullOrWhiteSpace(value)) {
+ yield return Create(Ldnull);
+ yield break;
+ }
+
+ yield return Create(Ldstr, value);
+ yield return Create(Ldc_I4_0); //UriKind.RelativeOrAbsolute
+ yield return Create(Newobj, module.ImportCtorReference(("System", "System", "Uri"), parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("System", "System", "UriKind")}));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [ContentProperty("Items")]
+ class ArrayExtension : ICompiledMarkupExtension
+ {
+ public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference memberRef)
+ {
+ var typeNode = node.Properties[new XmlName("", "Type")] as IElementNode;
+ var typeTypeRef = context.TypeExtensions[typeNode];
+ var n = node.CollectionItems.Count;
+
+ var instructions = new List<Instruction>();
+ instructions.Add(Instruction.Create(OpCodes.Ldc_I4, n));
+ instructions.Add(Instruction.Create(OpCodes.Newarr, typeTypeRef));
+
+ memberRef = typeTypeRef.MakeArrayType();
+ for (var i = 0; i < n; i++)
+ {
+ var vardef = context.Variables[node.CollectionItems[i] as IElementNode];
+ if (typeTypeRef.IsValueType)
+ {
+ instructions.Add(Instruction.Create(OpCodes.Dup));
+ instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i));
+ instructions.Add(Instruction.Create(OpCodes.Ldelema, typeTypeRef));
+ instructions.Add(Instruction.Create(OpCodes.Ldloc, vardef));
+ if (vardef.VariableType == module.TypeSystem.Object)
+ instructions.Add(Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(typeTypeRef)));
+ instructions.Add(Instruction.Create(OpCodes.Stobj, typeTypeRef));
+ }
+ else
+ {
+ instructions.Add(Instruction.Create(OpCodes.Dup));
+ instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i));
+ instructions.Add(Instruction.Create(OpCodes.Ldloc, vardef));
+ instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
+ }
+ }
+ return instructions;
+ }
+
+ public EXamlCreateObject ProvideValue(IElementNode node, ModuleDefinition module, EXamlContext Context)
+ {
+ return new EXamlCreateArrayObject(Context, Type.MakeArrayType(), items);
+ }
+
+ public TypeReference Type
+ {
+ get;
+ set;
+ }
+
+ public object Items
+ {
+ get
+ {
+ return null;
+ }
+ set
+ {
+ if (null == items)
+ {
+ items = new List<object>();
+ }
+
+ items.Add(value);
+ }
+ }
+
+ private List<object> items;
+ }
+}
\ No newline at end of file
--- /dev/null
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using System.Collections.Generic;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ interface ICompiledMarkupExtension
+ {
+ IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference typeRef);
+
+ EXamlCreateObject ProvideValue(IElementNode node, ModuleDefinition module, EXamlContext Context);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class NullExtension : ICompiledMarkupExtension
+ {
+ public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference typeRef)
+ {
+ typeRef = module.TypeSystem.Object;
+ return new[] { Instruction.Create(OpCodes.Ldnull) };
+ }
+
+ public EXamlCreateObject ProvideValue(IElementNode node, ModuleDefinition module, EXamlContext Context)
+ {
+ return null;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using System.Xml;
+
+using static System.String;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class StaticExtension : ICompiledMarkupExtension
+ {
+ public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference memberRef)
+ {
+ INode ntype;
+ if (!node.Properties.TryGetValue(new XmlName("", "Member"), out ntype))
+ ntype = node.CollectionItems[0];
+ var member = ((ValueNode)ntype).Value as string;
+
+ if (IsNullOrEmpty(member) || !member.Contains("."))
+ {
+ var lineInfo = node as IXmlLineInfo;
+ throw new XamlParseException("Syntax for x:Static is [Member=][prefix:]typeName.staticMemberName", lineInfo);
+ }
+
+ var dotIdx = member.LastIndexOf('.');
+ var typename = member.Substring(0, dotIdx);
+ var membername = member.Substring(dotIdx + 1);
+
+ var typeRef = module.ImportReference(XmlTypeExtensions.GetTypeReference(typename, module, node as BaseNode));
+ var fieldRef = GetFieldReference(typeRef, membername, module);
+ var propertyDef = GetPropertyDefinition(typeRef, membername, module);
+
+ if (fieldRef == null && propertyDef == null)
+ throw new XamlParseException($"x:Static: unable to find a public static field, static property, const or enum value named {membername} in {typename}", node as IXmlLineInfo);
+
+ var fieldDef = fieldRef?.Resolve();
+ if (fieldRef != null)
+ {
+ memberRef = fieldRef.FieldType;
+ if (!fieldDef.HasConstant)
+ return new[] { Instruction.Create(OpCodes.Ldsfld, fieldRef) };
+
+ //Constants can be numbers, Boolean values, strings, or a null reference. (https://msdn.microsoft.com/en-us/library/e6w8fe1b.aspx)
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Boolean))
+ return new[] { Instruction.Create(((bool)fieldDef.Constant) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.String))
+ return new[] { Instruction.Create(OpCodes.Ldstr, (string)fieldDef.Constant) };
+ if (fieldDef.Constant == null)
+ return new[] { Instruction.Create(OpCodes.Ldnull) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Char))
+ return new[] { Instruction.Create(OpCodes.Ldc_I4, (char)fieldDef.Constant) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Single))
+ return new[] { Instruction.Create(OpCodes.Ldc_R4, (float)fieldDef.Constant) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Double))
+ return new[] { Instruction.Create(OpCodes.Ldc_R8, (double)fieldDef.Constant) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Byte) || TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Int16) || TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Int32))
+ return new[] { Instruction.Create(OpCodes.Ldc_I4, (int)fieldDef.Constant) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.SByte) || TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.UInt16) || TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.UInt32))
+ return new[] { Instruction.Create(OpCodes.Ldc_I4, (uint)fieldDef.Constant) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.Int64))
+ return new[] { Instruction.Create(OpCodes.Ldc_I8, (long)fieldDef.Constant) };
+ if (TypeRefComparer.Default.Equals(memberRef, module.TypeSystem.UInt64))
+ return new[] { Instruction.Create(OpCodes.Ldc_I8, (ulong)fieldDef.Constant) };
+
+ //enum values
+ if (memberRef.ResolveCached().IsEnum)
+ {
+ if (fieldDef.Constant is long)
+ return new[] { Instruction.Create(OpCodes.Ldc_I8, (long)fieldDef.Constant) };
+ if (fieldDef.Constant is ulong)
+ return new[] { Instruction.Create(OpCodes.Ldc_I8, (ulong)fieldDef.Constant) };
+ if (fieldDef.Constant is uint)
+ return new[] { Instruction.Create(OpCodes.Ldc_I4, (uint)fieldDef.Constant) };
+ //everything else will cast just fine to an int
+ return new[] { Instruction.Create(OpCodes.Ldc_I4, (int)fieldDef.Constant) };
+ }
+ }
+
+ memberRef = propertyDef.PropertyType;
+ var getterDef = module.ImportReference(propertyDef.GetMethod);
+ return new[] { Instruction.Create(OpCodes.Call, getterDef) };
+ }
+
+ public EXamlCreateObject ProvideValue(IElementNode node, ModuleDefinition module, EXamlContext Context)
+ {
+ INode ntype;
+ if (!node.Properties.TryGetValue(new XmlName("", "Member"), out ntype))
+ ntype = node.CollectionItems[0];
+ var member = ((ValueNode)ntype).Value as string;
+
+ if (IsNullOrEmpty(member) || !member.Contains("."))
+ {
+ var lineInfo = node as IXmlLineInfo;
+ throw new XamlParseException("Syntax for x:Static is [Member=][prefix:]typeName.staticMemberName", lineInfo);
+ }
+
+ var dotIdx = member.LastIndexOf('.');
+ var typename = member.Substring(0, dotIdx);
+ var membername = member.Substring(dotIdx + 1);
+
+ var typeRef = module.ImportReference(XmlTypeExtensions.GetTypeReference(typename, module, node as BaseNode));
+ var fieldRef = GetFieldReference(typeRef, membername, module);
+ var propertyDef = GetPropertyDefinition(typeRef, membername, module);
+
+ var ret = EXamlCreateObject.GetStaticInstance(Context, typeRef, fieldRef, propertyDef);
+ if (null == ret)
+ {
+ throw new XamlParseException($"{membername} is not static member in type {typename}", node as IXmlLineInfo);
+ }
+ return ret;
+ }
+
+ public static FieldReference GetFieldReference(TypeReference typeRef, string fieldName, ModuleDefinition module)
+ {
+ TypeReference declaringTypeReference;
+ FieldReference fRef = typeRef.GetField(fd => fd.Name == fieldName &&
+ fd.IsStatic &&
+ fd.IsPublic, out declaringTypeReference);
+ if (fRef != null)
+ {
+ fRef = module.ImportReference(fRef.ResolveGenericParameters(declaringTypeReference));
+ fRef.FieldType = module.ImportReference(fRef.FieldType);
+ }
+ return fRef;
+ }
+
+ public static PropertyDefinition GetPropertyDefinition(TypeReference typeRef, string propertyName, ModuleDefinition module)
+ {
+ TypeReference declaringTypeReference;
+ PropertyDefinition pDef = typeRef.GetProperty(pd => pd.Name == propertyName &&
+ pd.GetMethod.IsPublic &&
+ pd.GetMethod.IsStatic, out declaringTypeReference);
+ return pDef;
+ }
+ }
+}
--- /dev/null
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class TypeExtension : ICompiledMarkupExtension
+ {
+ public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference memberRef)
+ {
+ memberRef = module.ImportReference(("mscorlib", "System", "Type"));
+ INode typeNameNode;
+
+ var name = new XmlName("", "TypeName");
+ if (!node.Properties.TryGetValue(name, out typeNameNode) && node.CollectionItems.Any())
+ typeNameNode = node.CollectionItems[0];
+
+ var valueNode = typeNameNode as ValueNode;
+ if (valueNode == null)
+ throw new XamlParseException("TypeName isn't set.", node as XmlLineInfo);
+
+ if (!node.Properties.ContainsKey(name))
+ {
+ node.Properties[name] = typeNameNode;
+ node.CollectionItems.Clear();
+ }
+
+ var typeref = module.ImportReference(XmlTypeExtensions.GetTypeReference(valueNode.Value as string, module, node as BaseNode));
+
+ context.TypeExtensions[node] = typeref ?? throw new XamlParseException($"Can't resolve type `{valueNode.Value}'.", node as IXmlLineInfo);
+
+ return new List<Instruction> {
+ Create(Ldtoken, module.ImportReference(typeref)),
+ Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"),
+ methodName: "GetTypeFromHandle",
+ parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") },
+ isStatic: true)),
+ };
+ }
+
+ public EXamlCreateObject ProvideValue(IElementNode node, ModuleDefinition module, EXamlContext context)
+ {
+ INode typeNameNode;
+
+ var name = new XmlName("", "TypeName");
+ if (!node.Properties.TryGetValue(name, out typeNameNode) && node.CollectionItems.Any())
+ typeNameNode = node.CollectionItems[0];
+
+ var valueNode = typeNameNode as ValueNode;
+ if (valueNode == null)
+ throw new XamlParseException("TypeName isn't set.", node as XmlLineInfo);
+
+ if (!node.Properties.ContainsKey(name))
+ {
+ node.Properties[name] = typeNameNode;
+ node.CollectionItems.Clear();
+ }
+
+ var typeref = module.ImportReference(XmlTypeExtensions.GetTypeReference(valueNode.Value as string, module, node as BaseNode));
+
+ context.TypeExtensions[node] = typeref ?? throw new XamlParseException($"Can't resolve type `{valueNode.Value}'.", node as IXmlLineInfo);
+
+ return new EXamlCreateObject(context, typeref, module.ImportReference(typeof(TypeReference)));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml
+{
+ interface ICompiledValueProvider
+ {
+ IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context);
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class PassthroughValueProvider : ICompiledValueProvider
+ {
+ public IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context)
+ {
+ yield break;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml;
+using Tizen.NUI.Xaml.Build.Tasks;
+using System.Xml;
+
+namespace Tizen.NUI.Xaml.Core.XamlC
+{
+ class SetterValueProvider : ICompiledValueProvider
+ {
+ public IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context)
+ {
+ INode valueNode = null;
+ if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Value"), out valueNode) &&
+ !((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Value"), out valueNode) &&
+ ((IElementNode)node).CollectionItems.Count == 1)
+ valueNode = ((IElementNode)node).CollectionItems[0];
+
+ var bpNode = ((ValueNode)((IElementNode)node).Properties[new XmlName("", "Property")]);
+ var bpRef = BindablePropertyConverter.GetBindablePropertyFieldReference((string)bpNode.Value, module, bpNode);
+
+ if (SetterValueIsCollection(bpRef, module, node, context))
+ yield break;
+
+ if (valueNode == null)
+ throw new XamlParseException("Missing Value for Setter", (IXmlLineInfo)node);
+
+ //if it's an elementNode, there's probably no need to convert it
+ if (valueNode is IElementNode)
+ yield break;
+
+ var value = ((string)((ValueNode)valueNode).Value);
+
+ //push the setter
+ yield return Instruction.Create(OpCodes.Ldloc, vardefref.VariableDefinition);
+
+ //push the value
+ foreach (var instruction in ((ValueNode)valueNode).PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context, bpRef: bpRef), boxValueTypes: true, unboxValueTypes: false))
+ yield return instruction;
+
+ //set the value
+ yield return Instruction.Create(OpCodes.Callvirt, module.ImportPropertySetterReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Setter"), propertyName: "Value"));
+ }
+
+ static bool SetterValueIsCollection(FieldReference bindablePropertyReference, ModuleDefinition module, BaseNode node, ILContext context)
+ {
+ var items = (node as IElementNode)?.CollectionItems;
+
+ if (items == null || items.Count <= 0)
+ return false;
+
+ // Is this a generic type ?
+ var generic = bindablePropertyReference.GetBindablePropertyType(node, module) as GenericInstanceType;
+
+ // With a single generic argument?
+ if (generic?.GenericArguments.Count != 1)
+ return false;
+
+ // Is the generic argument assignable from this value?
+ var genericType = generic.GenericArguments[0];
+
+ if (!(items[0] is IElementNode firstItem))
+ return false;
+
+ return context.Variables[firstItem].VariableType.InheritsFromOrImplements(genericType);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.Xaml.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);
+ yield return Create(Call, module.ImportMethodReference((XamlTask.xamlAssemblyName, "Tizen.NUI.StyleSheets", "StyleSheet"),
+ methodName: "FromString",
+ parameterTypes: new[] { ("mscorlib", "System", "String") },
+ isStatic: true));
+ }
+ else {
+ var 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 = XamlTask.GetResourceIdForPath(module, resourcePath);
+ if (resourceId == null)
+ throw new XamlParseException($"Resource '{source}' not found.", node);
+
+ yield return Create(Ldtoken, module.ImportReference(((ILRootNode)rootNode).TypeReference));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System.Reflection", "IntrospectionExtensions"), methodName: "GetTypeInfo", parameterTypes: new[] { ("mscorlib", "System", "Type") }, isStatic: true));
+ yield return Create(Callvirt, module.ImportPropertyGetterReference(("mscorlib", "System.Reflection", "TypeInfo"), propertyName: "Assembly", flatten: true));
+
+ yield return Create(Ldstr, resourceId); //resourceId
+
+ foreach (var instruction in node.PushXmlLineInfo(context))
+ yield return instruction; //lineinfo
+
+ yield return Create(Call, module.ImportMethodReference((XamlTask.xamlAssemblyName, "Tizen.NUI.StyleSheets", "StyleSheet"),
+ methodName: "FromAssemblyResource",
+ parameterTypes: new[] { ("mscorlib", "System.Reflection", "Assembly"), ("mscorlib", "System", "String"), ("System.Xml.ReaderWriter", "System.Xml", "IXmlLineInfo") },
+ isStatic: true));
+ }
+
+ //the variable is of type `object`. fix that
+ var vardef = new VariableDefinition(module.ImportReference((XamlTask.xamlAssemblyName, "Tizen.NUI.StyleSheets", "StyleSheet")));
+ yield return Create(Stloc, vardef);
+ vardefref.VariableDefinition = vardef;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+using System.Xml;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class CreateObjectVisitor : IXamlNodeVisitor
+ {
+ public CreateObjectVisitor(ILContext context)
+ {
+ Context = context;
+ Module = context.Body.Method.Module;
+ }
+
+ public ILContext Context { get; }
+
+ ModuleDefinition Module { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ Context.Values[node] = node.Value;
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ //At this point, all MarkupNodes are expanded to ElementNodes
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ var typeref = Module.ImportReference(node.XmlType.GetTypeReference(Module, node));
+ TypeDefinition typedef = typeref.ResolveCached();
+
+ if (IsXaml2009LanguagePrimitive(node))
+ {
+ var vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+ Context.Body.Variables.Add(vardef);
+
+ Context.IL.Append(PushValueFromLanguagePrimitive(typeref, node));
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ return;
+ }
+
+ //if this is a MarkupExtension that can be compiled directly, compile and returns the value
+ var compiledMarkupExtensionName = typeref
+ .GetCustomAttribute(Module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "ProvideCompiledAttribute"))
+ ?.ConstructorArguments?[0].Value as string;
+ Type compiledMarkupExtensionType;
+ ICompiledMarkupExtension markupProvider;
+ if (compiledMarkupExtensionName != null &&
+ (compiledMarkupExtensionType = Type.GetType(compiledMarkupExtensionName)) != null &&
+ (markupProvider = Activator.CreateInstance(compiledMarkupExtensionType) as ICompiledMarkupExtension) != null)
+ {
+
+ var il = markupProvider.ProvideValue(node, Module, Context, out typeref);
+ typeref = Module.ImportReference(typeref);
+
+ var vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+ Context.Body.Variables.Add(vardef);
+
+ Context.IL.Append(il);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+
+ //clean the node as it has been fully exhausted
+ foreach (var prop in node.Properties)
+ if (!node.SkipProperties.Contains(prop.Key))
+ node.SkipProperties.Add(prop.Key);
+ node.CollectionItems.Clear();
+ return;
+ }
+
+ MethodDefinition factoryCtorInfo = null;
+ MethodDefinition factoryMethodInfo = null;
+ TypeDefinition ownerTypeOfFactoryMethod = null;
+ MethodDefinition parameterizedCtorInfo = null;
+ MethodDefinition ctorInfo = null;
+
+ if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod))
+ {
+ factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
+ !md.IsStatic &&
+ md.HasParameters &&
+ md.MatchXArguments(node, typeref, Module, Context));
+ if (factoryCtorInfo == null)
+ {
+ throw new XamlParseException(
+ string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
+ }
+ ctorInfo = factoryCtorInfo;
+ if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
+ Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
+ }
+ else if (node.Properties.ContainsKey(XmlName.xFactoryMethod))
+ {
+ var factoryMethod = (string)(node.Properties[XmlName.xFactoryMethod] as ValueNode).Value;
+ factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
+ md.Name == factoryMethod &&
+ md.IsStatic &&
+ md.MatchXArguments(node, typeref, Module, Context));
+ if (factoryMethodInfo == null)
+ {
+ var typeExtensionRef = Module.ImportReference(node.XmlType.GetTypeExtensionReference(Module, node));
+ typeExtensionRef = typeExtensionRef?.ResolveCached();
+
+ if (null != typeExtensionRef?.Resolve())
+ {
+ factoryMethodInfo = typeExtensionRef.Resolve().AllMethods().FirstOrDefault(md => !md.IsConstructor &&
+ md.Name == factoryMethod &&
+ md.IsStatic &&
+ md.MatchXArguments(node, typeref, Module, Context));
+
+ if (null != factoryMethod)
+ {
+ ownerTypeOfFactoryMethod = typeExtensionRef.ResolveCached();
+ }
+ }
+ }
+ else
+ {
+ ownerTypeOfFactoryMethod = typedef;
+
+ }
+
+ if (factoryMethodInfo == null)
+ {
+ throw new XamlParseException(
+ String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
+ }
+ Context.IL.Append(PushCtorXArguments(factoryMethodInfo, node));
+ }
+ if (ctorInfo == null && factoryMethodInfo == null)
+ {
+ parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
+ !md.IsStatic &&
+ md.HasParameters &&
+ md.Parameters.All(
+ pd =>
+ pd.CustomAttributes.Any(
+ ca =>
+ ca.AttributeType.FullName ==
+ "Tizen.NUI.Binding.ParameterAttribute")));
+ }
+ string missingCtorParameter = null;
+ if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node, out missingCtorParameter))
+ {
+ ctorInfo = parameterizedCtorInfo;
+ // IL_0000: ldstr "foo"
+ Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
+ }
+
+ ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
+
+ if (null == ctorInfo && null == factoryMethodInfo)
+ {
+ foreach (var method in typedef.Methods)
+ {
+ if (method.IsConstructor && !method.IsStatic)
+ {
+ bool areAllParamsDefault = true;
+
+ foreach (var param in method.Parameters)
+ {
+ if (!param.HasDefault)
+ {
+ areAllParamsDefault = false;
+ break;
+ }
+ }
+
+ if (areAllParamsDefault)
+ {
+ if (null == ctorInfo)
+ {
+ ctorInfo = method;
+ }
+ else
+ {
+ throw new XamlParseException($"{typedef.FullName} has more than one constructor which params are all default.", node);
+ }
+ }
+ }
+ }
+
+ if (null == ctorInfo)
+ {
+ if (!typedef.IsValueType)
+ {
+ throw new XamlParseException($"{typedef.FullName} has no constructor which params are all default.", node);
+ }
+ }
+ else
+ {
+ factoryCtorInfo = ctorInfo;
+
+ if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
+ {
+ Context.IL.Append(PushCtorDefaultArguments(factoryCtorInfo, node));
+ }
+ }
+ }
+
+ if (parameterizedCtorInfo != null && ctorInfo == null)
+ //there was a parameterized ctor, we didn't use it
+ throw new XamlParseException($"The Property '{missingCtorParameter}' is required to create a '{typedef.FullName}' object.", node);
+ var ctorinforef = ctorInfo?.ResolveGenericParameters(typeref, Module);
+
+ var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(ownerTypeOfFactoryMethod, Module);
+ var implicitOperatorref = typedef.Methods.FirstOrDefault(md =>
+ md.IsPublic &&
+ md.IsStatic &&
+ md.IsSpecialName &&
+ md.Name == "op_Implicit" && md.Parameters[0].ParameterType.FullName == "System.String");
+
+ if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType)
+ {
+ VariableDefinition vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+ Context.Body.Variables.Add(vardef);
+
+ ValueNode vnode = null;
+ if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
+ vardef.VariableType.IsValueType)
+ {
+ //<Color>Purple</Color>
+ Context.IL.Append(vnode.PushConvertedValue(Context, typeref, new ICustomAttributeProvider[] { typedef },
+ node.PushServiceProvider(Context), false, true));
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ }
+ else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
+ implicitOperatorref != null)
+ {
+ //<FileImageSource>path.png</FileImageSource>
+ var implicitOperator = Module.ImportReference(implicitOperatorref);
+ Context.IL.Emit(OpCodes.Ldstr, ((ValueNode)(node.CollectionItems.First())).Value as string);
+ Context.IL.Emit(OpCodes.Call, implicitOperator);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ }
+ else if (factorymethodinforef != null)
+ {
+ Context.IL.Emit(OpCodes.Call, Module.ImportReference(factorymethodinforef));
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ }
+ else if (!typedef.IsValueType)
+ {
+ var ctor = Module.ImportReference(ctorinforef);
+ // IL_0001: newobj instance void class [Tizen.NUI.Xaml.UIComponents]Tizen.NUI.Xaml.UIComponents.Button::'.ctor'()
+ // IL_0006: stloc.0
+ Context.IL.Emit(OpCodes.Newobj, ctor);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ }
+ else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
+ !node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, typeref, Module, Context))
+ {
+ // IL_0008: ldloca.s 1
+ // IL_000a: ldc.i4.1
+ // IL_000b: call instance void valuetype Test/Foo::'.ctor'(bool)
+
+ var ctor = Module.ImportReference(ctorinforef);
+ Context.IL.Emit(OpCodes.Ldloca, vardef);
+ Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
+ Context.IL.Emit(OpCodes.Call, ctor);
+ }
+ else
+ {
+ // IL_0000: ldloca.s 0
+ // IL_0002: initobj Test/Foo
+ Context.IL.Emit(OpCodes.Ldloca, vardef);
+ Context.IL.Emit(OpCodes.Initobj, Module.ImportReference(typedef));
+ }
+
+ if (null != XamlCTask.BaseTypeDefiniation && typedef.InheritsFromOrImplements(XamlCTask.BaseTypeDefiniation))
+ {
+ var field = XamlCTask.BaseTypeDefiniation.Properties.SingleOrDefault(fd => fd.Name == "IsCreateByXaml");
+ if (field == null)
+ return;
+
+ ValueNode value = new ValueNode("true", node.NamespaceResolver);
+ Set(Context.Variables[node], "IsCreateByXaml", value, null);
+ }
+
+ if (typeref.FullName == "Tizen.NUI.Xaml.ArrayExtension")
+ {
+ var visitor = new SetPropertiesVisitor(Context);
+ foreach (var cnode in node.Properties.Values.ToList())
+ cnode.Accept(visitor, node);
+ foreach (var cnode in node.CollectionItems)
+ cnode.Accept(visitor, node);
+
+ markupProvider = new ArrayExtension();
+
+ var il = markupProvider.ProvideValue(node, Module, Context, out typeref);
+
+ vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+ Context.Body.Variables.Add(vardef);
+
+ Context.IL.Append(il);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+
+ //clean the node as it has been fully exhausted
+ foreach (var prop in node.Properties)
+ if (!node.SkipProperties.Contains(prop.Key))
+ node.SkipProperties.Add(prop.Key);
+ node.CollectionItems.Clear();
+
+ return;
+ }
+ }
+ }
+
+ private void Set(VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo)
+ {
+ var module = Context.Body.Method.Module;
+ TypeReference declaringTypeReference;
+ var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ var propertySetter = property.SetMethod;
+
+ module.ImportReference(parent.VariableType.ResolveCached());
+ var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertySetterRef.ImportTypes(module);
+ var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
+ var valueNode = node as ValueNode;
+ var elementNode = node as IElementNode;
+
+ if (parent.VariableType.IsValueType)
+ Context.IL.Emit(OpCodes.Ldloca, parent);
+ else
+ Context.IL.Emit(OpCodes.Ldloc, parent);
+
+ if (valueNode != null)
+ {
+ foreach (var instruction in valueNode.PushConvertedValue(Context, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(Context, propertyRef: property), false, true))
+ {
+ Context.IL.Append(instruction);
+ }
+
+ if (parent.VariableType.IsValueType)
+ Context.IL.Emit(OpCodes.Call, propertySetterRef);
+ else
+ Context.IL.Emit(OpCodes.Callvirt, propertySetterRef);
+ }
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ // IL_0013: ldarg.0
+ // IL_0014: stloc.3
+
+ var ilnode = (ILRootNode)node;
+ var typeref = ilnode.TypeReference;
+ var vardef = new VariableDefinition(typeref);
+ Context.Variables[node] = vardef;
+ Context.Root = vardef;
+ Context.Body.Variables.Add(vardef);
+ Context.IL.Emit(OpCodes.Ldarg_0);
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ XmlName name;
+ if (SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out name))
+ node.XmlName = name;
+ }
+
+ bool ValidateCtorArguments(MethodDefinition ctorinfo, ElementNode enode, out string firstMissingProperty)
+ {
+ firstMissingProperty = null;
+ foreach (var parameter in ctorinfo.Parameters)
+ {
+ var propname =
+ parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
+ .ConstructorArguments.First()
+ .Value as string;
+ if (!enode.Properties.ContainsKey(new XmlName("", propname)))
+ {
+ firstMissingProperty = propname;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ IEnumerable<Instruction> PushCtorArguments(MethodDefinition ctorinfo, ElementNode enode)
+ {
+ foreach (var parameter in ctorinfo.Parameters)
+ {
+ var propname =
+ parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
+ .ConstructorArguments.First()
+ .Value as string;
+ var node = enode.Properties[new XmlName("", propname)];
+ if (!enode.SkipProperties.Contains(new XmlName("", propname)))
+ enode.SkipProperties.Add(new XmlName("", propname));
+ VariableDefinition vardef;
+ ValueNode vnode = null;
+
+ if (node is IElementNode && (vardef = Context.Variables[node as IElementNode]) != null)
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ else if ((vnode = node as ValueNode) != null)
+ {
+ foreach (var instruction in vnode.PushConvertedValue(Context,
+ parameter.ParameterType,
+ new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
+ enode.PushServiceProvider(Context), false, true))
+ yield return instruction;
+ }
+ }
+ }
+
+ IEnumerable<Instruction> PushCtorDefaultArguments(MethodDefinition factoryCtorInfo, ElementNode enode)
+ {
+ var arguments = new List<INode>();
+
+ for (var i = 0; i < factoryCtorInfo.Parameters.Count; i++)
+ {
+ var parameter = factoryCtorInfo.Parameters[i];
+
+ ValueNode arg = new ValueNode(parameter.Constant?.ToString(), enode.NamespaceResolver);
+
+ if (arg != null)
+ {
+ foreach (var instruction in arg.PushConvertedValue(Context,
+ parameter.ParameterType,
+ new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
+ enode.PushServiceProvider(Context), false, true))
+ yield return instruction;
+ }
+ }
+ }
+
+
+ IEnumerable<Instruction> PushCtorXArguments(MethodDefinition factoryCtorInfo, ElementNode enode)
+ {
+ if (!enode.Properties.ContainsKey(XmlName.xArguments))
+ yield break;
+
+ var arguments = new List<INode>();
+ var node = enode.Properties[XmlName.xArguments] as ElementNode;
+ if (node != null)
+ {
+ node.Accept(new SetPropertiesVisitor(Context, true), null);
+ arguments.Add(node);
+ }
+
+ var list = enode.Properties[XmlName.xArguments] as ListNode;
+ if (list != null)
+ {
+ foreach (var n in list.CollectionItems)
+ arguments.Add(n);
+ }
+
+ for (var i = 0; i < arguments.Count; i++)
+ {
+ var parameter = factoryCtorInfo.Parameters[i];
+ var arg = arguments[i];
+ VariableDefinition vardef;
+ ValueNode vnode = null;
+
+ if (arg is IElementNode && (vardef = Context.Variables[arg as IElementNode]) != null)
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ else if ((vnode = arg as ValueNode) != null)
+ {
+ foreach (var instruction in vnode.PushConvertedValue(Context,
+ parameter.ParameterType,
+ new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
+ enode.PushServiceProvider(Context), false, true))
+ yield return instruction;
+ }
+ }
+
+ for (var i = arguments.Count; i < factoryCtorInfo.Parameters.Count; i++)
+ {
+ var parameter = factoryCtorInfo.Parameters[i];
+ var arg = new ValueNode(parameter.Constant.ToString(), node.NamespaceResolver);
+
+ foreach (var instruction in arg.PushConvertedValue(Context,
+ parameter.ParameterType,
+ new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
+ enode.PushServiceProvider(Context), false, true))
+ yield return instruction;
+ }
+ }
+
+ static bool IsXaml2009LanguagePrimitive(IElementNode node)
+ {
+ if (node.NamespaceURI == XamlParser.X2009Uri)
+ {
+ var n = node.XmlType.Name.Split(':')[1];
+ return n != "Array";
+ }
+ if (node.NamespaceURI != "clr-namespace:System;assembly=mscorlib")
+ return false;
+ var name = node.XmlType.Name.Split(':')[1];
+ if (name == "SByte" ||
+ name == "Int16" ||
+ name == "Int32" ||
+ name == "Int64" ||
+ name == "Byte" ||
+ name == "UInt16" ||
+ name == "UInt32" ||
+ name == "UInt64" ||
+ name == "Single" ||
+ name == "Double" ||
+ name == "Boolean" ||
+ name == "String" ||
+ name == "Char" ||
+ name == "Decimal" ||
+ name == "TimeSpan" ||
+ name == "Uri")
+ return true;
+ return false;
+ }
+
+ IEnumerable<Instruction> PushValueFromLanguagePrimitive(TypeReference typeRef, ElementNode node)
+ {
+ var module = Context.Body.Method.Module;
+ var hasValue = node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode &&
+ ((ValueNode)node.CollectionItems[0]).Value is string;
+ var valueString = hasValue ? ((ValueNode)node.CollectionItems[0]).Value as string : string.Empty;
+ switch (typeRef.FullName)
+ {
+ case "System.SByte":
+ if (hasValue && sbyte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out sbyte outsbyte))
+ yield return Create(Ldc_I4, (int)outsbyte);
+ else
+ yield return Create(Ldc_I4, 0x00);
+ break;
+ case "System.Int16":
+ if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outshort))
+ yield return Create(Ldc_I4, outshort);
+ else
+ yield return Create(Ldc_I4, 0x00);
+ break;
+ case "System.Int32":
+ if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out int outint))
+ yield return Create(Ldc_I4, outint);
+ else
+ yield return Create(Ldc_I4, 0x00);
+ break;
+ case "System.Int64":
+ if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outlong))
+ yield return Create(Ldc_I8, outlong);
+ else
+ yield return Create(Ldc_I8, 0L);
+ break;
+ case "System.Byte":
+ if (hasValue && byte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out byte outbyte))
+ yield return Create(Ldc_I4, (int)outbyte);
+ else
+ yield return Create(Ldc_I4, 0x00);
+ break;
+ case "System.UInt16":
+ if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outushort))
+ yield return Create(Ldc_I4, outushort);
+ else
+ yield return Create(Ldc_I4, 0x00);
+ break;
+ case "System.UInt32":
+ if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out int outuint))
+ yield return Create(Ldc_I4, outuint);
+ else
+ yield return Create(Ldc_I4, 0x00);
+ break;
+ case "System.UInt64":
+ if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outulong))
+ yield return Create(Ldc_I8, outulong);
+ else
+ yield return Create(Ldc_I8, 0L);
+ break;
+ case "System.Boolean":
+ if (hasValue && bool.TryParse(valueString, out bool outbool))
+ yield return Create(outbool ? Ldc_I4_1 : Ldc_I4_0);
+ else
+ yield return Create(Ldc_I4_0);
+ break;
+ case "System.String":
+ yield return Create(Ldstr, valueString);
+ break;
+ case "System.Object":
+ var ctorinfo =
+ module.TypeSystem.Object.ResolveCached()
+ .Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
+ var ctor = module.ImportReference(ctorinfo);
+ yield return Create(Newobj, ctor);
+ break;
+ case "System.Char":
+ if (hasValue && char.TryParse(valueString, out char outchar))
+ yield return Create(Ldc_I4, outchar);
+ else
+ yield return Create(Ldc_I4, 0x00);
+ break;
+ case "System.Decimal":
+ decimal outdecimal;
+ if (hasValue && decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
+ {
+ var vardef = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Decimal")));
+ Context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ // IL_0003: ldstr "adecimal"
+ // IL_0008: ldc.i4.s 0x6f
+ // IL_000a: call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
+ // IL_000f: ldloca.s 0
+ // IL_0011: call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
+ // IL_0016: pop
+ yield return Create(Ldstr, valueString);
+ yield return Create(Ldc_I4, 0x6f); //NumberStyles.Number
+ yield return Create(Call, module.ImportPropertyGetterReference(("mscorlib", "System.Globalization", "CultureInfo"),
+ propertyName: "InvariantCulture",
+ isStatic: true));
+ yield return Create(Ldloca, vardef);
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Decimal"),
+ methodName: "TryParse",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System.Globalization", "NumberStyles"),
+ ("mscorlib", "System", "IFormatProvider"),
+ ("mscorlib", "System", "Decimal"),
+ },
+ isStatic: true));
+ yield return Create(Pop);
+ yield return Create(Ldloc, vardef);
+ }
+ else
+ {
+ yield return Create(Ldc_I4_0);
+ yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Decimal"), parameterTypes: new[] { ("mscorlib", "System", "Int32") }));
+ }
+ break;
+ case "System.Single":
+ if (hasValue && float.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out float outfloat))
+ yield return Create(Ldc_R4, outfloat);
+ else
+ yield return Create(Ldc_R4, 0f);
+ break;
+ case "System.Double":
+ if (hasValue && double.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out double outdouble))
+ yield return Create(Ldc_R8, outdouble);
+ else
+ yield return Create(Ldc_R8, 0d);
+ break;
+ case "System.TimeSpan":
+ if (hasValue && TimeSpan.TryParse(valueString, CultureInfo.InvariantCulture, out TimeSpan outspan))
+ {
+ var vardef = new VariableDefinition(module.ImportReference(("mscorlib", "System", "TimeSpan")));
+ Context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ yield return Create(Ldstr, valueString);
+ yield return Create(Call, module.ImportPropertyGetterReference(("mscorlib", "System.Globalization", "CultureInfo"),
+ propertyName: "InvariantCulture", isStatic: true));
+ yield return Create(Ldloca, vardef);
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "TimeSpan"),
+ methodName: "TryParse",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System", "IFormatProvider"),
+ ("mscorlib", "System", "TimeSpan"),
+ },
+ isStatic: true));
+ yield return Create(Pop);
+ yield return Create(Ldloc, vardef);
+ }
+ else
+ {
+ yield return Create(Ldc_I8, 0L);
+ yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "TimeSpan"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
+ }
+ break;
+ case "System.Uri":
+ if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out Uri outuri))
+ {
+ var vardef = new VariableDefinition(module.ImportReference(("System", "System", "Uri")));
+ Context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ yield return Create(Ldstr, valueString);
+ yield return Create(Ldc_I4, (int)UriKind.RelativeOrAbsolute);
+ yield return Create(Ldloca, vardef);
+ yield return Create(Call, module.ImportMethodReference(("System", "System", "Uri"),
+ methodName: "TryCreate",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("System", "System", "UriKind"),
+ ("System", "System", "Uri"),
+ },
+ isStatic: true));
+ yield return Create(Pop);
+ yield return Create(Ldloc, vardef);
+ }
+ else
+ yield return Create(Ldnull);
+ break;
+ default:
+ var defaultCtor = module.ImportCtorReference(typeRef, parameterTypes: null);
+ if (defaultCtor != null)
+ yield return Create(Newobj, defaultCtor);
+ else
+ {
+ //should never happen. but if it does, this prevents corrupting the IL stack
+ yield return Create(Ldnull);
+ }
+ break;
+ }
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Xml;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class CssGTask : Task
+ {
+ [Required]
+ public ITaskItem[] CSSFiles { get; set; }
+
+ [Required]
+ public ITaskItem[] OutputFiles { get; set; }
+
+ public string Language { get; set; }
+ public string AssemblyName { get; set; }
+
+ public override bool Execute()
+ {
+ bool success = true;
+ Log.LogMessage(MessageImportance.Normal, "Generating assembly attributes for CSS files");
+ if (CSSFiles == null || OutputFiles == null) {
+ Log.LogMessage(MessageImportance.Low, "Skipping CssG");
+ return true;
+ }
+
+ if (CSSFiles.Length != OutputFiles.Length) {
+ Log.LogError("\"{2}\" refers to {0} item(s), and \"{3}\" refers to {1} item(s). They must have the same number of items.", CSSFiles.Length, OutputFiles.Length, "CSSFiles", "OutputFiles");
+ return false;
+ }
+
+ for (var i = 0; i < CSSFiles.Length;i++) {
+ var cssFile = CSSFiles[i];
+ var outputFile = OutputFiles[i].ItemSpec;
+
+ var generator = new CssGenerator(cssFile, Language, AssemblyName, outputFile, Log);
+ try {
+ if (!generator.Execute()) {
+ //If Execute() fails, the file still needs to exist because it is added to the <Compile/> ItemGroup
+ File.WriteAllText(outputFile, string.Empty);
+ }
+ }
+ catch (XmlException xe) {
+ Log.LogError(null, null, null, cssFile.ItemSpec, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
+
+ success = false;
+ }
+ catch (Exception e) {
+ Log.LogError(null, null, null, cssFile.ItemSpec, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
+ success = false;
+ }
+ }
+
+ return success;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.CodeDom;
+using System.CodeDom.Compiler;
+using System.IO;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.CSharp;
+
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.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(MessageImportance.Low, "Source: {0}", CssFile);
+ Logger?.LogMessage(MessageImportance.Low, " Language: {0}", Language);
+ Logger?.LogMessage(MessageImportance.Low, " ResourceID: {0}", ResourceId);
+ Logger?.LogMessage(MessageImportance.Low, " TargetPath: {0}", TargetPath);
+ Logger?.LogMessage(MessageImportance.Low, " AssemblyName: {0}", AssemblyName);
+ Logger?.LogMessage(MessageImportance.Low, " OutputFile {0}", OutputFile);
+
+ GenerateCode();
+
+ return true;
+ }
+
+ void GenerateCode()
+ {
+ //Create the target directory if required
+ Directory.CreateDirectory(System.IO.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());
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+
+using static Microsoft.Build.Framework.MessageImportance;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class DebugXamlCTask : XamlTask
+ {
+ public override bool Execute(out IList<Exception> thrownExceptions)
+ {
+ thrownExceptions = null;
+ LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Preparing debug code for xamlc, assembly: {Assembly}");
+
+ var resolver = new DefaultAssemblyResolver();
+ if (!string.IsNullOrEmpty(DependencyPaths)) {
+ foreach (var dep in DependencyPaths.Split(';')) {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {dep}");
+ resolver.AddSearchDirectory(dep);
+ }
+ }
+ if (!string.IsNullOrEmpty(ReferencePath)) {
+ var paths = ReferencePath.Replace("//", "/").Split(';');
+ foreach (var p in paths) {
+ var searchpath = System.IO.Path.GetDirectoryName(p);
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {searchpath}");
+ resolver.AddSearchDirectory(searchpath);
+ }
+ }
+
+ var debug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none");
+
+ using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(Assembly, new ReaderParameters {
+ ReadWrite = true,
+ ReadSymbols = debug,
+ AssemblyResolver = resolver
+ })) {
+ foreach (var module in assemblyDefinition.Modules) {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Module: {module.Name}");
+ foreach (var resource in module.Resources.OfType<EmbeddedResource>()) {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Resource: {resource.Name}");
+ if (!resource.IsXaml(module, out var classname)) {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}skipped.");
+ continue;
+ }
+ TypeDefinition typeDef = module.GetType(classname);
+ if (typeDef == null) {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no type found... skipped.");
+ continue;
+ }
+
+ var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
+ if (initComp == null) {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no InitializeComponent found... skipped.");
+ continue;
+ }
+ var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
+ if (initCompRuntime == null) {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
+ initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
+ initCompRuntime.Body.InitLocals = true;
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
+ initCompRuntime.Body = new MethodBody(initCompRuntime);
+ var iCRIl = initCompRuntime.Body.GetILProcessor();
+ foreach (var instr in initComp.Body.Instructions)
+ iCRIl.Append(instr);
+ initComp.Body.Instructions.Clear();
+ initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
+ typeDef.Methods.Add(initCompRuntime);
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+ }
+
+// IL_0000: ldarg.0
+// IL_0001: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.ContentPage::'.ctor'()
+//
+// IL_0006: nop
+// IL_0007: ldarg.1
+// IL_0008: brfalse IL_0018
+//
+// IL_000d: ldarg.0
+// IL_000e: callvirt instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::InitializeComponent()
+// IL_0013: br IL_001e
+//
+// IL_0018: ldarg.0
+// IL_0019: callvirt instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::__InitComponentRuntime()
+// IL_001e: ret
+
+ var altCtor = typeDef.Methods.FirstOrDefault(md => md.IsConstructor
+ && md.Parameters.Count == 1
+ && md.Parameters[0].ParameterType == module.TypeSystem.Boolean);
+ if (altCtor != null)
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing body of {typeDef.Name}.{typeDef.Name} (bool {altCtor.Parameters[0].Name})");
+ else {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Adding {typeDef.Name}.{typeDef.Name} (bool useCompiledXaml)");
+ altCtor = new MethodDefinition(".ctor",
+ MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
+ MethodAttributes.RTSpecialName, module.TypeSystem.Void);
+ altCtor.Parameters.Add(new ParameterDefinition("useCompiledXaml", ParameterAttributes.None,
+ module.TypeSystem.Boolean));
+ }
+
+ var body = new MethodBody(altCtor) {
+ InitLocals = true
+ };
+ var il = body.GetILProcessor();
+ var br2 = Instruction.Create(OpCodes.Ldarg_0);
+ var ret = Instruction.Create(OpCodes.Ret);
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Callvirt,
+ module.ImportReference(typeDef.BaseType.Resolve().GetConstructors().First(c => c.HasParameters == false)));
+
+ il.Emit(OpCodes.Nop);
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Brfalse, br2);
+
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Callvirt, initComp);
+ il.Emit(OpCodes.Br, ret);
+
+ il.Append(br2);
+ il.Emit(OpCodes.Callvirt, initCompRuntime);
+ il.Append(ret);
+
+ altCtor.Body = body;
+ if (!typeDef.Methods.Contains(altCtor))
+ typeDef.Methods.Add(altCtor);
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+ }
+
+ }
+ LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Writing the assembly.");
+ assemblyDefinition.Write(new WriterParameters {
+ WriteSymbols = debug
+ });
+ }
+ LoggingHelper.LogMessage(Normal, $"{new string(' ', 2)}done.");
+
+ return true;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Xml;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class ExpandMarkupsVisitor : IXamlNodeVisitor
+ {
+ readonly IList<XmlName> skips = new List<XmlName>
+ {
+ XmlName.xKey,
+ XmlName.xTypeArguments,
+ XmlName.xFactoryMethod,
+ XmlName.xName,
+ XmlName.xDataType
+ };
+
+ public ExpandMarkupsVisitor(ILContext context)
+ {
+ Context = context;
+ }
+
+ ILContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => false;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(MarkupNode markupnode, INode parentNode)
+ {
+ XmlName propertyName;
+ if (!TryGetProperyName(markupnode, parentNode, out propertyName))
+ return;
+ if (skips.Contains(propertyName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+ var markupString = markupnode.MarkupString;
+ var node = ParseExpression(ref markupString, Context, markupnode.NamespaceResolver, markupnode) as IElementNode;
+ if (node != null)
+ {
+ ((IElementNode)parentNode).Properties[propertyName] = node;
+ node.Accept(new XamlNodeVisitor((n, parent) => n.Parent = parent), parentNode);
+ }
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ public static bool TryGetProperyName(INode node, INode parentNode, out XmlName name)
+ {
+ name = default(XmlName);
+ var parentElement = parentNode as IElementNode;
+ if (parentElement == null)
+ return false;
+ foreach (var kvp in parentElement.Properties)
+ {
+ if (kvp.Value != node)
+ continue;
+ name = kvp.Key;
+ return true;
+ }
+ return false;
+ }
+
+ static INode ParseExpression(ref string expression, ILContext context, IXmlNamespaceResolver nsResolver,
+ IXmlLineInfo xmlLineInfo)
+ {
+ if (expression.StartsWith("{}", StringComparison.Ordinal))
+ return new ValueNode(expression.Substring(2), null);
+
+ if (expression[expression.Length - 1] != '}')
+ throw new XamlParseException("Markup expression missing its closing tag", xmlLineInfo);
+
+ int len;
+ string match;
+ if (!MarkupExpressionParser.MatchMarkup(out match, expression, out len))
+ throw new XamlParseException("Error while parsing markup expression", xmlLineInfo);
+ expression = expression.Substring(len).TrimStart();
+ if (expression.Length == 0)
+ throw new XamlParseException("Markup expression not closed", xmlLineInfo);
+
+ var provider = new XamlServiceProvider(null, null);
+ provider.Add(typeof (ILContextProvider), new ILContextProvider(context));
+ provider.Add(typeof (IXmlNamespaceResolver), nsResolver);
+ provider.Add(typeof (IXmlLineInfoProvider), new XmlLineInfoProvider(xmlLineInfo));
+
+ return new MarkupExpansionParser().Parse(match, ref expression, provider);
+ }
+
+ class ILContextProvider
+ {
+ public ILContextProvider(ILContext context)
+ {
+ Context = context;
+ }
+
+ public ILContext Context { get; }
+ }
+
+ class MarkupExpansionParser : MarkupExpressionParser, IExpressionParser<INode>
+ {
+ IElementNode node;
+
+ object IExpressionParser.Parse(string match, ref string remaining, IServiceProvider serviceProvider)
+ {
+ return Parse(match, ref remaining, serviceProvider);
+ }
+
+ public INode Parse(string match, ref string remaining, IServiceProvider serviceProvider)
+ {
+ var nsResolver = serviceProvider.GetService(typeof (IXmlNamespaceResolver)) as IXmlNamespaceResolver;
+ if (nsResolver == null)
+ throw new ArgumentException();
+ IXmlLineInfo xmlLineInfo = null;
+ var xmlLineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
+ if (xmlLineInfoProvider != null)
+ xmlLineInfo = xmlLineInfoProvider.XmlLineInfo;
+ var contextProvider = serviceProvider.GetService(typeof (ILContextProvider)) as ILContextProvider;
+
+ var split = match.Split(':');
+ if (split.Length > 2)
+ throw new ArgumentException();
+
+ string prefix, name;
+ if (split.Length == 2)
+ {
+ prefix = split[0];
+ name = split[1];
+ }
+ else
+ {
+ prefix = "";
+ name = split[0];
+ }
+
+ var namespaceuri = nsResolver.LookupNamespace(prefix) ?? "";
+ if (!string.IsNullOrEmpty(prefix) && string.IsNullOrEmpty(namespaceuri))
+ throw new XamlParseException($"Undeclared xmlns prefix '{prefix}'", xmlLineInfo);
+ //The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
+ XmlType type;
+ try
+ {
+ type = new XmlType(namespaceuri, name + "Extension", null);
+ type.GetTypeReference(contextProvider.Context.Module, null);
+ }
+ catch (XamlParseException)
+ {
+ type = new XmlType(namespaceuri, name, null);
+ }
+
+ if (type == null)
+ throw new NotSupportedException();
+
+ node = xmlLineInfo == null
+ ? new ElementNode(type, "", nsResolver)
+ : new ElementNode(type, "", nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
+
+ if (remaining.StartsWith("}", StringComparison.Ordinal))
+ {
+ remaining = remaining.Substring(1);
+ return node;
+ }
+
+ char next;
+ string piece;
+ while ((piece = GetNextPiece(ref remaining, out next)) != null)
+ HandleProperty(piece, serviceProvider, ref remaining, next != '=');
+
+ return node;
+ }
+
+ protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
+ {
+ var nsResolver = serviceProvider.GetService(typeof(IXmlNamespaceResolver)) as IXmlNamespaceResolver;
+ if (prop != null)
+ {
+ var name = new XmlName(node.NamespaceURI, prop);
+ node.Properties[name] = value as INode ?? new ValueNode(strValue, nsResolver);
+ }
+ else //ContentProperty
+ node.CollectionItems.Add(value as INode ?? new ValueNode(strValue, nsResolver));
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Mono.Cecil;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class FieldReferenceExtensions
+ {
+ public static FieldReference ResolveGenericParameters(this FieldReference self, TypeReference declaringTypeRef)
+ {
+ var fieldType = self.FieldType;
+ if (fieldType.IsGenericParameter)
+ {
+ var genericParameter = (GenericParameter)fieldType;
+ fieldType = ((GenericInstanceType)declaringTypeRef).GenericArguments[genericParameter.Position];
+ }
+ var fieldReference = new FieldReference(self.Name, fieldType)
+ {
+ DeclaringType = declaringTypeRef
+ };
+ return fieldReference;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.ComponentModel;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class GetTasksAbi : Task
+ {
+ [Output]
+ public string AbiVersion { get; } = "4";
+
+ public override bool Execute()
+ => true;
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class ILContext
+ {
+ public ILContext(ILProcessor il, MethodBody body, List<Instruction> insOfAddEvent, ModuleDefinition module, FieldDefinition parentContextValues = null)
+ {
+ IL = il;
+ Body = body;
+ InsOfAddEvent = insOfAddEvent;
+ Values = new Dictionary<INode, object>();
+ Variables = new Dictionary<IElementNode, VariableDefinition>();
+ Scopes = new Dictionary<INode, Tuple<VariableDefinition, IList<string>>>();
+ TypeExtensions = new Dictionary<INode, TypeReference>();
+ ParentContextValues = parentContextValues;
+ Module = module;
+ }
+
+ public Dictionary<INode, object> Values { get; private set; }
+
+ public Dictionary<IElementNode, VariableDefinition> Variables { get; private set; }
+
+ public Dictionary<INode, Tuple<VariableDefinition, IList<string>>> Scopes { get; private set; }
+
+ public Dictionary<INode, TypeReference> TypeExtensions { get; }
+
+ public FieldDefinition ParentContextValues { get; private set; }
+
+ public object Root { get; set; } //FieldDefinition or VariableDefinition
+
+ public ILProcessor IL { get; private set; }
+
+ public MethodBody Body { get; private set; }
+
+ public List<Instruction> InsOfAddEvent { get; private set; }
+
+ public ModuleDefinition Module { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Mono.Cecil.Cil;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class ILProcessorExtensions
+ {
+ public static void Append(this ILProcessor processor, IEnumerable<Instruction> instructions)
+ {
+ foreach (var instruction in instructions)
+ processor.Append(instruction);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Xml;
+using Mono.Cecil;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class ILRootNode : RootNode
+ {
+ public ILRootNode(XmlType xmlType, TypeReference typeReference, IXmlNamespaceResolver nsResolver) : base(xmlType, nsResolver)
+ {
+ TypeReference = typeReference;
+ }
+
+ public TypeReference TypeReference { get; private set; }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Xml;
+using System.ComponentModel;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class Logger {
+ public TaskLoggingHelper Helper { get; }
+
+ public Logger(TaskLoggingHelper helper)
+ {
+ Helper = helper;
+ }
+
+
+ public void LogException(string subcategory, string errorCode, string helpKeyword, string file, Exception e)
+ {
+ var xpe = e as XamlParseException;
+ var xe = e as XmlException;
+ if (xpe != null)
+ LogError(subcategory, errorCode, helpKeyword, file, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
+ else if (xe != null)
+ LogError(subcategory, errorCode, helpKeyword, file, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
+ else
+ LogError(subcategory, errorCode, helpKeyword, file, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
+ }
+
+ public void LogError(string subcategory, string errorCode, string helpKeyword, string file, int lineNumber,
+ int columnNumber, int endLineNumber, int endColumnNumber, string message, params object [] messageArgs)
+ {
+ FlushBuffer();
+
+ if (Helper != null) {
+ Helper.LogError(subcategory, errorCode, helpKeyword, file, lineNumber, columnNumber, endLineNumber,
+ endColumnNumber, message, messageArgs);
+ } else
+ Console.Error.WriteLine($"{file} ({lineNumber}:{columnNumber}) : {message}");
+ }
+
+ public void LogLine(MessageImportance messageImportance, string format, params object [] arg)
+ {
+ if (!string.IsNullOrEmpty(buffer)) {
+ format = buffer + format;
+ buffer = "";
+ bufferImportance = MessageImportance.Low;
+ }
+
+ if (Helper != null)
+ Helper.LogMessage(messageImportance, format, arg);
+ else
+ Console.WriteLine(format, arg);
+ }
+
+ public void LogString(MessageImportance messageImportance, string format, params object [] arg)
+ {
+ if (Helper != null) {
+ buffer += String.Format(format, arg);
+ bufferImportance = messageImportance;
+ } else
+ Console.Write(format, arg);
+ }
+
+ string buffer = "";
+ MessageImportance bufferImportance = MessageImportance.Low;
+ void FlushBuffer()
+ {
+ if (!string.IsNullOrEmpty(buffer)) {
+ if (Helper != null)
+ Helper.LogMessage(bufferImportance, buffer);
+ else
+ Console.WriteLine(buffer);
+ }
+ buffer = "";
+ bufferImportance = MessageImportance.Low;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class MethodBodyExtensions
+ {
+ public static void Optimize(this MethodBody self)
+ {
+ if (self == null)
+ throw new ArgumentNullException(nameof(self));
+
+ self.OptimizeLongs();
+ self.OptimizeStLdLoc();
+ self.RemoveUnusedLocals();
+ self.OptimizeMacros();
+ }
+
+ static void ExpandMacro(Instruction instruction, OpCode opcode, object operand)
+ {
+ instruction.OpCode = opcode;
+ instruction.Operand = operand;
+ }
+
+ //this can be removed if/when https://github.com/jbevain/cecil/pull/307 is released in a nuget we consume
+ static void OptimizeLongs(this MethodBody self)
+ {
+ for (var i = 0; i < self.Instructions.Count; i++) {
+ var instruction = self.Instructions[i];
+ if (instruction.OpCode.Code != Code.Ldc_I8)
+ continue;
+ var l = (long)instruction.Operand;
+ if (l < int.MinValue || l > int.MaxValue)
+ continue;
+ ExpandMacro(instruction, OpCodes.Ldc_I4, unchecked((int)l));
+ self.Instructions.Insert(++i, Instruction.Create(OpCodes.Conv_I8));
+ }
+ }
+
+ static void OptimizeStLdLoc(this MethodBody self)
+ {
+ var method = self.Method;
+ for (var i = 0; i < self.Instructions.Count; i++) {
+ var instruction = self.Instructions[i];
+ if (instruction.OpCode.Code != Code.Stloc)
+ continue;
+ if (i + 1 >= self.Instructions.Count)
+ continue;
+ var next = self.Instructions[i + 1];
+ int num = ((VariableDefinition)instruction.Operand).Index;
+ var vardef = instruction.Operand;
+ if (next.OpCode.Code != Code.Ldloc || num != ((VariableDefinition)next.Operand).Index)
+ continue;
+ ExpandMacro(instruction, OpCodes.Dup, null);
+ ExpandMacro(next, OpCodes.Stloc, vardef);
+ }
+ }
+
+ static void RemoveUnusedLocals(this MethodBody self)
+ {
+ //Count ldloc for each variable
+ var ldlocUsed = new List<VariableDefinition>();
+ foreach (var instruction in self.Instructions) {
+ if (instruction.OpCode.Code != Code.Ldloc)
+ continue;
+ var varDef = (VariableDefinition)instruction.Operand;
+ if (!ldlocUsed.Contains(varDef))
+ ldlocUsed.Add(varDef);
+ }
+
+ foreach (var varDef in self.Variables.ToArray()) {
+ if (ldlocUsed.Contains(varDef))
+ continue;
+
+ //find the Stloc instruction
+ var instruction = (from instr in self.Instructions where instr.OpCode.Code == Code.Stloc && instr.Operand == varDef select instr).First();
+
+ //remove dup/stloc
+ if (instruction.Previous.OpCode.Code != Code.Dup)
+ break;
+
+ self.Instructions.Remove(instruction.Previous);
+ self.Instructions.Remove(instruction);
+
+ //and remove the variable
+ self.Variables.Remove(varDef);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using Mono.Cecil;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class MethodDefinitionExtensions
+ {
+ public static bool MatchXArguments(this MethodDefinition methodDef, ElementNode enode, TypeReference declaringTypeRef, ModuleDefinition module, ILContext context)
+ {
+ if (!enode.Properties.ContainsKey(XmlName.xArguments))
+ return !methodDef.HasParameters;
+
+ var arguments = new List<INode>();
+ var node = enode.Properties[XmlName.xArguments] as ElementNode;
+ if (node != null)
+ arguments.Add(node);
+ else
+ {
+ if (enode.Properties[XmlName.xArguments] is ValueNode valueNode)
+ {
+ var value = valueNode.Value as string;
+ if (value != null && value.Substring(0, "{x:Reference ".Length) == "{x:Reference ")
+ {
+ var elementName = value.Substring("{x:Reference ".Length);
+ elementName = elementName.Substring(0, elementName.Length - 1);
+ }
+ }
+ }
+
+ var list = enode.Properties[XmlName.xArguments] as ListNode;
+ if (list != null)
+ foreach (var n in list.CollectionItems)
+ arguments.Add(n);
+
+ if (methodDef.Parameters.Count < arguments.Count)
+ return false;
+
+ for (int i = arguments.Count; i < methodDef.Parameters.Count; i++)
+ {
+ if (false == methodDef.Parameters[i].HasDefault)
+ {
+ return false;
+ }
+ }
+
+ for (var i = 0; i < arguments.Count; i++)
+ {
+ var paramType = methodDef.Parameters[i].ParameterType;
+ var genParam = paramType as GenericParameter;
+ if (genParam != null) {
+ var index = genParam.DeclaringType.GenericParameters.IndexOf(genParam);
+ paramType = (declaringTypeRef as GenericInstanceType).GenericArguments[index];
+ }
+
+ var argType = context.Variables[arguments[i] as IElementNode].VariableType;
+ if (!argType.InheritsFromOrImplements(paramType))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static TypeReference ResolveGenericReturnType(this MethodDefinition self, TypeReference declaringTypeRef, ModuleDefinition module)
+ {
+ if (self == null)
+ throw new System.ArgumentNullException(nameof(self));
+ if (declaringTypeRef == null)
+ throw new System.ArgumentNullException(nameof(declaringTypeRef));
+ if (!self.ReturnType.IsGenericParameter)
+ return self.ReturnType;
+
+ var t = ((GenericInstanceType)declaringTypeRef).GenericArguments[((GenericParameter)self.ReturnType).Position];
+ return t;
+ }
+ }
+}
--- /dev/null
+using System;
+using Mono.Cecil;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class MethodReferenceExtensions
+ {
+ public static MethodReference ResolveGenericParameters(this MethodReference self, TypeReference declaringTypeRef,
+ ModuleDefinition module)
+ {
+ if (self == null)
+ throw new ArgumentNullException(nameof(self));
+ if (declaringTypeRef == null)
+ throw new ArgumentNullException(nameof(declaringTypeRef));
+
+ var reference = new MethodReference(self.Name, module.ImportReference(self.ReturnType))
+ {
+ DeclaringType = module.ImportReference(declaringTypeRef),
+ HasThis = self.HasThis,
+ ExplicitThis = self.ExplicitThis,
+ CallingConvention = self.CallingConvention
+ };
+
+ foreach (var parameter in self.Parameters) {
+ var p = parameter.ParameterType.IsGenericParameter ? parameter.ParameterType : module.ImportReference(parameter.ParameterType);
+ reference.Parameters.Add(new ParameterDefinition(p));
+ }
+
+ foreach (var generic_parameter in self.GenericParameters)
+ reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));
+
+ return reference;
+ }
+
+ public static void ImportTypes(this MethodReference self, ModuleDefinition module)
+ {
+ if (!self.HasParameters)
+ return;
+
+ for (var i = 0; i < self.Parameters.Count; i++)
+ self.Parameters[i].ParameterType = module.ImportReference(self.Parameters[i].ParameterType);
+ }
+
+ public static MethodReference MakeGeneric(this MethodReference self, TypeReference declaringType, params TypeReference [] arguments)
+ {
+ var reference = new MethodReference(self.Name, self.ReturnType) {
+ DeclaringType = declaringType,
+ HasThis = self.HasThis,
+ ExplicitThis = self.ExplicitThis,
+ CallingConvention = self.CallingConvention,
+ };
+
+ foreach (var parameter in self.Parameters)
+ reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
+
+ foreach (var generic_parameter in self.GenericParameters)
+ reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));
+
+ return reference;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Rocks;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class ModuleDefinitionExtensions
+ {
+ static Dictionary<(ModuleDefinition module, string typeKey), TypeReference> TypeRefCache = new Dictionary<(ModuleDefinition module, string typeKey), TypeReference>();
+ public static TypeReference ImportReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type)
+ {
+ var typeKey = type.ToString();
+ if (!TypeRefCache.TryGetValue((module, typeKey), out var typeRef))
+ TypeRefCache.Add((module, typeKey), typeRef = module.ImportReference(module.GetTypeDefinition(type)));
+ return typeRef;
+ }
+
+ public static TypeReference ImportReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, (string assemblyName, string clrNamespace, string typeName)[] classArguments)
+ {
+ var typeKey = $"{type}<{string.Join(",",classArguments)}>";
+ if (!TypeRefCache.TryGetValue((module, typeKey), out var typeRef))
+ TypeRefCache.Add((module, typeKey), typeRef = module.ImportReference(module.ImportReference(type).MakeGenericInstanceType(classArguments.Select(gp => module.GetTypeDefinition((gp.assemblyName, gp.clrNamespace, gp.typeName))).ToArray())));
+ return typeRef;
+ }
+
+ public static TypeReference ImportArrayReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type)
+ {
+ var typeKey = "${type}[]";
+ if (!TypeRefCache.TryGetValue((module, typeKey), out var typeRef))
+ TypeRefCache.Add((module, typeKey), typeRef = module.ImportReference(module.ImportReference(type).MakeArrayType()));
+ return typeRef;
+ }
+
+ static Dictionary<(ModuleDefinition module, string methodRefKey), MethodReference> MethodRefCache = new Dictionary<(ModuleDefinition module, string methodRefKey), MethodReference>();
+ static MethodReference ImportCtorReference(this ModuleDefinition module, TypeReference type, TypeReference[] classArguments, Func<MethodDefinition, bool> predicate)
+ {
+ var ctor = module.ImportReference(type).ResolveCached().Methods.FirstOrDefault(md => !md.IsPrivate && !md.IsStatic && md.IsConstructor && (predicate?.Invoke(md) ?? true));
+ if (ctor is null)
+ return null;
+ var ctorRef = module.ImportReference(ctor);
+ if (type.IsGenericInstance && type.Name == "List`1")
+ {
+ ctorRef = module.ImportReference(ctorRef.ResolveGenericParameters(type, module));
+ }
+
+ if (classArguments == null)
+ return ctorRef;
+
+ return module.ImportReference(ctorRef.ResolveGenericParameters(type.MakeGenericInstanceType(classArguments), module));
+ }
+
+ public static MethodReference ImportCtorReference(this ModuleDefinition module, TypeReference type, TypeReference[] parameterTypes)
+ {
+ var ctorKey = $"{type}.ctor({(parameterTypes == null ? "" : string.Join(",", parameterTypes.Select(tr => (tr.Scope.Name, tr.Namespace, tr.Name))))})";
+ if (MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef))
+ return ctorRef;
+ ctorRef = module.ImportCtorReference(type, classArguments: null, predicate: md => {
+ if (md.Parameters.Count != (parameterTypes?.Length ?? 0))
+ return false;
+ for (var i = 0; i < md.Parameters.Count; i++)
+ if (!TypeRefComparer.Default.Equals(md.Parameters[i].ParameterType, module.ImportReference(parameterTypes[i])))
+ return false;
+ return true;
+ });
+ MethodRefCache.Add((module, ctorKey), ctorRef);
+ return ctorRef;
+ }
+
+ public static MethodReference ImportCtorReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, int paramCount)
+ {
+ var ctorKey = $"{type}.ctor({(string.Join(",", Enumerable.Repeat("_", paramCount)))})";
+ if (!MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef))
+ MethodRefCache.Add((module, ctorKey), ctorRef = module.ImportCtorReference(module.GetTypeDefinition(type), null, md => md.Parameters.Count == paramCount));
+ return ctorRef;
+ }
+
+ public static MethodReference ImportCtorReference(this ModuleDefinition module, TypeReference type, int paramCount)
+ {
+ var ctorKey = $"{type}.ctor({(string.Join(",", Enumerable.Repeat("_", paramCount)))})";
+ if (!MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef))
+ MethodRefCache.Add((module, ctorKey), ctorRef = module.ImportCtorReference(type, null, md => md.Parameters.Count == paramCount));
+ return ctorRef;
+ }
+
+ public static MethodReference ImportCtorReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, int paramCount, (string assemblyName, string clrNamespace, string typeName)[] classArguments)
+ {
+ var ctorKey = $"{type}<{(string.Join(",", classArguments))}>.ctor({(string.Join(",", Enumerable.Repeat("_", paramCount)))})";
+ if (!MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef))
+ MethodRefCache.Add((module, ctorKey), ctorRef = module.ImportCtorReference(module.GetTypeDefinition(type), classArguments.Select(module.GetTypeDefinition).ToArray(), md=>md.Parameters.Count==paramCount));
+ return ctorRef;
+ }
+
+ public static MethodReference ImportCtorReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, int paramCount, TypeReference[] classArguments)
+ {
+ var ctorKey = $"{type}<{(string.Join(",", classArguments.Select(tr => (tr.Scope.Name, tr.Namespace, tr.Name))))}>.ctor({(string.Join(",", Enumerable.Repeat("_", paramCount)))})";
+ if (!MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef))
+ MethodRefCache.Add((module, ctorKey), ctorRef = module.ImportCtorReference(module.GetTypeDefinition(type), classArguments, predicate: md => md.Parameters.Count == paramCount));
+ return ctorRef;
+ }
+
+ public static MethodReference ImportCtorReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, (string assemblyName, string clrNamespace, string typeName)[] parameterTypes, (string assemblyName, string clrNamespace, string typeName)[] classArguments)
+ {
+ var ctorKey = $"{type}<{(string.Join(",", classArguments))}>.ctor({(parameterTypes == null ? "" : string.Join(",", parameterTypes))})";
+ if (MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef))
+ return ctorRef;
+ ctorRef = module.ImportCtorReference(module.GetTypeDefinition(type), classArguments.Select(module.GetTypeDefinition).ToArray(), md => {
+ if (md.Parameters.Count != (parameterTypes?.Length ?? 0))
+ return false;
+ for (var i = 0; i < md.Parameters.Count; i++)
+ if (!TypeRefComparer.Default.Equals(md.Parameters[i].ParameterType, module.ImportReference(parameterTypes[i])))
+ return false;
+ return true;
+ });
+ MethodRefCache.Add((module, ctorKey), ctorRef);
+ return ctorRef;
+ }
+
+ public static MethodReference ImportCtorReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, (string assemblyName, string clrNamespace, string typeName)[] parameterTypes)
+ {
+ var ctorKey = $"{type}.ctor({(parameterTypes == null ? "" : string.Join(",", parameterTypes))})";
+ if (MethodRefCache.TryGetValue((module, ctorKey), out var ctorRef))
+ return ctorRef;
+ ctorRef = module.ImportCtorReference(module.GetTypeDefinition(type), classArguments: null, predicate: md => {
+ if (md.Parameters.Count != (parameterTypes?.Length ?? 0))
+ return false;
+ for (var i = 0; i < md.Parameters.Count; i++)
+ if (!TypeRefComparer.Default.Equals(md.Parameters[i].ParameterType, module.ImportReference(parameterTypes[i])))
+ return false;
+ return true;
+ });
+ MethodRefCache.Add((module, ctorKey), ctorRef);
+ return ctorRef;
+ }
+
+ static MethodReference ImportPropertyGetterReference(this ModuleDefinition module, TypeReference type, string propertyName, Func<PropertyDefinition, bool> predicate = null, bool flatten = false, bool caseSensitive = true)
+ {
+ var properties = module.ImportReference(type).Resolve().Properties;
+ var getter = module
+ .ImportReference(type)
+ .ResolveCached()
+ .Properties(flatten)
+ .FirstOrDefault(pd =>
+ string.Equals(pd.Name, propertyName, caseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase)
+ && !pd.GetMethod.IsPrivate
+ && (predicate?.Invoke(pd) ?? true))
+ ?.GetMethod;
+ return getter == null ? null : module.ImportReference(getter);
+ }
+
+ public static MethodReference ImportPropertyGetterReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, string propertyName, bool isStatic = false, bool flatten = false, bool caseSensitive = true)
+ {
+ var getterKey = $"{(isStatic ? "static " : "")}{type}.get_{propertyName}{(flatten ? "*" : "")}";
+ if (!MethodRefCache.TryGetValue((module, getterKey), out var methodReference))
+ MethodRefCache.Add((module, getterKey), methodReference = module.ImportPropertyGetterReference(module.GetTypeDefinition(type), propertyName, pd => pd.GetMethod.IsStatic == isStatic, flatten, caseSensitive: caseSensitive));
+ return methodReference;
+ }
+
+ static MethodReference ImportPropertySetterReference(this ModuleDefinition module, TypeReference type, string propertyName, Func<PropertyDefinition, bool> predicate = null)
+ {
+ var setter = module
+ .ImportReference(type)
+ .ResolveCached()
+ .Properties
+ .FirstOrDefault(pd =>
+ pd.Name == propertyName
+ && !pd.SetMethod.IsPrivate
+ && (predicate?.Invoke(pd) ?? true))
+ ?.SetMethod;
+ return setter == null ? null : module.ImportReference(setter);
+ }
+
+ public static MethodReference ImportPropertySetterReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, string propertyName, bool isStatic = false)
+ {
+ var setterKey = $"{(isStatic ? "static " : "")}{type}.set{propertyName}";
+ if (!MethodRefCache.TryGetValue((module, setterKey), out var methodReference))
+ MethodRefCache.Add((module,setterKey), methodReference = module.ImportPropertySetterReference(module.GetTypeDefinition(type), propertyName, pd => pd.SetMethod.IsStatic == isStatic));
+ return methodReference;
+ }
+
+ static MethodReference ImportMethodReference(this ModuleDefinition module, TypeReference type, string methodName, Func<MethodDefinition, bool> predicate = null, TypeReference[] classArguments = null)
+ {
+ var method = module
+ .ImportReference(type)
+ .ResolveCached()
+ .Methods
+ .FirstOrDefault(md =>
+ !md.IsConstructor
+ && !md.IsPrivate
+ && md.Name == methodName
+ && (predicate?.Invoke(md) ?? true));
+ if (method is null)
+ return null;
+ var methodRef = module.ImportReference(method);
+ if (classArguments == null)
+ return methodRef;
+ return module.ImportReference(methodRef.ResolveGenericParameters(type.MakeGenericInstanceType(classArguments), module));
+ }
+
+ public static MethodReference ImportMethodReference(this ModuleDefinition module,
+ (string assemblyName, string clrNamespace, string typeName) type,
+ string methodName,
+ (string assemblyName, string clrNamespace, string typeName)[] parameterTypes,
+ (string assemblyName, string clrNamespace, string typeName)[] classArguments = null,
+ bool isStatic = false)
+ {
+ var methodKey = $"{(isStatic ? "static " : "")}{type}<{(classArguments == null ? "" : string.Join(",", classArguments))}>.({(parameterTypes == null ? "" : string.Join(",", parameterTypes))})";
+ if (MethodRefCache.TryGetValue((module, methodKey), out var methodReference))
+ return methodReference;
+ methodReference = module.ImportMethodReference(module.GetTypeDefinition(type),
+ methodName: methodName,
+ predicate: md => {
+ if (md.IsStatic != isStatic)
+ return false;
+ if (md.Parameters.Count != (parameterTypes?.Length ?? 0))
+ return false;
+ for (var i = 0; i < md.Parameters.Count; i++)
+ if (!TypeRefComparer.Default.Equals(md.Parameters[i].ParameterType, module.ImportReference(parameterTypes[i])))
+ return false;
+ return true;
+ },
+ classArguments: classArguments?.Select(gp => module.GetTypeDefinition((gp.assemblyName, gp.clrNamespace, gp.typeName))).ToArray());
+ MethodRefCache.Add((module, methodKey), methodReference);
+ return methodReference;
+ }
+
+ public static MethodReference ImportMethodReference(this ModuleDefinition module,
+ (string assemblyName, string clrNamespace, string typeName) type,
+ string methodName,
+ int paramCount,
+ (string assemblyName, string clrNamespace, string typeName)[] classArguments = null,
+ bool isStatic = false)
+ {
+ var methodKey = $"{(isStatic ? "static " : "")}{type}<{(classArguments == null ? "" : string.Join(",", classArguments))}>.({(string.Join(",", Enumerable.Repeat("_", paramCount)))})";
+ if (MethodRefCache.TryGetValue((module, methodKey), out var methodReference))
+ return methodReference;
+ methodReference = module.ImportMethodReference(module.GetTypeDefinition(type),
+ methodName: methodName,
+ predicate: md => {
+ if (md.IsStatic != isStatic)
+ return false;
+ if (md.Parameters.Count != paramCount)
+ return false;
+ return true;
+ },
+ classArguments: classArguments?.Select(gp => module.GetTypeDefinition((gp.assemblyName, gp.clrNamespace, gp.typeName))).ToArray());
+ MethodRefCache.Add((module, methodKey), methodReference);
+ return methodReference;
+ }
+
+ static Dictionary<(ModuleDefinition module, string fieldRefKey), FieldReference> FieldRefCache = new Dictionary<(ModuleDefinition module, string fieldRefKey), FieldReference>();
+ static FieldReference ImportFieldReference(this ModuleDefinition module, TypeReference type, string fieldName, Func<FieldDefinition, bool> predicate = null, bool caseSensitive = true)
+ {
+ var field = module
+ .ImportReference(type)
+ .ResolveCached()
+ .Fields
+ .FirstOrDefault(fd =>
+ string.Equals(fd.Name, fieldName, caseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase)
+ && (predicate?.Invoke(fd) ?? true));
+ return field == null ? null : module.ImportReference(field);
+ }
+
+ public static FieldReference ImportFieldReference(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type, string fieldName, bool isStatic = false, bool caseSensitive = true)
+ {
+ var fieldKey = $"{(isStatic ? "static " : "")}{type}.{(caseSensitive ? fieldName : fieldName.ToLowerInvariant())}";
+ if (!FieldRefCache.TryGetValue((module, fieldKey), out var fieldReference))
+ FieldRefCache.Add((module, fieldKey), fieldReference = module.ImportFieldReference(module.GetTypeDefinition(type), fieldName: fieldName, predicate: fd => fd.IsStatic == isStatic, caseSensitive: caseSensitive));
+ return fieldReference;
+ }
+
+ static Dictionary<(ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName)), TypeDefinition> typeDefCache
+ = new Dictionary<(ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName)), TypeDefinition>();
+
+ public static TypeDefinition GetTypeDefinition(this ModuleDefinition module, string typeName)
+ {
+ int index = typeName.LastIndexOf('.');
+
+ var ret = module.GetType(typeName);
+
+ if (null == ret)
+ {
+ foreach (var ass in module.AssemblyReferences)
+ {
+ var refAss = module.AssemblyResolver.Resolve(ass);
+ ret = refAss?.MainModule.GetType(typeName);
+ if (null != ret)
+ {
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public static TypeDefinition GetTypeDefinition(this ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type)
+ {
+ if (typeDefCache.TryGetValue((module, type), out TypeDefinition cachedTypeDefinition))
+ return cachedTypeDefinition;
+
+ var asm = module.Assembly.Name.Name == type.assemblyName
+ ? module.Assembly
+ : module.AssemblyResolver.Resolve(AssemblyNameReference.Parse(type.assemblyName));
+ var typeDef = asm.MainModule.GetType($"{type.clrNamespace}.{type.typeName}");
+ if (typeDef != null) {
+ typeDefCache.Add((module, type), typeDef);
+ return typeDef;
+ }
+ var exportedType = asm.MainModule.ExportedTypes.FirstOrDefault(
+ arg => arg.IsForwarder && arg.Namespace == type.clrNamespace && arg.Name == type.typeName);
+ if (exportedType != null) {
+ typeDef = exportedType.Resolve();
+ typeDefCache.Add((module, type), typeDef);
+ return typeDef;
+ }
+
+ //I hate you, netstandard
+ if (type.assemblyName == "mscorlib" && type.clrNamespace == "System.Reflection")
+ return module.GetTypeDefinition(("System.Reflection", type.clrNamespace, type.typeName));
+ return null;
+ }
+
+ static IEnumerable<PropertyDefinition> Properties(this TypeDefinition typedef, bool flatten)
+ {
+ foreach (var property in typedef.Properties)
+ yield return property;
+ if (!flatten || typedef.BaseType == null)
+ yield break;
+ foreach (var property in typedef.BaseType.ResolveCached().Properties(true))
+ yield return property;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Xml;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+using Tizen.NUI.Xaml;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class NodeILExtensions
+ {
+ public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, TypeReference targetTypeRef, IEnumerable<ICustomAttributeProvider> attributeProviders)
+ {
+ TypeReference typeConverter = null;
+ foreach (var attributeProvider in attributeProviders) {
+ CustomAttribute typeConverterAttribute;
+ if (
+ (typeConverterAttribute =
+ attributeProvider.CustomAttributes.FirstOrDefault(
+ cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null) {
+ typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
+ break;
+ }
+ }
+
+ return node.CanConvertValue(module, targetTypeRef, typeConverter);
+ }
+
+ public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, MemberReference bpRef)
+ {
+ var targetTypeRef = bpRef.GetBindablePropertyType(node, module);
+ var typeConverter = bpRef.GetBindablePropertyTypeConverter(module);
+ return node.CanConvertValue(module, targetTypeRef, typeConverter);
+ }
+
+ public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, TypeReference targetTypeRef, TypeReference typeConverter)
+ {
+ var str = (string)node.Value;
+
+ //If there's a [TypeConverter], use it
+ if (typeConverter != null && str != null) {
+ var typeConvAttribute = typeConverter.GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "TypeConversionAttribute"));
+ if (typeConvAttribute == null) //trust the unattributed TypeConverter
+ return true;
+ var toType = typeConvAttribute.ConstructorArguments.First().Value as TypeReference;
+ return toType.InheritsFromOrImplements(targetTypeRef);
+ }
+
+ if (targetTypeRef.FullName == "System.String")
+ {
+ return true;
+ }
+
+ var implicitOperator = targetTypeRef.GetImplicitOperatorTo(module.ImportReference(node.Value.GetType()), module);
+ if (implicitOperator != null)
+ {
+ return true;
+ }
+
+ if (true == targetTypeRef.IsInterface(typeof(IList).FullName))
+ {
+ return false;
+ }
+
+ ///No reason to return false
+ return true;
+ }
+
+ public static object GetBaseValue(EXamlContext context, string str, TypeReference targetTypeRef)
+ {
+ //Obvious Built-in conversions
+ if (str == null) //if default parameter is null, exception will throw
+ return null;
+ else if (targetTypeRef.ResolveCached().BaseType != null && targetTypeRef.ResolveCached().BaseType.FullName == "System.Enum")
+ return GetParsedEnum(context, targetTypeRef, str);
+ else if (targetTypeRef.FullName == "System.Char")
+ return Char.Parse(str);
+ else if (targetTypeRef.FullName == "System.SByte")
+ return SByte.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.Int16")
+ return Int16.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.Int32")
+ return Int32.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.Int64")
+ return Int64.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.Byte")
+ return Byte.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.UInt16")
+ return UInt16.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.UInt32")
+ return UInt32.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.UInt64")
+ return UInt64.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.Single")
+ return Single.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.Double")
+ return Double.Parse(str, CultureInfo.InvariantCulture);
+ else if (targetTypeRef.FullName == "System.Boolean")
+ {
+ if (Boolean.Parse(str))
+ return true;
+ else
+ return false;
+ }
+ else if (targetTypeRef.FullName == "System.TimeSpan")
+ {
+ var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture);
+ return ts;
+ }
+ else if (targetTypeRef.FullName == "System.DateTime")
+ {
+ var dt = DateTime.Parse(str, CultureInfo.InvariantCulture);
+ return dt;
+ }
+ else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
+ return str.Substring(2);
+ else if (targetTypeRef.FullName == "System.String")
+ return str;
+ else if (targetTypeRef.FullName == "System.Object")
+ return str;
+ else if (targetTypeRef.FullName == "System.Decimal")
+ {
+ decimal outdecimal;
+ if (decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
+ {
+ return outdecimal;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ var originalTypeRef = targetTypeRef;
+ var module = targetTypeRef.Resolve().Module;
+
+ var isNullable = false;
+ MethodReference nullableCtor = null;
+ if (targetTypeRef.ResolveCached().FullName == "System.Nullable`1")
+ {
+ var nullableTypeRef = targetTypeRef;
+ targetTypeRef = ((GenericInstanceType)targetTypeRef).GenericArguments[0];
+ isNullable = true;
+ nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1;
+ nullableCtor = nullableCtor.ResolveGenericParameters(nullableTypeRef, module);
+ }
+
+ var implicitOperator = module.TypeSystem.String.GetImplicitOperatorTo(targetTypeRef, module);
+
+ if (implicitOperator != null)
+ {
+ //Fang: Need to deal
+ //yield return Create(Ldstr, node.Value as string);
+ //yield return Create(Call, module.ImportReference(implicitOperator));
+ }
+ else
+ {
+ bool isNotNull = false;
+
+ var targetType = targetTypeRef.ResolveCached();
+
+ foreach (var method in targetType.Methods.Where(a => a.Name == "op_Implicit"))
+ {
+ TypeReference typeReference = null;
+
+ if (method.Parameters[0].ParameterType.IsGenericParameter)
+ {
+ var genericType = targetTypeRef as GenericInstanceType;
+
+ if (null != genericType)
+ {
+ for (int i = 0; i < targetType.GenericParameters.Count; i++)
+ {
+ if (method.Parameters[0].ParameterType == targetType.GenericParameters[i])
+ {
+ typeReference = genericType.GenericArguments[i];
+ }
+ }
+ }
+ }
+ else
+ {
+ typeReference = method.Parameters[0].ParameterType;
+ }
+
+ if (null != typeReference)
+ {
+ isNotNull = true;
+ if (typeReference.ResolveCached().FullName == "System.Nullable`1")
+ {
+ var genericType = typeReference as GenericInstanceType;
+ typeReference = genericType.GenericArguments[0];
+ }
+
+ //Fang: Need to deal nullable type
+ //TypeReference convertType = null;
+ //var insList = PushConvertedValue(node, context, typeReference, convertType, pushServiceProvider, boxValueTypes, unboxValueTypes);
+
+ //foreach (var ins in insList)
+ //{
+ // yield return ins;
+ //}
+ }
+ }
+
+ if (!isNotNull)
+ {
+ return null;
+ }
+ }
+
+ if (isNullable)
+ {
+ //yield return Create(Newobj, module.ImportReference(nullableCtor));
+ }
+ //if (originalTypeRef.IsValueType && boxValueTypes)
+ //{
+ // yield return Create(Box, module.ImportReference(originalTypeRef));
+ //}
+ return null;
+ }
+
+ public static object GetBaseValue(this ValueNode node, EXamlContext context, TypeReference targetTypeRef)
+ {
+ var str = (string)node.Value;
+ object ret = null;
+
+ if ("System.String" != targetTypeRef.FullName)
+ {
+ if (str.EndsWith("dp"))
+ {
+ var value = GetBaseValue(context, str.Substring(0, str.Length - "dp".Length), targetTypeRef);
+ ret = new EXamlCreateDPObject(context, value, targetTypeRef, "dp");
+ }
+ else if (str.EndsWith("px"))
+ {
+ var value = GetBaseValue(context, str.Substring(0, str.Length - "px".Length), targetTypeRef);
+ ret = new EXamlCreateDPObject(context, value, targetTypeRef, "px");
+ }
+ }
+
+ if (null == ret)
+ {
+ ret = GetBaseValue(context, str, targetTypeRef);
+ }
+
+ return ret;
+ }
+
+ public static TypeReference GetConverterType(this ValueNode node, IEnumerable<ICustomAttributeProvider> attributeProviders)
+ {
+ TypeReference typeConverter = null;
+ foreach (var attributeProvider in attributeProviders)
+ {
+ CustomAttribute typeConverterAttribute;
+ if (
+ (typeConverterAttribute =
+ attributeProvider.CustomAttributes.FirstOrDefault(
+ cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null)
+ {
+ typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
+ break;
+ }
+ }
+
+ return typeConverter;
+ }
+
+ public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context,
+ TypeReference targetTypeRef, IEnumerable<ICustomAttributeProvider> attributeProviders,
+ IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes)
+ {
+ TypeReference typeConverter = null;
+ foreach (var attributeProvider in attributeProviders)
+ {
+ CustomAttribute typeConverterAttribute;
+ if (
+ (typeConverterAttribute =
+ attributeProvider.CustomAttributes.FirstOrDefault(
+ cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null)
+ {
+ typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
+ break;
+ }
+ }
+ return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes,
+ unboxValueTypes);
+ }
+
+ public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context, FieldReference bpRef,
+ IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes)
+ {
+ var module = context.Body.Method.Module;
+ var targetTypeRef = bpRef.GetBindablePropertyType(node, module);
+ var typeConverter = bpRef.GetBindablePropertyTypeConverter(module);
+
+ return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes,
+ unboxValueTypes);
+ }
+
+ public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context,
+ TypeReference targetTypeRef, TypeReference typeConverter, IEnumerable<Instruction> pushServiceProvider,
+ bool boxValueTypes, bool unboxValueTypes)
+ {
+ var module = context.Body.Method.Module;
+ var str = (string)node.Value;
+
+ //If the TypeConverter has a ProvideCompiledAttribute that can be resolved, shortcut this
+ var compiledConverterName = typeConverter?.GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "ProvideCompiledAttribute"))?.ConstructorArguments?.First().Value as string;
+
+ if (null == compiledConverterName)
+ {
+ compiledConverterName = "Tizen.NUI.Xaml.Core.XamlC." + targetTypeRef.Name + "TypeConverter";
+ }
+
+ Type compiledConverterType;
+ if (compiledConverterName != null && (compiledConverterType = Type.GetType (compiledConverterName)) != null) {
+ var compiledConverter = Activator.CreateInstance (compiledConverterType);
+ var converter = typeof(ICompiledTypeConverter).GetMethods ().FirstOrDefault (md => md.Name == "ConvertFromString");
+ IEnumerable<Instruction> instructions = (IEnumerable<Instruction>)converter.Invoke (compiledConverter, new object[] {
+ node.Value as string, context, node as BaseNode});
+
+ if (null != instructions)
+ {
+ foreach (var i in instructions)
+ yield return i;
+ if (targetTypeRef.IsValueType && boxValueTypes)
+ yield return Instruction.Create(OpCodes.Box, module.ImportReference(targetTypeRef));
+ yield break;
+ }
+ }
+
+ //If there's a [TypeConverter], use it
+ if (typeConverter != null)
+ {
+ var isExtendedConverter = typeConverter.ImplementsInterface(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "IExtendedTypeConverter")));
+ var typeConverterCtorRef = module.ImportCtorReference(typeConverter, paramCount: 0);
+ var convertFromInvariantStringDefinition = isExtendedConverter
+ ? module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "IExtendedTypeConverter"))
+ .ResolveCached()
+ .Methods.FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 2)
+ : typeConverter.ResolveCached()
+ .AllMethods()
+ .FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 1);
+ var convertFromInvariantStringReference = module.ImportReference(convertFromInvariantStringDefinition);
+
+ yield return Instruction.Create(OpCodes.Newobj, typeConverterCtorRef);
+ yield return Instruction.Create(OpCodes.Ldstr, node.Value as string);
+
+ if (isExtendedConverter)
+ {
+ foreach (var instruction in pushServiceProvider)
+ yield return instruction;
+ }
+
+ yield return Instruction.Create(OpCodes.Callvirt, convertFromInvariantStringReference);
+
+ if (targetTypeRef.IsValueType && unboxValueTypes)
+ yield return Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(targetTypeRef));
+
+ //ConvertFrom returns an object, no need to Box
+ yield break;
+ }
+ var originalTypeRef = targetTypeRef;
+ var isNullable = false;
+ MethodReference nullableCtor = null;
+ if (targetTypeRef.ResolveCached().FullName == "System.Nullable`1")
+ {
+ var nullableTypeRef = targetTypeRef;
+ targetTypeRef = ((GenericInstanceType)targetTypeRef).GenericArguments[0];
+ isNullable = true;
+ nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1;
+ nullableCtor = nullableCtor.ResolveGenericParameters(nullableTypeRef, module);
+ }
+
+ var implicitOperator = module.TypeSystem.String.GetImplicitOperatorTo(targetTypeRef, module);
+
+ //Obvious Built-in conversions
+ if (str == null) //if default parameter is null, exception will throw
+ yield return Create(OpCodes.Ldnull);
+ else if (targetTypeRef.ResolveCached().BaseType != null && targetTypeRef.ResolveCached().BaseType.FullName == "System.Enum")
+ yield return PushParsedEnum(targetTypeRef, str, node);
+ else if (targetTypeRef.FullName == "System.Char")
+ yield return Instruction.Create(OpCodes.Ldc_I4, Char.Parse(str));
+ else if (targetTypeRef.FullName == "System.SByte")
+ yield return Instruction.Create(OpCodes.Ldc_I4, SByte.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.Int16")
+ {
+ if (str.EndsWith("dp") || str.EndsWith("px"))
+ {
+ var insOfDPValue = GetDPValue(module, node, targetTypeRef, str);
+
+ foreach (var ins in insOfDPValue)
+ {
+ yield return ins;
+ }
+ }
+ else
+ {
+ yield return Instruction.Create(OpCodes.Ldc_I4, Int16.Parse(str, CultureInfo.InvariantCulture));
+ }
+ }
+ else if (targetTypeRef.FullName == "System.Int32")
+ yield return Instruction.Create(OpCodes.Ldc_I4, Int32.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.Int64")
+ yield return Instruction.Create(OpCodes.Ldc_I8, Int64.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.Byte")
+ yield return Instruction.Create(OpCodes.Ldc_I4, Byte.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.UInt16")
+ yield return Instruction.Create(OpCodes.Ldc_I4, unchecked((int)UInt16.Parse(str, CultureInfo.InvariantCulture)));
+ else if (targetTypeRef.FullName == "System.UInt32")
+ yield return Instruction.Create(OpCodes.Ldc_I8, unchecked((uint)UInt32.Parse(str, CultureInfo.InvariantCulture)));
+ else if (targetTypeRef.FullName == "System.UInt64")
+ yield return Instruction.Create(OpCodes.Ldc_I8, unchecked((long)UInt64.Parse(str, CultureInfo.InvariantCulture)));
+ else if (targetTypeRef.FullName == "System.Single")
+ {
+ if (str.EndsWith("dp") || str.EndsWith("px"))
+ {
+ var insOfDPValue = GetDPValue(module, node, targetTypeRef, str);
+
+ foreach (var ins in insOfDPValue)
+ {
+ yield return ins;
+ }
+ }
+ else
+ {
+ yield return Instruction.Create(OpCodes.Ldc_R4, Single.Parse(str, CultureInfo.InvariantCulture));
+ }
+ }
+ else if (targetTypeRef.FullName == "System.Double")
+ yield return Instruction.Create(OpCodes.Ldc_R8, Double.Parse(str, CultureInfo.InvariantCulture));
+ else if (targetTypeRef.FullName == "System.Boolean")
+ {
+ if (Boolean.Parse(str))
+ yield return Instruction.Create(OpCodes.Ldc_I4_1);
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4_0);
+ }
+ else if (targetTypeRef.FullName == "System.TimeSpan")
+ {
+ var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture);
+ var ticks = ts.Ticks;
+ yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("mscorlib", "System", "TimeSpan"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
+ }
+ else if (targetTypeRef.FullName == "System.DateTime")
+ {
+ var dt = DateTime.Parse(str, CultureInfo.InvariantCulture);
+ var ticks = dt.Ticks;
+ yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("mscorlib", "System", "DateTime"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
+ }
+ else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
+ yield return Instruction.Create(OpCodes.Ldstr, str.Substring(2));
+ else if (targetTypeRef.FullName == "System.String")
+ yield return Instruction.Create(OpCodes.Ldstr, str);
+ else if (targetTypeRef.FullName == "System.Object")
+ yield return Instruction.Create(OpCodes.Ldstr, str);
+ else if (targetTypeRef.FullName == "System.Decimal")
+ {
+ decimal outdecimal;
+ if (decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
+ {
+ var vardef = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Decimal")));
+ context.Body.Variables.Add(vardef);
+ //Use an extra temp var so we can push the value to the stack, just like other cases
+ //IL_0003: ldstr "adecimal"
+ //IL_0008: ldc.i4.s 0x6f
+ //IL_000a: call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
+ //IL_000f: ldloca.s 0
+ //IL_0011: call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
+ //IL_0016: pop
+ yield return Create(Ldstr, str);
+ yield return Create(Ldc_I4, 0x6f); //NumberStyles.Number
+ yield return Create(Call, module.ImportPropertyGetterReference(("mscorlib", "System.Globalization", "CultureInfo"),
+ propertyName: "InvariantCulture", isStatic: true));
+ yield return Create(Ldloca, vardef);
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Decimal"),
+ methodName: "TryParse",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System.Globalization", "NumberStyles"),
+ ("mscorlib", "System", "IFormatProvider"),
+ ("mscorlib", "System", "Decimal"),
+ },
+ isStatic: true));
+ yield return Create(Pop);
+ yield return Create(Ldloc, vardef);
+ }
+ else
+ {
+ yield return Create(Ldc_I4_0);
+ yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Decimal"), parameterTypes: new[] { ("mscorlib", "System", "Int32") }));
+ }
+ }
+ else if (implicitOperator != null)
+ {
+ yield return Create(Ldstr, node.Value as string);
+ yield return Create(Call, module.ImportReference(implicitOperator));
+ }
+ else
+ {
+ bool isNotNull = false;
+
+ var targetType = targetTypeRef.ResolveCached();
+
+ foreach (var method in targetType.Methods.Where(a => a.Name == "op_Implicit"))
+ {
+ TypeReference typeReference = null;
+
+ if (method.Parameters[0].ParameterType.IsGenericParameter)
+ {
+ var genericType = targetTypeRef as GenericInstanceType;
+
+ if (null != genericType)
+ {
+ for (int i = 0; i < targetType.GenericParameters.Count; i++)
+ {
+ if (method.Parameters[0].ParameterType == targetType.GenericParameters[i])
+ {
+ typeReference = genericType.GenericArguments[i];
+ }
+ }
+ }
+ }
+ else
+ {
+ typeReference = method.Parameters[0].ParameterType;
+ }
+
+ if (null != typeReference)
+ {
+ isNotNull = true;
+ if (typeReference.ResolveCached().FullName == "System.Nullable`1")
+ {
+ var genericType = typeReference as GenericInstanceType;
+ typeReference = genericType.GenericArguments[0];
+ }
+
+ TypeReference convertType = null;
+ var insList = PushConvertedValue(node, context, typeReference, convertType, pushServiceProvider, boxValueTypes, unboxValueTypes);
+
+ foreach (var ins in insList)
+ {
+ yield return ins;
+ }
+ }
+ }
+
+ if (!isNotNull)
+ {
+ yield return Create(Ldnull);
+ }
+ }
+
+ if (isNullable)
+ yield return Create(Newobj, module.ImportReference(nullableCtor));
+ if (originalTypeRef.IsValueType && boxValueTypes)
+ yield return Create(Box, module.ImportReference(originalTypeRef));
+ }
+
+ private static TypeDefinition typeOfGraphicManager;
+ private static MethodReference getMethodOfInstance;
+ private static MethodReference methodOfConvertScriptToPixel;
+
+ static private IEnumerable<Instruction> GetDPValue(ModuleDefinition module, ValueNode node, TypeReference targetTypeRef, string str)
+ {
+ if (null == typeOfGraphicManager)
+ {
+ typeOfGraphicManager = module.GetTypeDefinition(("Tizen.NUI", "Tizen.NUI", "GraphicsTypeManager"));
+ }
+
+ if (null == getMethodOfInstance)
+ {
+ var propertyOfInstance = typeOfGraphicManager.Properties.FirstOrDefault(a => a.Name == "Instance");
+ getMethodOfInstance = propertyOfInstance.GetMethod;
+ getMethodOfInstance = module.ImportReference(getMethodOfInstance);
+ }
+
+ yield return Create(Call, getMethodOfInstance);
+ yield return Create(Ldstr, str);
+
+ if (null == methodOfConvertScriptToPixel)
+ {
+ methodOfConvertScriptToPixel = typeOfGraphicManager.Methods.FirstOrDefault(a => a.Name == "ConvertScriptToPixel");
+ methodOfConvertScriptToPixel = module.ImportReference(methodOfConvertScriptToPixel);
+ }
+
+ yield return Create(Callvirt, methodOfConvertScriptToPixel);
+
+ var convertType = typeof(System.Convert);
+ var typeOfConvert = module.GetTypeDefinition((convertType.Assembly.FullName, convertType.Namespace, convertType.Name));
+
+ var methodOfTo = typeOfConvert.Methods.FirstOrDefault(a => a.Name == "To" + targetTypeRef.Name);
+
+ yield return Create(Box, module.ImportReference(targetTypeRef));
+
+ yield return Create(Call, module.ImportReference(methodOfTo));
+ }
+
+ static public object GetParsedEnum(EXamlContext context, TypeReference enumRef, string value)
+ {
+ var enumDef = enumRef.ResolveCached();
+ if (!enumDef.IsEnum)
+ throw new InvalidOperationException();
+
+ bool isStrMatchEnumValue = false;
+
+ foreach (var field in enumDef.Fields)
+ {
+ if (field.Name == "value__")
+ continue;
+
+ if (field.Name == value)
+ {
+ isStrMatchEnumValue = true;
+ break;
+ }
+ }
+
+ if (!isStrMatchEnumValue)
+ {
+ foreach (var field in enumDef.Fields)
+ {
+ if (field.Name == "value__")
+ continue;
+ if (IsStringMatchObject(field.Constant, value))
+ {
+ isStrMatchEnumValue = true;
+ value = field.Name;
+ break;
+ }
+ }
+ }
+
+ if (!isStrMatchEnumValue)
+ {
+ throw new Exception($"{value} is not value of {enumRef.FullName}");
+ }
+
+ return new EXamlCreateObject(context, value, enumRef);
+ }
+
+ static Instruction PushParsedEnum(TypeReference enumRef, string value, IXmlLineInfo lineInfo)
+ {
+ var enumDef = enumRef.ResolveCached();
+ if (!enumDef.IsEnum)
+ throw new InvalidOperationException();
+
+ // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
+ // https://msdn.microsoft.com/en-us/library/sbbt4032.aspx
+ byte b = 0; sbyte sb = 0; short s = 0; ushort us = 0;
+ int i = 0; uint ui = 0; long l = 0; ulong ul = 0;
+ bool found = false;
+ TypeReference typeRef = null;
+
+ foreach (var field in enumDef.Fields)
+ if (field.Name == "value__")
+ typeRef = field.FieldType;
+
+ if (typeRef == null)
+ throw new ArgumentException();
+
+ foreach (var v in value.Split(',')) {
+ foreach (var field in enumDef.Fields) {
+ if (field.Name == "value__")
+ continue;
+ if (field.Name == v.Trim()) {
+ switch (typeRef.FullName) {
+ case "System.Byte":
+ b |= (byte)field.Constant;
+ break;
+ case "System.SByte":
+ if (found)
+ throw new XamlParseException($"Multi-valued enums are not valid on sbyte enum types", lineInfo);
+ sb = (sbyte)field.Constant;
+ break;
+ case "System.Int16":
+ s |= (short)field.Constant;
+ break;
+ case "System.UInt16":
+ us |= (ushort)field.Constant;
+ break;
+ case "System.Int32":
+ i |= (int)field.Constant;
+ break;
+ case "System.UInt32":
+ ui |= (uint)field.Constant;
+ break;
+ case "System.Int64":
+ l |= (long)field.Constant;
+ break;
+ case "System.UInt64":
+ ul |= (ulong)field.Constant;
+ break;
+ }
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ foreach (var field in enumDef.Fields)
+ {
+ if (field.Name == "value__")
+ continue;
+ if (IsStringMatchObject(field.Constant, v))
+ {
+ switch (typeRef.FullName)
+ {
+ case "System.Byte":
+ b |= (byte)field.Constant;
+ break;
+ case "System.SByte":
+ if (found)
+ throw new XamlParseException($"Multi-valued enums are not valid on sbyte enum types", lineInfo);
+ sb = (sbyte)field.Constant;
+ break;
+ case "System.Int16":
+ s |= (short)field.Constant;
+ break;
+ case "System.UInt16":
+ us |= (ushort)field.Constant;
+ break;
+ case "System.Int32":
+ i |= (int)field.Constant;
+ break;
+ case "System.UInt32":
+ ui |= (uint)field.Constant;
+ break;
+ case "System.Int64":
+ l |= (long)field.Constant;
+ break;
+ case "System.UInt64":
+ ul |= (ulong)field.Constant;
+ break;
+ }
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (!found)
+ throw new XamlParseException($"Enum value not found for {value}", lineInfo);
+
+ switch (typeRef.FullName) {
+ case "System.Byte":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)b);
+ case "System.SByte":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)sb);
+ case "System.Int16":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)s);
+ case "System.UInt16":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)us);
+ case "System.Int32":
+ return Instruction.Create(OpCodes.Ldc_I4, (int)i);
+ case "System.UInt32":
+ return Instruction.Create(OpCodes.Ldc_I8, (uint)ui);
+ case "System.Int64":
+ return Instruction.Create(OpCodes.Ldc_I8, (long)l);
+ case "System.UInt64":
+ return Instruction.Create(OpCodes.Ldc_I8, (ulong)ul);
+ default:
+ throw new XamlParseException($"Enum value not found for {value}", lineInfo);
+ }
+ }
+
+ private static bool IsStringMatchObject(object obj, string str)
+ {
+ try
+ {
+ switch (obj.GetType().FullName)
+ {
+ case "System.Byte":
+ return (byte)obj == byte.Parse(str);
+ case "System.SByte":
+ return (sbyte)obj == sbyte.Parse(str);
+ case "System.Int16":
+ return (Int16)obj == Int16.Parse(str);
+ case "System.UInt16":
+ return (UInt16)obj == UInt16.Parse(str);
+ case "System.Int32":
+ return (Int32)obj == Int32.Parse(str);
+ case "System.UInt32":
+ return (UInt32)obj == UInt32.Parse(str);
+ case "System.Int64":
+ return (Int64)obj == Int64.Parse(str);
+ case "System.UInt64":
+ return (UInt64)obj == UInt64.Parse(str);
+ }
+ }
+ catch (Exception e)
+ {
+ }
+
+ return false;
+ }
+
+ public static IEnumerable<Instruction> PushXmlLineInfo(this INode node, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+
+ var xmlLineInfo = node as IXmlLineInfo;
+ if (xmlLineInfo == null) {
+ yield return Create(Ldnull);
+ yield break;
+ }
+ MethodReference ctor;
+ if (xmlLineInfo.HasLineInfo()) {
+ yield return Create(Ldc_I4, xmlLineInfo.LineNumber);
+ yield return Create(Ldc_I4, xmlLineInfo.LinePosition);
+ ctor = module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfo"), parameterTypes: new[] {
+ ("mscorlib", "System", "Int32"),
+ ("mscorlib", "System", "Int32"),
+ });
+ }
+ else
+ ctor = module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfo"), parameterTypes: null);
+ yield return Create(Newobj, ctor);
+ }
+
+ public static IEnumerable<Instruction> PushParentObjectsArray(this INode node, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+
+ var nodes = new List<IElementNode>();
+ INode n = node.Parent;
+ while (n != null)
+ {
+ var en = n as IElementNode;
+ if (en != null && context.Variables.ContainsKey(en))
+ nodes.Add(en);
+ n = n.Parent;
+ }
+
+ if (nodes.Count == 0 && context.ParentContextValues == null)
+ {
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield break;
+ }
+
+ if (nodes.Count == 0)
+ {
+ yield return Instruction.Create(OpCodes.Ldarg_0);
+ yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues);
+ yield break;
+ }
+
+ //Compute parent object length
+ if (context.ParentContextValues != null)
+ {
+ yield return Instruction.Create(OpCodes.Ldarg_0);
+ yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues);
+ yield return Instruction.Create(OpCodes.Ldlen);
+ yield return Instruction.Create(OpCodes.Conv_I4);
+ }
+ else
+ yield return Instruction.Create(OpCodes.Ldc_I4_0);
+ var parentObjectLength = new VariableDefinition(module.TypeSystem.Int32);
+ context.Body.Variables.Add(parentObjectLength);
+ yield return Instruction.Create(OpCodes.Stloc, parentObjectLength);
+
+ //Create the final array
+ yield return Instruction.Create(OpCodes.Ldloc, parentObjectLength);
+ yield return Instruction.Create(OpCodes.Ldc_I4, nodes.Count);
+ yield return Instruction.Create(OpCodes.Add);
+ yield return Instruction.Create(OpCodes.Newarr, module.TypeSystem.Object);
+ var finalArray = new VariableDefinition(module.ImportArrayReference(("mscorlib", "System", "Object")));
+ context.Body.Variables.Add(finalArray);
+ yield return Instruction.Create(OpCodes.Stloc, finalArray);
+
+ //Copy original array to final
+ if (context.ParentContextValues != null)
+ {
+ yield return Create(Ldarg_0);
+ yield return Create(Ldfld, context.ParentContextValues); //sourceArray
+ yield return Create(Ldc_I4_0); //sourceIndex
+ yield return Create(Ldloc, finalArray); //destinationArray
+ yield return Create(Ldc_I4, nodes.Count); //destinationIndex
+ yield return Create(Ldloc, parentObjectLength); //length
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Array"),
+ methodName: "Copy",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "Array"),
+ ("mscorlib", "System", "Int32"),
+ ("mscorlib", "System", "Array"),
+ ("mscorlib", "System", "Int32"),
+ ("mscorlib", "System", "Int32"),
+ },
+ isStatic: true));
+ }
+
+ //Add nodes to array
+ yield return Instruction.Create(OpCodes.Ldloc, finalArray);
+ if (nodes.Count > 0)
+ {
+ for (var i = 0; i < nodes.Count; i++)
+ {
+ var en = nodes[i];
+ yield return Instruction.Create(OpCodes.Dup);
+ yield return Instruction.Create(OpCodes.Ldc_I4, i);
+ yield return Instruction.Create(OpCodes.Ldloc, context.Variables[en]);
+ if (context.Variables[en].VariableType.IsValueType)
+ yield return Instruction.Create(OpCodes.Box, module.ImportReference(context.Variables[en].VariableType));
+ yield return Instruction.Create(OpCodes.Stelem_Ref);
+ }
+ }
+ }
+
+ static IEnumerable<Instruction> PushTargetProperty(FieldReference bpRef, PropertyReference propertyRef, TypeReference declaringTypeReference, ModuleDefinition module)
+ {
+ if (bpRef != null) {
+ yield return Create(Ldsfld, bpRef);
+ yield break;
+ }
+ if (propertyRef != null) {
+ yield return Create(Ldtoken, module.ImportReference(declaringTypeReference ?? propertyRef.DeclaringType));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+ yield return Create(Ldstr, propertyRef.Name);
+ yield return Create(Call, module.ImportMethodReference(("System.Reflection.Extensions", "System.Reflection", "RuntimeReflectionExtensions"),
+ methodName: "GetRuntimeProperty",
+ parameterTypes: new[]{
+ ("mscorlib", "System", "Type"),
+ ("mscorlib", "System", "String"),
+ },
+ isStatic: true));
+ yield break;
+ }
+ yield return Create(Ldnull);
+ yield break;
+ }
+
+ public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILContext context, FieldReference bpRef = null, PropertyReference propertyRef = null, TypeReference declaringTypeReference = null)
+ {
+ var module = context.Body.Method.Module;
+
+#if NOSERVICEPROVIDER
+ yield return Instruction.Create (OpCodes.Ldnull);
+ yield break;
+#endif
+
+ var addService = module.ImportMethodReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlServiceProvider"),
+ methodName: "Add",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "Type"),
+ ("mscorlib", "System", "Object"),
+ });
+
+ yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlServiceProvider"), parameterTypes: null));
+
+ //Add a SimpleValueTargetProvider and register it as IProvideValueTarget and IReferenceProvider
+ var pushParentIl = node.PushParentObjectsArray(context).ToList();
+ if (pushParentIl[pushParentIl.Count - 1].OpCode != Ldnull) {
+ yield return Create(Dup); //Keep the serviceProvider on the stack
+ yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IProvideValueTarget")));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+
+ foreach (var instruction in pushParentIl)
+ yield return instruction;
+
+ foreach (var instruction in PushTargetProperty(bpRef, propertyRef, declaringTypeReference, module))
+ yield return instruction;
+
+ yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "SimpleValueTargetProvider"), paramCount: 2));
+ //store the provider so we can register it again with a different key
+ yield return Create(Dup);
+ var refProvider = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Object")));
+ context.Body.Variables.Add(refProvider);
+ yield return Create(Stloc, refProvider);
+ yield return Create(Callvirt, addService);
+
+ yield return Create(Dup); //Keep the serviceProvider on the stack
+ yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IReferenceProvider")));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+ yield return Create(Ldloc, refProvider);
+ yield return Create(Callvirt, addService);
+ }
+
+ //Add a XamlTypeResolver
+ if (node.NamespaceResolver != null) {
+ yield return Create(Dup); //Duplicate the serviceProvider
+ yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IXamlTypeResolver")));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+ yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlNamespaceResolver"), parameterTypes: null));
+ foreach (var kvp in node.NamespaceResolver.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml)) {
+ yield return Create(Dup); //dup the resolver
+ yield return Create(Ldstr, kvp.Key);
+ yield return Create(Ldstr, kvp.Value);
+ yield return Create(Callvirt, module.ImportMethodReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlNamespaceResolver"),
+ methodName: "Add",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System", "String"),
+ }));
+ }
+ yield return Create(Ldtoken, context.Body.Method.DeclaringType);
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System.Reflection", "IntrospectionExtensions"), methodName: "GetTypeInfo", parameterTypes: new[] { ("mscorlib", "System", "Type") }, isStatic: true));
+ yield return Create(Callvirt, module.ImportPropertyGetterReference(("mscorlib", "System.Reflection", "TypeInfo"), propertyName: "Assembly", flatten: true));
+ yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlTypeResolver"), paramCount: 2));
+ yield return Create(Callvirt, addService);
+ }
+
+ if (node is IXmlLineInfo) {
+ yield return Create(Dup); //Duplicate the serviceProvider
+ yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IXmlLineInfoProvider")));
+ yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
+ foreach (var instruction in node.PushXmlLineInfo(context))
+ yield return instruction;
+ yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfoProvider"), parameterTypes: new[] { ("System.Xml.ReaderWriter", "System.Xml", "IXmlLineInfo") }));
+ yield return Create(Callvirt, addService);
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [Preserve(AllMembers = true)]
+ internal class PerformanceProvider : IPerformanceProvider
+ {
+ internal class Statistic
+ {
+ public readonly List<Tuple<string, long>> StartTimes = new List<Tuple<string, long>>();
+ public int CallCount;
+ public long TotalTime;
+ public bool IsDetail;
+ }
+
+ readonly Dictionary<string, Statistic> _Statistics = new Dictionary<string, Statistic>();
+
+ public Dictionary<string, Statistic> Statistics {
+ get { return _Statistics; }
+ }
+
+ public void Clear()
+ {
+ Statistics.Clear();
+ }
+
+ public void Start(string reference, string tag = null, [CallerFilePath] string path = null, [CallerMemberName] string member = null)
+ {
+ string id = GetId(tag, path, member);
+
+ Statistic stats = GetStat(id);
+
+ if (tag != null)
+ stats.IsDetail = true;
+
+ stats.CallCount++;
+ stats.StartTimes.Add(new Tuple<string, long>(reference, Stopwatch.GetTimestamp()));
+ }
+
+ public void Stop(string reference, string tag = null, [CallerFilePath] string path = null, [CallerMemberName] string member = null)
+ {
+ string id = GetId(tag, path, member);
+ long stop = Stopwatch.GetTimestamp();
+
+ Statistic stats = GetStat(id);
+
+ if (!stats.StartTimes.Any())
+ return;
+
+ long start = stats.StartTimes.Single(s => s.Item1 == reference).Item2;
+ stats.TotalTime += stop - start;
+ }
+
+ public IEnumerable<string> GetStats()
+ {
+ yield return "ID | Call Count | Total Time | Avg Time";
+ foreach (KeyValuePair<string, Statistic> kvp in Statistics.OrderBy(kvp => kvp.Key)) {
+ string key = ShortenPath(kvp.Key);
+ double total = TimeSpan.FromTicks(kvp.Value.TotalTime).TotalMilliseconds;
+ double avg = total / kvp.Value.CallCount;
+ yield return string.Format("{0,-80} | {1,-10} | {2,-10}ms | {3,-8}ms", key, kvp.Value.CallCount, total, avg);
+ }
+ }
+
+ static string ShortenPath(string path)
+ {
+ int index = path.IndexOf("Tizen.NUI.Xaml.");
+ if (index > -1)
+ path = path.Substring(index + 14);
+
+ return path;
+ }
+
+ static string GetId(string tag, string path, string member)
+ {
+ return string.Format("{0}:{1}{2}", path, member, (tag != null ? "-" + tag : string.Empty));
+ }
+
+ Statistic GetStat(string id)
+ {
+ Statistic stats;
+ if (!Statistics.TryGetValue(id, out stats)) {
+ Statistics[id] = stats = new Statistic();
+ }
+ return stats;
+ }
+ }
+}
--- /dev/null
+using System;
+using Mono.Cecil;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class PropertyDefinitionExtensions
+ {
+ public static TypeReference ResolveGenericPropertyType(this PropertyDefinition self, TypeReference declaringTypeRef,
+ ModuleDefinition module)
+ {
+ if (self == null)
+ throw new ArgumentNullException(nameof(self));
+ if (declaringTypeRef == null)
+ throw new ArgumentNullException(nameof(declaringTypeRef));
+ if (!self.PropertyType.IsGenericParameter)
+ return self.PropertyType;
+
+ return ((GenericInstanceType)declaringTypeRef).GenericArguments [((GenericParameter)self.PropertyType).Position];
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Linq;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class SetFieldVisitor : IXamlNodeVisitor
+ {
+ public SetFieldVisitor(ILContext context)
+ {
+ Context = context;
+ }
+
+ public ILContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ if (!IsXNameProperty(node, parentNode))
+ return;
+ var field = Context.Body.Method.DeclaringType.Fields.SingleOrDefault(fd => fd.Name == (string)node.Value);
+ if (field == null)
+ return;
+ Context.IL.Emit(OpCodes.Ldarg_0);
+ Context.IL.Emit(OpCodes.Ldloc, Context.Variables[(IElementNode)parentNode]);
+ Context.IL.Emit(OpCodes.Stfld, field);
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ static bool IsXNameProperty(ValueNode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode xNameNode;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
+ return true;
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class SetNamescopesAndRegisterNamesVisitor : IXamlNodeVisitor
+ {
+ public SetNamescopesAndRegisterNamesVisitor(ILContext context)
+ {
+ Context = context;
+ }
+
+ ILContext Context { get; }
+
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ Context.Scopes[node] = Context.Scopes[parentNode];
+ 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)
+ {
+ Context.Scopes[node] = Context.Scopes[parentNode];
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ VariableDefinition namescopeVarDef;
+ IList<string> namesInNamescope;
+ var setNameScope = false;
+ if (parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode) || IsVisualStateGroupList(node)) {
+ namescopeVarDef = CreateNamescope();
+ namesInNamescope = new List<string>();
+ setNameScope = true;
+ } else {
+ namescopeVarDef = Context.Scopes[parentNode].Item1;
+ namesInNamescope = Context.Scopes[parentNode].Item2;
+ }
+ if (setNameScope && Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Body.Method.Module.ImportReference((XamlCTask.xamlAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"))))
+ SetNameScope(node, namescopeVarDef);
+ Context.Scopes[node] = new Tuple<VariableDefinition, IList<string>>(namescopeVarDef, namesInNamescope);
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ var namescopeVarDef = CreateNamescope();
+ IList<string> namesInNamescope = new List<string>();
+ if (Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Body.Method.Module.ImportReference((XamlCTask.xamlAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"))))
+ SetNameScope(node, namescopeVarDef);
+ Context.Scopes[node] = new System.Tuple<VariableDefinition, IList<string>>(namescopeVarDef, namesInNamescope);
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ Context.Scopes[node] = Context.Scopes[parentNode];
+ }
+
+ static bool IsDataTemplate(INode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode createContent;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
+ createContent == node)
+ return true;
+ return false;
+ }
+
+ static bool IsStyle(INode node, INode parentNode)
+ {
+ var pnode = parentNode as ElementNode;
+ return pnode != null && pnode.XmlType.Name == "Style";
+ }
+
+ static bool IsVisualStateGroupList(ElementNode node)
+ {
+ return node != null && node.XmlType.Name == "VisualStateGroup" && node.Parent is IListNode;
+ }
+
+ static bool IsXNameProperty(ValueNode node, INode parentNode)
+ {
+ var parentElement = parentNode as IElementNode;
+ INode xNameNode;
+ if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
+ return true;
+ return false;
+ }
+
+ VariableDefinition CreateNamescope()
+ {
+ var module = Context.Body.Method.Module;
+ var vardef = new VariableDefinition(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "NameScope")));
+ Context.Body.Variables.Add(vardef);
+ Context.IL.Emit(OpCodes.Newobj, module.ImportCtorReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "NameScope"), parameterTypes: null));
+ Context.IL.Emit(OpCodes.Stloc, vardef);
+ return vardef;
+ }
+
+ void SetNameScope(ElementNode node, VariableDefinition ns)
+ {
+ var module = Context.Body.Method.Module;
+ Context.IL.Emit(OpCodes.Ldloc, Context.Variables[node]);
+ Context.IL.Emit(OpCodes.Ldloc, ns);
+ Context.IL.Emit(OpCodes.Call, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "NameScope"),
+ methodName: "SetNameScope",
+ parameterTypes: new[] {
+ (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
+ (XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "INameScope"),
+ },
+ isStatic: true));
+ }
+
+ void RegisterName(string str, VariableDefinition namescopeVarDef, IList<string> namesInNamescope, VariableDefinition element, INode node)
+ {
+ if (namesInNamescope.Contains(str))
+ throw new XamlParseException($"An element with the name \"{str}\" already exists in this NameScope", node as IXmlLineInfo);
+ namesInNamescope.Add(str);
+
+ var module = Context.Body.Method.Module;
+ Context.IL.Emit(OpCodes.Ldloc, namescopeVarDef);
+ Context.IL.Emit(OpCodes.Ldstr, str);
+ Context.IL.Emit(OpCodes.Ldloc, element);
+ Context.IL.Emit(OpCodes.Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "INameScope"),
+ methodName: "RegisterName",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System", "Object"),
+ }));
+ }
+
+ void SetStyleId(string str, VariableDefinition element)
+ {
+ if (!element.VariableType.InheritsFromOrImplements(Context.Body.Method.Module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "Element"))))
+ return;
+
+ var module = Context.Body.Method.Module;
+
+ var nop = Instruction.Create(OpCodes.Nop);
+ Context.IL.Emit(OpCodes.Ldloc, element);
+ Context.IL.Emit(OpCodes.Callvirt, module.ImportPropertyGetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "Element"), propertyName: "StyleId"));
+ Context.IL.Emit(OpCodes.Brtrue, nop);
+ Context.IL.Emit(OpCodes.Ldloc, element);
+ Context.IL.Emit(OpCodes.Ldstr, str);
+ Context.IL.Emit(OpCodes.Callvirt, module.ImportPropertySetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "Element"), propertyName: "StyleId"));
+ Context.IL.Append(nop);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Rocks;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Binding.Internals;
+
+using Tizen.NUI.Xaml;
+
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class SetPropertiesVisitor : IXamlNodeVisitor
+ {
+ static int dtcount;
+ static int typedBindingCount;
+
+ static readonly IList<XmlName> skips = new List<XmlName>
+ {
+ XmlName.xKey,
+ XmlName.xTypeArguments,
+ XmlName.xArguments,
+ XmlName.xFactoryMethod,
+ XmlName.xName,
+ XmlName.xDataType
+ };
+
+ public SetPropertiesVisitor(ILContext context, bool stopOnResourceDictionary = false)
+ {
+ Context = context;
+ Module = context.Body.Method.Module;
+ StopOnResourceDictionary = stopOnResourceDictionary;
+ }
+
+ public ILContext Context { get; }
+ public bool StopOnResourceDictionary { get; }
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
+ public bool StopOnDataTemplate => true;
+ public bool VisitNodeOnDataTemplate => true;
+ public bool SkipChildren(INode node, INode parentNode) => false;
+
+ public bool IsResourceDictionary(ElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ ModuleDefinition Module { get; }
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ //TODO support Label text as element
+ XmlName propertyName;
+ if (!TryGetPropertyName(node, parentNode, out propertyName))
+ {
+ if (!IsCollectionItem(node, parentNode))
+ return;
+ string contentProperty;
+ if (!Context.Variables.ContainsKey((IElementNode)parentNode))
+ return;
+ var parentVar = Context.Variables[(IElementNode)parentNode];
+ if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
+ propertyName = new XmlName(((IElementNode)parentNode).NamespaceURI, contentProperty);
+ else
+ return;
+ }
+
+ if (TrySetRuntimeName(propertyName, Context.Variables[(IElementNode)parentNode], node))
+ return;
+ if (skips.Contains(propertyName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+ if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
+ return;
+ Context.IL.Append(SetPropertyValue(Context.Variables [(IElementNode)parentNode], propertyName, node, Context, node));
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ XmlName propertyName = XmlName.Empty;
+
+ //Simplify ListNodes with single elements
+ var pList = parentNode as ListNode;
+ if (pList != null && pList.CollectionItems.Count == 1) {
+ propertyName = pList.XmlName;
+ parentNode = parentNode.Parent;
+ }
+
+ if ((propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) && skips.Contains(propertyName))
+ return;
+
+ if (propertyName == XmlName._CreateContent) {
+ SetDataTemplate((IElementNode)parentNode, node, Context, node);
+ return;
+ }
+
+ //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
+ var vardef = Context.Variables[node];
+ var vardefref = new VariableDefinitionReference(vardef);
+ var localName = propertyName.LocalName;
+ TypeReference declaringTypeReference = null;
+ FieldReference bpRef = null;
+ var _ = false;
+ PropertyDefinition propertyRef = null;
+ if (parentNode is IElementNode && propertyName != XmlName.Empty) {
+ bpRef = GetBindablePropertyReference(Context.Variables [(IElementNode)parentNode], propertyName.NamespaceURI, ref localName, out _, Context, node);
+ propertyRef = Context.Variables [(IElementNode)parentNode].VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ }
+ Context.IL.Append(ProvideValue(vardefref, Context, Module, node, bpRef:bpRef, propertyRef:propertyRef, propertyDeclaringTypeRef: declaringTypeReference));
+ if (vardef != vardefref.VariableDefinition)
+ {
+ vardef = vardefref.VariableDefinition;
+ Context.Body.Variables.Add(vardef);
+ Context.Variables[node] = vardef;
+ }
+
+ if (propertyName != XmlName.Empty) {
+ if (skips.Contains(propertyName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+
+ Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
+ var parentVar = Context.Variables[(IElementNode)parentNode];
+ string contentProperty;
+
+ bool isAdded = false;
+
+ if (CanAddToResourceDictionary(parentVar, parentVar.VariableType, node, node, Context))
+ {
+ Context.IL.Emit(Ldloc, parentVar);
+ Context.IL.Append(AddToResourceDictionary(node, node, Context));
+ isAdded = true;
+ }
+ // Collection element, implicit content, or implicit collection element.
+ else if (parentVar.VariableType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).Any())
+ {
+ var elementType = parentVar.VariableType;
+ var paramType = Context.Variables[node].VariableType;
+
+ foreach (var adderTuple in elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module))
+ {
+ var adderRef = Module.ImportReference(adderTuple.Item1);
+ adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
+
+ if (IsAddMethodOfCollection(Module, adderRef.Resolve()))
+ {
+ isAdded = true;
+ }
+ else if (paramType.InheritsFromOrImplements(adderTuple.Item1.Parameters[0].ParameterType.FullName))
+ {
+ isAdded = true;
+ }
+
+ if (isAdded)
+ {
+ Context.IL.Emit(Ldloc, parentVar);
+ Context.IL.Emit(Ldloc, vardef);
+ Context.IL.Emit(Callvirt, adderRef);
+ if (adderRef.ReturnType.FullName != "System.Void")
+ Context.IL.Emit(Pop);
+ break;
+ }
+ }
+ }
+
+ if (!isAdded && (contentProperty = GetContentProperty(parentVar.VariableType)) != null)
+ {
+ var name = new XmlName(node.NamespaceURI, contentProperty);
+ if (skips.Contains(name))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains(propertyName))
+ return;
+ Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], name, node, Context, node));
+ isAdded = true;
+ }
+
+ if (!isAdded)
+ {
+ throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
+ }
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
+ {
+// IL_000d: ldloc.2
+// IL_000e: callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Layout`1<class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.View>::get_Children()
+// IL_0013: ldloc.0
+// IL_0014: callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.View>::Add(!0)
+
+ var parentList = (ListNode)parentNode;
+ var parent = Context.Variables[((IElementNode)parentNode.Parent)];
+
+ if (skips.Contains(parentList.XmlName))
+ return;
+ if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
+ return;
+ var elementType = parent.VariableType;
+ var localname = parentList.XmlName.LocalName;
+
+ TypeReference propertyType;
+ Context.IL.Append(GetPropertyValue(parent, parentList.XmlName, Context, node, out propertyType));
+
+ if (CanAddToResourceDictionary(parent, propertyType, node, node, Context)) {
+ Context.IL.Append(AddToResourceDictionary(node, node, Context));
+ return;
+ }
+ var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).FirstOrDefault();
+ if (adderTuple == null)
+ throw new XamlParseException($"Can not Add() elements to {parent.VariableType}.{localname}", node);
+ var adderRef = Module.ImportReference(adderTuple.Item1);
+ adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
+
+ Context.IL.Emit(OpCodes.Ldloc, vardef);
+ Context.IL.Emit(OpCodes.Callvirt, adderRef);
+ if (adderRef.ReturnType.FullName != "System.Void")
+ Context.IL.Emit(OpCodes.Pop);
+ }
+ }
+
+ private static bool IsAddMethodOfCollection(ModuleDefinition module, MethodDefinition methodDef)
+ {
+ return module.ImportReference(typeof(List<string>)).InheritsFromOrImplements(methodDef.DeclaringType);
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
+ {
+ name = default(XmlName);
+ var parentElement = parentNode as IElementNode;
+ if (parentElement == null)
+ return false;
+ foreach (var kvp in parentElement.Properties)
+ {
+ if (kvp.Value != node)
+ continue;
+ name = kvp.Key;
+ return true;
+ }
+ return false;
+ }
+
+ static bool IsCollectionItem(INode node, INode parentNode)
+ {
+ var parentList = parentNode as IListNode;
+ if (parentList == null)
+ return false;
+ return parentList.CollectionItems.Contains(node);
+ }
+
+ internal static string GetContentProperty(TypeReference typeRef)
+ {
+ var typeDef = typeRef.ResolveCached();
+ var attributes = typeDef.CustomAttributes;
+ var attr =
+ attributes.FirstOrDefault(cad => ContentPropertyAttribute.ContentPropertyTypes.Contains(cad.AttributeType.FullName));
+ if (attr != null)
+ return attr.ConstructorArguments[0].Value as string;
+ if (typeDef.BaseType == null)
+ return null;
+ return GetContentProperty(typeDef.BaseType);
+ }
+
+ public static IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context,
+ ModuleDefinition module, ElementNode node, FieldReference bpRef = null,
+ PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null)
+ {
+ GenericInstanceType markupExtension;
+ IList<TypeReference> genericArguments;
+ if (vardefref.VariableDefinition.VariableType.FullName == "Tizen.NUI.Xaml.ArrayExtension" &&
+ vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Tizen.NUI.Xaml.IMarkupExtension`1",
+ out markupExtension, out genericArguments))
+ {
+ var markExt = markupExtension.ResolveCached();
+ var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
+ var provideValue = module.ImportReference(provideValueInfo);
+ provideValue =
+ module.ImportReference(provideValue.ResolveGenericParameters(markupExtension, module));
+
+ var typeNode = node.Properties[new XmlName("", "Type")];
+ TypeReference arrayTypeRef;
+ if (context.TypeExtensions.TryGetValue(typeNode, out arrayTypeRef))
+ vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(arrayTypeRef.MakeArrayType()));
+ else
+ vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(genericArguments.First()));
+ yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
+ foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
+ yield return instruction;
+ yield return Instruction.Create(OpCodes.Callvirt, provideValue);
+
+ if (arrayTypeRef != null)
+ yield return Instruction.Create(OpCodes.Castclass, module.ImportReference(arrayTypeRef.MakeArrayType()));
+ yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
+ }
+ else if (vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Tizen.NUI.Xaml.IMarkupExtension`1",
+ out markupExtension, out genericArguments))
+ {
+ var acceptEmptyServiceProvider = vardefref.VariableDefinition.VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
+ if (vardefref.VariableDefinition.VariableType.FullName == "Tizen.NUI.Xaml.BindingExtension")
+ foreach (var instruction in CompileBindingPath(node, context, vardefref.VariableDefinition))
+ yield return instruction;
+
+ var markExt = markupExtension.ResolveCached();
+ var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
+ var provideValue = module.ImportReference(provideValueInfo);
+ provideValue =
+ module.ImportReference(provideValue.ResolveGenericParameters(markupExtension, module));
+
+ vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(genericArguments.First()));
+ yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
+ if (acceptEmptyServiceProvider)
+ yield return Instruction.Create(OpCodes.Ldnull);
+ else
+ foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
+ yield return instruction;
+ yield return Instruction.Create(OpCodes.Callvirt, provideValue);
+ yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
+ }
+ else if (context.Variables[node].VariableType.ImplementsInterface(module.ImportReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IMarkupExtension"))))
+ {
+ var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
+ vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
+ yield return Create(Ldloc, context.Variables[node]);
+ if (acceptEmptyServiceProvider)
+ yield return Create(Ldnull);
+ else
+ foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
+ yield return instruction;
+ yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IMarkupExtension"),
+ methodName: "ProvideValue",
+ parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
+ yield return Create(Stloc, vardefref.VariableDefinition);
+ }
+ else if (context.Variables[node].VariableType.ImplementsInterface(module.ImportReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IValueProvider"))))
+ {
+ var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
+ var valueProviderType = context.Variables[node].VariableType;
+ //If the IValueProvider has a ProvideCompiledAttribute that can be resolved, shortcut this
+ var compiledValueProviderName = valueProviderType?.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "ProvideCompiledAttribute"))?.ConstructorArguments?[0].Value as string;
+ Type compiledValueProviderType;
+ if (compiledValueProviderName != null && (compiledValueProviderType = Type.GetType(compiledValueProviderName)) != null) {
+ var compiledValueProvider = Activator.CreateInstance(compiledValueProviderType);
+ var cProvideValue = typeof(ICompiledValueProvider).GetMethods().FirstOrDefault(md => md.Name == "ProvideValue");
+ var instructions = (IEnumerable<Instruction>)cProvideValue.Invoke(compiledValueProvider, new object[] {
+ vardefref,
+ context.Body.Method.Module,
+ node as BaseNode,
+ context});
+ foreach (var i in instructions)
+ yield return i;
+ yield break;
+ }
+
+ vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
+ yield return Create(Ldloc, context.Variables[node]);
+ if (acceptEmptyServiceProvider)
+ yield return Create(Ldnull);
+ else
+ foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
+ yield return instruction;
+ yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IValueProvider"),
+ methodName: "ProvideValue",
+ parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
+ yield return Create(Stloc, vardefref.VariableDefinition);
+ }
+ }
+
+ //Once we get compiled IValueProvider, this will move to the BindingExpression
+ static IEnumerable<Instruction> CompileBindingPath(ElementNode node, ILContext context, VariableDefinition bindingExt)
+ {
+ //TODO support casting operators
+ var module = context.Module;
+
+ INode pathNode;
+ if (!node.Properties.TryGetValue(new XmlName("", "Path"), out pathNode) && node.CollectionItems.Any())
+ pathNode = node.CollectionItems [0];
+ var path = (pathNode as ValueNode)?.Value as string;
+ BindingMode declaredmode;
+ if ( !node.Properties.TryGetValue(new XmlName("", "Mode"), out INode modeNode)
+ || !Enum.TryParse((modeNode as ValueNode)?.Value as string, true, out declaredmode))
+ declaredmode = BindingMode.TwoWay; //meaning the mode isn't specified in the Binding extension. generate getters, setters, handlers
+
+ INode dataTypeNode = null;
+ IElementNode n = node;
+ while (n != null) {
+ if (n.Properties.TryGetValue(XmlName.xDataType, out dataTypeNode))
+ break;
+ n = n.Parent as IElementNode;
+ }
+ var dataType = (dataTypeNode as ValueNode)?.Value as string;
+ if (dataType == null)
+ yield break; //throw
+
+ var prefix = dataType.Contains(":") ? dataType.Substring(0, dataType.IndexOf(":", StringComparison.Ordinal)) : "";
+ var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? "";
+ if (!string.IsNullOrEmpty(prefix) && string.IsNullOrEmpty(namespaceuri))
+ throw new XamlParseException($"Undeclared xmlns prefix '{prefix}'", dataTypeNode as IXmlLineInfo);
+
+ var dtXType = new XmlType(namespaceuri, dataType, null);
+
+ var tSourceRef = dtXType.GetTypeReference(module, (IXmlLineInfo)node);
+ if (tSourceRef == null)
+ yield break; //throw
+
+ var properties = ParsePath(path, tSourceRef, node as IXmlLineInfo, module);
+ var tPropertyRef = properties != null && properties.Any() ? properties.Last().Item1.PropertyType : tSourceRef;
+ tPropertyRef = module.ImportReference(tPropertyRef);
+
+ var funcRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef }));
+ var actionRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Action`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef }));
+ var funcObjRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, module.TypeSystem.Object }));
+ var tupleRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Tuple`2")).MakeGenericInstanceType(new [] { funcObjRef, module.TypeSystem.String}));
+ var typedBindingRef = module.ImportReference(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "TypedBinding`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef}));
+
+ var ctorInfo = module.ImportReference(typedBindingRef.ResolveCached().Methods.FirstOrDefault(md => md.IsConstructor && !md.IsStatic && md.Parameters.Count == 3 ));
+ var ctorinforef = ctorInfo.MakeGeneric(typedBindingRef, funcRef, actionRef, tupleRef);
+
+ yield return Instruction.Create(OpCodes.Ldloc, bindingExt);
+ foreach (var instruction in CompiledBindingGetGetter(tSourceRef, tPropertyRef, properties, node, context))
+ yield return instruction;
+ if (declaredmode != BindingMode.OneTime && declaredmode != BindingMode.OneWay) { //if the mode is explicitly 1w, or 1t, no need for setters
+ foreach (var instruction in CompiledBindingGetSetter(tSourceRef, tPropertyRef, properties, node, context))
+ yield return instruction;
+ } else
+ yield return Create(Ldnull);
+ if (declaredmode != BindingMode.OneTime) { //if the mode is explicitly 1t, no need for handlers
+ foreach (var instruction in CompiledBindingGetHandlers(tSourceRef, tPropertyRef, properties, node, context))
+ yield return instruction;
+ } else
+ yield return Create(Ldnull);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(ctorinforef));
+ yield return Instruction.Create(OpCodes.Callvirt, module.ImportPropertySetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingExtension"), propertyName: "TypedBinding"));
+ }
+
+ static IList<Tuple<PropertyDefinition, string>> ParsePath(string path, TypeReference tSourceRef, IXmlLineInfo lineInfo, ModuleDefinition module)
+ {
+ if (string.IsNullOrWhiteSpace(path))
+ return null;
+ path = path.Trim(' ', '.'); //trim leading or trailing dots
+ var parts = path.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);
+ var properties = new List<Tuple<PropertyDefinition, string>>();
+
+ var previousPartTypeRef = tSourceRef;
+ TypeReference _;
+ foreach (var part in parts) {
+ var p = part;
+ string indexArg = null;
+ var lbIndex = p.IndexOf('[');
+ if (lbIndex != -1) {
+ var rbIndex = p.LastIndexOf(']');
+ if (rbIndex == -1)
+ throw new XamlParseException("Binding: Indexer did not contain closing bracket", lineInfo);
+
+ var argLength = rbIndex - lbIndex - 1;
+ if (argLength == 0)
+ throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
+
+ indexArg = p.Substring(lbIndex + 1, argLength).Trim();
+ if (indexArg.Length == 0)
+ throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
+
+ p = p.Substring(0, lbIndex);
+ p = p.Trim();
+ }
+
+ if (p.Length > 0) {
+ var property = previousPartTypeRef.GetProperty(pd => pd.Name == p && pd.GetMethod != null && pd.GetMethod.IsPublic, out _)
+ ?? throw new XamlParseException($"Binding: Property '{p}' not found on '{previousPartTypeRef}'", lineInfo);
+ properties.Add(new Tuple<PropertyDefinition, string>(property,null));
+ previousPartTypeRef = property.PropertyType;
+ }
+ if (indexArg != null) {
+ var defaultMemberAttribute = previousPartTypeRef.GetCustomAttribute(module, ("mscorlib", "System.Reflection", "DefaultMemberAttribute"));
+ var indexerName = defaultMemberAttribute?.ConstructorArguments?.FirstOrDefault().Value as string ?? "Item";
+ var indexer = previousPartTypeRef.GetProperty(pd => pd.Name == indexerName && pd.GetMethod != null && pd.GetMethod.IsPublic, out _);
+ properties.Add(new Tuple<PropertyDefinition, string>(indexer, indexArg));
+ if (indexer.PropertyType != module.TypeSystem.String && indexer.PropertyType != module.TypeSystem.Int32)
+ throw new XamlParseException($"Binding: Unsupported indexer index type: {indexer.PropertyType.FullName}", lineInfo);
+ previousPartTypeRef = indexer.PropertyType;
+ }
+ }
+ return properties;
+ }
+
+ static IEnumerable<Instruction> CompiledBindingGetGetter(TypeReference tSourceRef, TypeReference tPropertyRef, IList<Tuple<PropertyDefinition, string>> properties, ElementNode node, ILContext context)
+ {
+// .method private static hidebysig default string '<Main>m__0' (class ViewModel vm) cil managed
+// {
+// .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ...
+//
+// IL_0000: ldarg.0
+// IL_0001: callvirt instance class ViewModel class ViewModel::get_Model()
+// IL_0006: callvirt instance string class ViewModel::get_Text()
+// IL_0006: ret
+// }
+
+ var module = context.Module;
+ var getter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}",
+ MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static,
+ tPropertyRef) {
+ Parameters = {
+ new ParameterDefinition(tSourceRef)
+ },
+ CustomAttributes = {
+ new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
+ }
+ };
+ getter.Body.InitLocals = true;
+ var il = getter.Body.GetILProcessor();
+
+ if (properties == null || properties.Count == 0) { //return self
+ il.Emit(Ldarg_0);
+ il.Emit(Ret);
+ }
+ else {
+ if (tSourceRef.IsValueType)
+ il.Emit(Ldarga_S, (byte)0);
+ else
+ il.Emit(Ldarg_0);
+
+ foreach (var propTuple in properties) {
+ var property = propTuple.Item1;
+ var indexerArg = propTuple.Item2;
+ if (indexerArg != null) {
+ if (property.GetMethod.Parameters[0].ParameterType == module.TypeSystem.String)
+ il.Emit(Ldstr, indexerArg);
+ else if (property.GetMethod.Parameters[0].ParameterType == module.TypeSystem.Int32) {
+ int index;
+ if (!int.TryParse(indexerArg, out index))
+ throw new XamlParseException($"Binding: {indexerArg} could not be parsed as an index for a {property.Name}", node as IXmlLineInfo);
+ il.Emit(Ldc_I4, index);
+ }
+ }
+ if (property.GetMethod.IsVirtual)
+ il.Emit(Callvirt, module.ImportReference(property.GetMethod));
+ else
+ il.Emit(Call, module.ImportReference(property.GetMethod));
+ }
+
+ il.Emit(Ret);
+ }
+ context.Body.Method.DeclaringType.Methods.Add(getter);
+
+// IL_0007: ldnull
+// IL_0008: ldftn string class Test::'<Main>m__0'(class ViewModel)
+// IL_000e: newobj instance void class [mscorlib]System.Func`2<class ViewModel, string>::'.ctor'(object, native int)
+
+ yield return Create(Ldnull);
+ yield return Create(Ldftn, getter);
+ yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Func`2"), paramCount: 2, classArguments: new[] { tSourceRef, tPropertyRef }));
+ }
+
+ static IEnumerable<Instruction> CompiledBindingGetSetter(TypeReference tSourceRef, TypeReference tPropertyRef, IList<Tuple<PropertyDefinition, string>> properties, ElementNode node, ILContext context)
+ {
+ if (properties == null || properties.Count == 0) {
+ yield return Create(Ldnull);
+ yield break;
+ }
+
+ // .method private static hidebysig default void '<Main>m__1' (class ViewModel vm, string s) cil managed
+ // {
+ // .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
+ //
+ // IL_0000: ldarg.0
+ // IL_0001: callvirt instance class ViewModel class ViewModel::get_Model()
+ // IL_0006: ldarg.1
+ // IL_0007: callvirt instance void class ViewModel::set_Text(string)
+ // IL_000c: ret
+ // }
+
+ var module = context.Module;
+ var setter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}",
+ MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static,
+ module.TypeSystem.Void) {
+ Parameters = {
+ new ParameterDefinition(tSourceRef),
+ new ParameterDefinition(tPropertyRef)
+ },
+ CustomAttributes = {
+ new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
+ }
+ };
+ setter.Body.InitLocals = true;
+
+ var il = setter.Body.GetILProcessor();
+ var lastProperty = properties.LastOrDefault();
+ var setterRef = lastProperty?.Item1.SetMethod;
+ if (setterRef == null) {
+ yield return Create(Ldnull); //throw or not ?
+ yield break;
+ }
+
+ if (tSourceRef.IsValueType)
+ il.Emit(Ldarga_S, (byte)0);
+ else
+ il.Emit(Ldarg_0);
+ for (int i = 0; i < properties.Count - 1; i++) {
+ var property = properties[i].Item1;
+ var indexerArg = properties[i].Item2;
+ if (indexerArg != null) {
+ if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.String)
+ il.Emit(Ldstr, indexerArg);
+ else if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.Int32) {
+ int index;
+ if (!int.TryParse(indexerArg, out index))
+ throw new XamlParseException($"Binding: {indexerArg} could not be parsed as an index for a {property.Name}", node as IXmlLineInfo);
+ il.Emit(Ldc_I4, index);
+ }
+ }
+ if (property.GetMethod.IsVirtual)
+ il.Emit(Callvirt, module.ImportReference(property.GetMethod));
+ else
+ il.Emit(Call, module.ImportReference(property.GetMethod));
+ }
+
+ var indexer = properties.Last().Item2;
+ if (indexer != null) {
+ if (lastProperty.Item1.GetMethod.Parameters [0].ParameterType == module.TypeSystem.String)
+ il.Emit(Ldstr, indexer);
+ else if (lastProperty.Item1.GetMethod.Parameters [0].ParameterType == module.TypeSystem.Int32) {
+ int index;
+ if (!int.TryParse(indexer, out index))
+ throw new XamlParseException($"Binding: {indexer} could not be parsed as an index for a {lastProperty.Item1.Name}", node as IXmlLineInfo);
+ il.Emit(Ldc_I4, index);
+ }
+ }
+
+ il.Emit(Ldarg_1);
+
+ if (setterRef.IsVirtual)
+ il.Emit(Callvirt, module.ImportReference(setterRef));
+ else
+ il.Emit(Call, module.ImportReference(setterRef));
+
+ il.Emit(Ret);
+
+ context.Body.Method.DeclaringType.Methods.Add(setter);
+
+// IL_0024: ldnull
+// IL_0025: ldftn void class Test::'<Main>m__1'(class ViewModel, string)
+// IL_002b: newobj instance void class [mscorlib]System.Action`2<class ViewModel, string>::'.ctor'(object, native int)
+ yield return Create(Ldnull);
+ yield return Create(Ldftn, setter);
+ yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Action`2"),
+ paramCount: 2,
+ classArguments:
+ new[] { tSourceRef, tPropertyRef }));
+ }
+
+ static IEnumerable<Instruction> CompiledBindingGetHandlers(TypeReference tSourceRef, TypeReference tPropertyRef, IList<Tuple<PropertyDefinition, string>> properties, ElementNode node, ILContext context)
+ {
+// .method private static hidebysig default object '<Main>m__2'(class ViewModel vm) cil managed {
+// .custom instance void class [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
+// IL_0000: ldarg.0
+// IL_0001: ret
+// } // end of method Test::<Main>m__2
+
+// .method private static hidebysig default object '<Main>m__3' (class ViewModel vm) cil managed {
+// .custom instance void class [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() = (01 00 00 00 ) // ....
+// IL_0000: ldarg.0
+// IL_0001: callvirt instance class ViewModel class ViewModel::get_Model()
+// IL_0006: ret
+// }
+
+ var module = context.Module;
+
+ var partGetters = new List<MethodDefinition>();
+ if (properties == null || properties.Count == 0) {
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield break;
+ }
+
+ for (int i = 0; i < properties.Count; i++) {
+ var tuple = properties [i];
+ var partGetter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, module.TypeSystem.Object) {
+ Parameters = {
+ new ParameterDefinition(tSourceRef)
+ },
+ CustomAttributes = {
+ new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
+ }
+ };
+ partGetter.Body.InitLocals = true;
+ var il = partGetter.Body.GetILProcessor();
+
+ if (i == 0) { //return self
+ il.Emit(Ldarg_0);
+ if (tSourceRef.IsValueType)
+ il.Emit(Box, module.ImportReference(tSourceRef));
+
+ il.Emit(Ret);
+ context.Body.Method.DeclaringType.Methods.Add(partGetter);
+ partGetters.Add(partGetter);
+ continue;
+ }
+
+ if (tSourceRef.IsValueType)
+ il.Emit(Ldarga_S, (byte)0);
+ else
+ il.Emit(Ldarg_0);
+ var lastGetterTypeRef = tSourceRef;
+ for (int j = 0; j < i; j++) {
+ var propTuple = properties [j];
+ var property = propTuple.Item1;
+ var indexerArg = propTuple.Item2;
+ if (indexerArg != null) {
+ if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.String)
+ il.Emit(OpCodes.Ldstr, indexerArg);
+ else if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.Int32) {
+ int index;
+ if (!int.TryParse(indexerArg, out index))
+ throw new XamlParseException($"Binding: {indexerArg} could not be parsed as an index for a {property.Name}", node as IXmlLineInfo);
+ il.Emit(OpCodes.Ldc_I4, index);
+ }
+ }
+ if (property.GetMethod.IsVirtual)
+ il.Emit(Callvirt, module.ImportReference(property.GetMethod));
+ else
+ il.Emit(Call, module.ImportReference(property.GetMethod));
+ lastGetterTypeRef = property.PropertyType;
+ }
+ if (lastGetterTypeRef.IsValueType)
+ il.Emit(Box, module.ImportReference(lastGetterTypeRef));
+
+ il.Emit(OpCodes.Ret);
+ context.Body.Method.DeclaringType.Methods.Add(partGetter);
+ partGetters.Add(partGetter);
+ }
+
+ var funcObjRef = context.Module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, module.TypeSystem.Object }));
+ var tupleRef = context.Module.ImportReference(module.ImportReference(("mscorlib", "System", "Tuple`2")).MakeGenericInstanceType(new [] { funcObjRef, module.TypeSystem.String }));
+ var funcCtor = module.ImportReference(funcObjRef.ResolveCached().GetConstructors().First());
+ funcCtor = funcCtor.MakeGeneric(funcObjRef, new [] { tSourceRef, module.TypeSystem.Object });
+ var tupleCtor = module.ImportReference(tupleRef.ResolveCached().GetConstructors().First());
+ tupleCtor = tupleCtor.MakeGeneric(tupleRef, new [] { funcObjRef, module.TypeSystem.String});
+
+// IL_003a: ldc.i4.2
+// IL_003b: newarr class [mscorlib] System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel,object>,string>
+
+// IL_0040: dup
+// IL_0041: ldc.i4.0
+// IL_0049: ldnull
+// IL_004a: ldftn object class Test::'<Main>m__2'(class ViewModel)
+// IL_0050: newobj instance void class [mscorlib]System.Func`2<class ViewModel, object>::'.ctor'(object, native int)
+// IL_005f: ldstr "Model"
+// IL_0064: newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
+// IL_0069: stelem.ref
+
+// IL_006a: dup
+// IL_006b: ldc.i4.1
+// IL_0073: ldnull
+// IL_0074: ldftn object class Test::'<Main>m__3'(class ViewModel)
+// IL_007a: newobj instance void class [mscorlib]System.Func`2<class ViewModel, object>::'.ctor'(object, native int)
+// IL_0089: ldstr "Text"
+// IL_008e: newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
+// IL_0093: stelem.ref
+
+ yield return Instruction.Create(OpCodes.Ldc_I4, properties.Count);
+ yield return Instruction.Create(OpCodes.Newarr, tupleRef);
+
+ for (var i = 0; i < properties.Count; i++) {
+ yield return Instruction.Create(OpCodes.Dup);
+ yield return Instruction.Create(OpCodes.Ldc_I4, i);
+ yield return Instruction.Create(OpCodes.Ldnull);
+ yield return Instruction.Create(OpCodes.Ldftn, partGetters [i]);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(funcCtor));
+ yield return Instruction.Create(OpCodes.Ldstr, properties [i].Item1.Name);
+ yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(tupleCtor));
+ yield return Instruction.Create(OpCodes.Stelem_Ref);
+ }
+ }
+
+ public static IEnumerable<Instruction> SetPropertyValue(VariableDefinition parent, XmlName propertyName, INode valueNode, ILContext context, IXmlLineInfo iXmlLineInfo)
+ {
+ var module = context.Body.Method.Module;
+ var localName = propertyName.LocalName;
+ bool attached;
+
+ var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, iXmlLineInfo);
+
+ //If the target is an event, connect
+ if (CanConnectEvent(parent, localName, attached))
+ {
+ var instrunctions = ConnectEvent(parent, localName, valueNode, iXmlLineInfo, context);
+ if (null != context.InsOfAddEvent)
+ {
+ foreach (var ins in instrunctions)
+ {
+ context.InsOfAddEvent.Add(ins);
+ }
+ }
+ return instrunctions;
+ }
+
+ //If Value is DynamicResource, SetDynamicResource
+ if (CanSetDynamicResource(bpRef, valueNode, context))
+ return SetDynamicResource(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
+
+ //If Value is a BindingBase and target is a BP, SetBinding
+ if (CanSetBinding(bpRef, valueNode, context))
+ return SetBinding(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
+
+ //If it's a property, set it
+ if (CanSet(parent, localName, valueNode, context))
+ return Set(parent, localName, valueNode, iXmlLineInfo, context);
+
+ //If it's a BP, SetValue ()
+ if (CanSetValue(bpRef, attached, valueNode, iXmlLineInfo, context))
+ return SetValue(parent, bpRef, valueNode, iXmlLineInfo, context);
+
+ //If it's an already initialized property, add to it
+ if (CanAdd(parent, propertyName, valueNode, iXmlLineInfo, context))
+ return Add(parent, propertyName, valueNode, iXmlLineInfo, context);
+
+ throw new XamlParseException($"No property, bindable property, or event found for '{localName}', or mismatching type between value and property.", iXmlLineInfo);
+ }
+
+ public static IEnumerable<Instruction> GetPropertyValue(VariableDefinition parent, XmlName propertyName, ILContext context, IXmlLineInfo lineInfo, out TypeReference propertyType)
+ {
+ var module = context.Body.Method.Module;
+ var localName = propertyName.LocalName;
+ bool attached;
+ var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
+
+ //If it's a BP, GetValue ()
+ if (CanGetValue(parent, bpRef, attached, lineInfo, context, out _))
+ return GetValue(parent, bpRef, lineInfo, context, out propertyType);
+
+ //If it's a property, set it
+ if (CanGet(parent, localName, context, out _))
+ return Get(parent, localName, lineInfo, context, out propertyType);
+
+ throw new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
+ }
+
+ static FieldReference GetBindablePropertyReference(VariableDefinition parent, string namespaceURI, ref string localName, out bool attached, ILContext context, IXmlLineInfo iXmlLineInfo)
+ {
+ var module = context.Body.Method.Module;
+ TypeReference declaringTypeReference;
+
+ //If it's an attached BP, update elementType and propertyName
+ var bpOwnerType = parent.VariableType;
+ attached = GetNameAndTypeRef(ref bpOwnerType, namespaceURI, ref localName, context, iXmlLineInfo);
+ var name = $"{localName}Property";
+ FieldReference bpRef = bpOwnerType.GetField(fd => fd.Name == name &&
+ fd.IsStatic &&
+ (fd.IsPublic || fd.IsAssembly), out declaringTypeReference);
+ if (bpRef != null) {
+ bpRef = module.ImportReference(bpRef.ResolveGenericParameters(declaringTypeReference));
+ bpRef.FieldType = module.ImportReference(bpRef.FieldType);
+ }
+ return bpRef;
+ }
+
+ static bool CanConnectEvent(VariableDefinition parent, string localName, bool attached)
+ {
+ return !attached && parent.VariableType.GetEvent(ed => ed.Name == localName, out _) != null;
+ }
+
+ static IEnumerable<Instruction> ConnectEvent(VariableDefinition parent, string localName, INode valueNode, IXmlLineInfo iXmlLineInfo, ILContext context)
+ {
+ var elementType = parent.VariableType;
+ var module = context.Body.Method.Module;
+ TypeReference eventDeclaringTypeRef;
+
+ var eventinfo = elementType.GetEvent(ed => ed.Name == localName, out eventDeclaringTypeRef);
+
+// IL_0007: ldloc.0
+// IL_0008: ldarg.0
+//
+// IL_0009: ldftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
+//OR, if the handler is virtual
+// IL_000x: ldarg.0
+// IL_0009: ldvirtftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
+//
+// IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
+// IL_0014: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Button::add_Clicked(class [mscorlib]System.EventHandler)
+
+ var value = ((ValueNode)valueNode).Value;
+
+ yield return Create(Ldloc, parent);
+ if (context.Root is VariableDefinition)
+ yield return Create(Ldloc, context.Root as VariableDefinition);
+ else if (context.Root is FieldDefinition) {
+ yield return Create(Ldarg_0);
+ yield return Create(Ldfld, context.Root as FieldDefinition);
+ } else
+ throw new InvalidProgramException();
+ var declaringType = context.Body.Method.DeclaringType;
+ while (declaringType.IsNested)
+ declaringType = declaringType.DeclaringType;
+ var handler = declaringType.AllMethods().FirstOrDefault(md => md.Name == value as string);
+ if (handler == null)
+ throw new XamlParseException($"EventHandler \"{value}\" not found in type \"{context.Body.Method.DeclaringType.FullName}\"", iXmlLineInfo);
+
+ //check if the handler signature matches the Invoke signature;
+ var invoke = module.ImportReference(eventinfo.EventType.ResolveCached().GetMethods().First(md => md.Name == "Invoke"));
+ invoke = invoke.ResolveGenericParameters(eventinfo.EventType, module);
+ if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
+ {
+ TypeDefinition realType = eventinfo.EventType.ResolveCached();
+
+ GenericInstanceType genericInstanceType = eventinfo.EventType as GenericInstanceType;
+
+ if (null != genericInstanceType
+ && genericInstanceType.GenericArguments.Count == realType.GenericParameters.Count)
+ {
+ Dictionary<string, TypeReference> dict = new Dictionary<string, TypeReference>();
+
+ for (int i = 0; i < realType.GenericParameters.Count; i++)
+ {
+ string p = realType.GenericParameters[i].Name;
+ TypeReference type = genericInstanceType.GenericArguments[i];
+
+ dict.Add(p, type);
+ }
+
+ if (dict.ContainsKey(invoke.ReturnType.Name))
+ {
+ invoke.ReturnType = dict[invoke.ReturnType.Name];
+ }
+
+ for (int i = 0; i < invoke.Parameters.Count; i++)
+ {
+ if (dict.ContainsKey(invoke.Parameters[i].ParameterType.Name))
+ {
+ invoke.Parameters[i].ParameterType = dict[invoke.Parameters[i].ParameterType.Name];
+ }
+ }
+ }
+ }
+
+ if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
+ throw new XamlParseException($"Signature (return type) of EventHandler \"{context.Body.Method.DeclaringType.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
+ if (invoke.Parameters.Count != handler.Parameters.Count)
+ throw new XamlParseException($"Signature (number of arguments) of EventHandler \"{context.Body.Method.DeclaringType.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
+ if (!invoke.ContainsGenericParameter)
+ for (var i = 0; i < invoke.Parameters.Count;i++)
+ if (!handler.Parameters[i].ParameterType.InheritsFromOrImplements(invoke.Parameters[i].ParameterType))
+ throw new XamlParseException($"Signature (parameter {i}) of EventHandler \"{context.Body.Method.DeclaringType.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
+
+ if (handler.IsVirtual) {
+ yield return Create(Ldarg_0);
+ yield return Create(Ldvirtftn, handler);
+ } else
+ yield return Create(Ldftn, handler);
+
+ //FIXME: eventually get the right ctor instead fo the First() one, just in case another one could exists (not even sure it's possible).
+ var ctor = module.ImportReference(eventinfo.EventType.ResolveCached().GetConstructors().First());
+ ctor = ctor.ResolveGenericParameters(eventinfo.EventType, module);
+ yield return Create(Newobj, module.ImportReference(ctor));
+ //Check if the handler has the same signature as the ctor (it should)
+ var adder = module.ImportReference(eventinfo.AddMethod);
+ adder = adder.ResolveGenericParameters(eventDeclaringTypeRef, module);
+ yield return Create(Callvirt, module.ImportReference(adder));
+ }
+
+ static bool CanSetDynamicResource(FieldReference bpRef, INode valueNode, ILContext context)
+ {
+ if (bpRef == null)
+ return false;
+ var elementNode = valueNode as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ VariableDefinition varValue;
+ if (!context.Variables.TryGetValue(valueNode as IElementNode, out varValue))
+ return false;
+ return varValue.VariableType.FullName == typeof(DynamicResource).FullName;
+ }
+
+ static IEnumerable<Instruction> SetDynamicResource(VariableDefinition parent, FieldReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+
+ yield return Create(Ldloc, parent);
+ yield return Create(Ldsfld, bpRef);
+ yield return Create(Ldloc, context.Variables[elementNode]);
+ yield return Create(Callvirt, module.ImportPropertyGetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "DynamicResource"), propertyName: "Key"));
+ yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "IDynamicResourceHandler"),
+ methodName: "SetDynamicResource",
+ parameterTypes: new[] {
+ (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty"),
+ ("mscorlib", "System", "String"),
+ }));
+ }
+
+ static bool CanSetBinding(FieldReference bpRef, INode valueNode, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+
+ if (bpRef == null)
+ return false;
+ var elementNode = valueNode as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ VariableDefinition varValue;
+ if (!context.Variables.TryGetValue(valueNode as IElementNode, out varValue))
+ return false;
+
+ var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase")), module);
+ if (implicitOperator != null)
+ return true;
+
+ return varValue.VariableType.InheritsFromOrImplements(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase")));
+ }
+
+ static IEnumerable<Instruction> SetBinding(VariableDefinition parent, FieldReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+ var varValue = context.Variables [elementNode];
+ var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase")), module);
+
+ //TODO: check if parent is a BP
+ yield return Create(Ldloc, parent);
+ yield return Create(Ldsfld, bpRef);
+ yield return Create(Ldloc, varValue);
+ if (implicitOperator != null)
+// IL_000f: call !0 class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<BindingBase>::op_Implicit(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<!0>)
+ yield return Create(Call, module.ImportReference(implicitOperator));
+ yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
+ methodName: "SetBinding",
+ parameterTypes: new[] {
+ (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty"),
+ (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase"),
+ }));
+ }
+
+ static bool CanSetValue(FieldReference bpRef, bool attached, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+
+ if (bpRef == null)
+ return false;
+
+ var valueNode = node as ValueNode;
+ if (valueNode != null && valueNode.CanConvertValue(context.Body.Method.Module, bpRef))
+ return true;
+
+ var elementNode = node as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ VariableDefinition varValue;
+ if (!context.Variables.TryGetValue(elementNode, out varValue))
+ return false;
+
+ var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
+ // If it's an attached BP, there's no second chance to handle IMarkupExtensions, so we try here.
+ // Worst case scenario ? InvalidCastException at runtime
+ if (attached && varValue.VariableType.FullName == "System.Object")
+ return true;
+ var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(bpTypeRef, module);
+ if (implicitOperator != null)
+ return true;
+
+ //as we're in the SetValue Scenario, we can accept value types, they'll be boxed
+ if (varValue.VariableType.IsValueType && bpTypeRef.FullName == "System.Object")
+ return true;
+
+ return varValue.VariableType.InheritsFromOrImplements(bpTypeRef);
+ }
+
+ static bool CanGetValue(VariableDefinition parent, FieldReference bpRef, bool attached, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
+ {
+ var module = context.Body.Method.Module;
+ propertyType = null;
+
+ if (bpRef == null)
+ return false;
+
+ if (!parent.VariableType.InheritsFromOrImplements(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"))))
+ return false;
+
+ propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
+ return true;
+ }
+
+ static IEnumerable<Instruction> SetValue(VariableDefinition parent, FieldReference bpRef, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
+ {
+ var valueNode = node as ValueNode;
+ var elementNode = node as IElementNode;
+ var module = context.Body.Method.Module;
+
+// IL_0007: ldloc.0
+// IL_0008: ldsfld class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.BindableProperty [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Label::TextProperty
+// IL_000d: ldstr "foo"
+// IL_0012: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.BindableObject::SetValue(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.BindableProperty, object)
+
+ yield return Create(Ldloc, parent);
+ yield return Create(Ldsfld, bpRef);
+
+ if (valueNode != null) {
+ foreach (var instruction in valueNode.PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context, bpRef:bpRef), true, false))
+ yield return instruction;
+ } else if (elementNode != null) {
+ var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
+ var varDef = context.Variables[elementNode];
+ var varType = varDef.VariableType;
+ var implicitOperator = varDef.VariableType.GetImplicitOperatorTo(bpTypeRef, module);
+ yield return Create(Ldloc, varDef);
+ if (implicitOperator != null) {
+ yield return Create(Call, module.ImportReference(implicitOperator));
+ varType = module.ImportReference(bpTypeRef);
+ }
+ if (varType.IsValueType)
+ yield return Create(Box, varType);
+ }
+ yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
+ methodName: "SetValue",
+ parameterTypes: new[] {
+ (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty"),
+ ("mscorlib", "System", "Object"),
+ }));
+ }
+
+ static IEnumerable<Instruction> GetValue(VariableDefinition parent, FieldReference bpRef, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
+ {
+ var module = context.Body.Method.Module;
+ propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
+
+ return new[] {
+ Create(Ldloc, parent),
+ Create(Ldsfld, bpRef),
+ Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
+ methodName: "GetValue",
+ parameterTypes: new[] { (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty") })),
+ };
+ }
+
+ static bool CanSet(VariableDefinition parent, string localName, INode node, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+ TypeReference declaringTypeReference;
+ var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ if (property == null)
+ return false;
+ var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
+ var propertySetter = property.SetMethod;
+ if (propertySetter == null || !propertySetter.IsPublic || propertySetter.IsStatic)
+ return false;
+
+ var valueNode = node as ValueNode;
+ if (valueNode != null && valueNode.CanConvertValue(context.Body.Method.Module, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached()}))
+ return true;
+
+ var elementNode = node as IElementNode;
+ if (elementNode == null)
+ return false;
+
+ var vardef = context.Variables [elementNode];
+ var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
+
+ if (vardef.VariableType.InheritsFromOrImplements(propertyType))
+ return true;
+ if (implicitOperator != null)
+ return true;
+ if (propertyType.FullName == "System.Object")
+ return true;
+
+ //I'd like to get rid of this condition. This comment used to be //TODO replace latest check by a runtime type check
+ if (vardef.VariableType.FullName == "System.Object")
+ return true;
+
+ return false;
+ }
+
+ static bool CanGet(VariableDefinition parent, string localName, ILContext context, out TypeReference propertyType)
+ {
+ var module = context.Body.Method.Module;
+ propertyType = null;
+ TypeReference declaringTypeReference;
+ var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ if (property == null)
+ return false;
+ var propertyGetter = property.GetMethod;
+ if (propertyGetter == null || !propertyGetter.IsPublic || propertyGetter.IsStatic)
+ return false;
+
+ module.ImportReference(parent.VariableType.ResolveCached());
+ var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertyGetterRef.ImportTypes(module);
+ propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
+
+ return true;
+ }
+
+ static IEnumerable<Instruction> Set(VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+ TypeReference declaringTypeReference;
+ var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ var propertySetter = property.SetMethod;
+
+// IL_0007: ldloc.0
+// IL_0008: ldstr "foo"
+// IL_000d: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Label::set_Text(string)
+
+ module.ImportReference(parent.VariableType.ResolveCached());
+ var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertySetterRef.ImportTypes(module);
+ var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
+ var valueNode = node as ValueNode;
+ var elementNode = node as IElementNode;
+
+ //if it's a value type, load the address so we can invoke methods on it
+ if (parent.VariableType.IsValueType)
+ yield return Instruction.Create(OpCodes.Ldloca, parent);
+ else
+ yield return Instruction.Create(OpCodes.Ldloc, parent);
+
+ if (valueNode != null) {
+ foreach (var instruction in valueNode.PushConvertedValue(context, propertyType, new ICustomAttributeProvider [] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(context, propertyRef:property), false, true))
+ yield return instruction;
+ if (parent.VariableType.IsValueType)
+ yield return Instruction.Create(OpCodes.Call, propertySetterRef);
+ else
+ yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
+ } else if (elementNode != null) {
+ var vardef = context.Variables [elementNode];
+ var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ if (!vardef.VariableType.InheritsFromOrImplements(propertyType) && implicitOperator != null) {
+// IL_000f: call !0 class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<bool>::op_Implicit(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<!0>)
+ yield return Instruction.Create(OpCodes.Call, module.ImportReference(implicitOperator));
+ } else if (!vardef.VariableType.IsValueType && propertyType.IsValueType)
+ yield return Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(propertyType));
+ else if (vardef.VariableType.IsValueType && propertyType.FullName == "System.Object")
+ yield return Instruction.Create(OpCodes.Box, vardef.VariableType);
+ if (parent.VariableType.IsValueType)
+ yield return Instruction.Create(OpCodes.Call, propertySetterRef);
+ else
+ yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
+ }
+ }
+
+ static IEnumerable<Instruction> Get(VariableDefinition parent, string localName, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
+ {
+ var module = context.Body.Method.Module;
+ var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out var declaringTypeReference);
+ var propertyGetter = property.GetMethod;
+
+ module.ImportReference(parent.VariableType.ResolveCached());
+ var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertyGetterRef.ImportTypes(module);
+ propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
+
+ if (parent.VariableType.IsValueType)
+ return new[] {
+ Instruction.Create(OpCodes.Ldloca, parent),
+ Instruction.Create(OpCodes.Call, propertyGetterRef),
+ };
+ else
+ return new[] {
+ Instruction.Create(OpCodes.Ldloc, parent),
+ Instruction.Create(OpCodes.Callvirt, propertyGetterRef),
+ };
+ }
+
+ static bool CanAdd(VariableDefinition parent, XmlName propertyName, INode node, IXmlLineInfo lineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+ var localName = propertyName.LocalName;
+ bool attached;
+ var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
+ TypeReference propertyType;
+
+ if ( !CanGetValue(parent, bpRef, attached, null, context, out propertyType)
+ && !CanGet(parent, localName, context, out propertyType))
+ return false;
+
+ //TODO check md.Parameters[0] type
+ var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
+ if (adderTuple == null)
+ return false;
+
+ return true;
+ }
+
+ static Dictionary<VariableDefinition, IList<string>> resourceNamesInUse = new Dictionary<VariableDefinition, IList<string>>();
+ static bool CanAddToResourceDictionary(VariableDefinition parent, TypeReference collectionType, IElementNode node, IXmlLineInfo lineInfo, ILContext context)
+ {
+ if ( collectionType.FullName != "Tizen.NUI.Binding.ResourceDictionary"
+ && collectionType.ResolveCached().BaseType?.FullName != "Tizen.NUI.Binding.ResourceDictionary")
+ return false;
+
+
+ if (node.Properties.ContainsKey(XmlName.xKey)) {
+ var key = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
+ if (!resourceNamesInUse.TryGetValue(parent, out var names))
+ resourceNamesInUse[parent] = (names = new List<string>());
+ if (names.Contains(key))
+ throw new XamlParseException($"A resource with the key '{key}' is already present in the ResourceDictionary.", lineInfo);
+ names.Add(key);
+ return true;
+ }
+
+ //is there a RD.Add() overrides that accepts this ?
+ var nodeTypeRef = context.Variables[node].VariableType;
+ var module = context.Body.Method.Module;
+ if (module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "ResourceDictionary"),
+ methodName: "Add",
+ parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }) != null)
+ return true;
+
+ throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
+ }
+
+ static IEnumerable<Instruction> Add(VariableDefinition parent, XmlName propertyName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+ var elementNode = node as IElementNode;
+ var vardef = context.Variables [elementNode];
+
+ TypeReference propertyType;
+ foreach (var instruction in GetPropertyValue(parent, propertyName, context, iXmlLineInfo, out propertyType))
+ yield return instruction;
+
+ if (CanAddToResourceDictionary(parent, propertyType, elementNode, iXmlLineInfo, context)) {
+ foreach (var instruction in AddToResourceDictionary(elementNode, iXmlLineInfo, context))
+ yield return instruction;
+ yield break;
+ }
+
+ var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
+ var adderRef = module.ImportReference(adderTuple.Item1);
+ adderRef = module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, module));
+ var childType = GetParameterType(adderRef.Parameters[0]);
+ var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(childType, module);
+
+ yield return Instruction.Create(OpCodes.Ldloc, vardef);
+ if (implicitOperator != null)
+ yield return Instruction.Create(OpCodes.Call, module.ImportReference(implicitOperator));
+ if (implicitOperator == null && vardef.VariableType.IsValueType && !childType.IsValueType)
+ yield return Instruction.Create(OpCodes.Box, vardef.VariableType);
+ yield return Instruction.Create(OpCodes.Callvirt, adderRef);
+ if (adderRef.ReturnType.FullName != "System.Void")
+ yield return Instruction.Create(OpCodes.Pop);
+ }
+
+ static IEnumerable<Instruction> AddToResourceDictionary(IElementNode node, IXmlLineInfo lineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+
+ if (node.Properties.ContainsKey(XmlName.xKey)) {
+// IL_0014: ldstr "key"
+// IL_0019: ldstr "foo"
+// IL_001e: callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.ResourceDictionary::Add(string, object)
+ yield return Create(Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
+ var varDef = context.Variables[node];
+ yield return Create(Ldloc, varDef);
+ if (varDef.VariableType.IsValueType)
+ yield return Create(Box, module.ImportReference(varDef.VariableType));
+ yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "ResourceDictionary"),
+ methodName: "Add",
+ parameterTypes: new[] {
+ ("mscorlib", "System", "String"),
+ ("mscorlib", "System", "Object"),
+ }));
+ yield break;
+ }
+
+ var nodeTypeRef = context.Variables[node].VariableType;
+ yield return Create(Ldloc, context.Variables[node]);
+ yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "ResourceDictionary"),
+ methodName: "Add",
+ parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }));
+ yield break;
+ }
+
+ public static TypeReference GetParameterType(ParameterDefinition param)
+ {
+ if (!param.ParameterType.IsGenericParameter)
+ return param.ParameterType;
+ var type = (param.Method as MethodReference).DeclaringType as GenericInstanceType;
+ return type.GenericArguments [0];
+ }
+
+ static bool GetNameAndTypeRef(ref TypeReference elementType, string namespaceURI, ref string localname,
+ ILContext context, IXmlLineInfo lineInfo)
+ {
+ var dotIdx = localname.IndexOf('.');
+ if (dotIdx > 0)
+ {
+ var typename = localname.Substring(0, dotIdx);
+ localname = localname.Substring(dotIdx + 1);
+ elementType = new XmlType(namespaceURI, typename, null).GetTypeReference(context.Body.Method.Module, lineInfo);
+ return true;
+ }
+ return false;
+ }
+
+ static void SetDataTemplate(IElementNode parentNode, ElementNode node, ILContext parentContext,
+ IXmlLineInfo xmlLineInfo)
+ {
+ var parentVar = parentContext.Variables[parentNode];
+ //Push the DataTemplate to the stack, for setting the template
+ parentContext.IL.Emit(OpCodes.Ldloc, parentVar);
+
+ //Create nested class
+ // .class nested private auto ansi sealed beforefieldinit '<Main>c__AnonStorey0'
+ // extends [mscorlib]System.Object
+
+
+ var module = parentContext.Module;
+ var anonType = new TypeDefinition(
+ null,
+ "_" + parentContext.Body.Method.Name + "_anonXamlCDataTemplate_" + dtcount++,
+ TypeAttributes.BeforeFieldInit |
+ TypeAttributes.Sealed |
+ TypeAttributes.NestedPrivate) {
+ BaseType = module.TypeSystem.Object,
+ CustomAttributes = {
+ new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null)),
+ }
+ };
+
+ parentContext.Body.Method.DeclaringType.NestedTypes.Add(anonType);
+ var ctor = anonType.AddDefaultConstructor();
+
+ var loadTemplate = new MethodDefinition("LoadDataTemplate",
+ MethodAttributes.Assembly | MethodAttributes.HideBySig,
+ module.TypeSystem.Object);
+ loadTemplate.Body.InitLocals = true;
+ anonType.Methods.Add(loadTemplate);
+
+ var parentValues = new FieldDefinition("parentValues", FieldAttributes.Assembly, module.ImportArrayReference(("mscorlib", "System", "Object")));
+ anonType.Fields.Add(parentValues);
+
+ TypeReference rootType = null;
+ var vdefRoot = parentContext.Root as VariableDefinition;
+ if (vdefRoot != null)
+ rootType = vdefRoot.VariableType;
+ var fdefRoot = parentContext.Root as FieldDefinition;
+ if (fdefRoot != null)
+ rootType = fdefRoot.FieldType;
+
+ var root = new FieldDefinition("root", FieldAttributes.Assembly, rootType);
+ anonType.Fields.Add(root);
+
+ //Fill the loadTemplate Body
+ var templateIl = loadTemplate.Body.GetILProcessor();
+ templateIl.Emit(OpCodes.Nop);
+ var templateContext = new ILContext(templateIl, loadTemplate.Body, null, module, parentValues)
+ {
+ Root = root
+ };
+ node.Accept(new CreateObjectVisitor(templateContext), null);
+ node.Accept(new SetNamescopesAndRegisterNamesVisitor(templateContext), null);
+ node.Accept(new SetFieldVisitor(templateContext), null);
+ node.Accept(new SetResourcesVisitor(templateContext), null);
+ node.Accept(new SetPropertiesVisitor(templateContext, stopOnResourceDictionary: true), null);
+
+ templateIl.Emit(OpCodes.Ldloc, templateContext.Variables[node]);
+ templateIl.Emit(OpCodes.Ret);
+
+ //Instanciate nested class
+ var parentIl = parentContext.IL;
+ parentIl.Emit(OpCodes.Newobj, ctor);
+
+ //Copy required local vars
+ parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance
+ parentIl.Append(node.PushParentObjectsArray(parentContext));
+ parentIl.Emit(OpCodes.Stfld, parentValues);
+ parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance
+ if (parentContext.Root is VariableDefinition)
+ parentIl.Emit(OpCodes.Ldloc, parentContext.Root as VariableDefinition);
+ else if (parentContext.Root is FieldDefinition)
+ {
+ parentIl.Emit(OpCodes.Ldarg_0);
+ parentIl.Emit(OpCodes.Ldfld, parentContext.Root as FieldDefinition);
+ }
+ else
+ throw new InvalidProgramException();
+ parentIl.Emit(OpCodes.Stfld, root);
+
+ //SetDataTemplate
+ parentIl.Emit(Ldftn, loadTemplate);
+ parentIl.Emit(Newobj, module.ImportCtorReference(("mscorlib", "System", "Func`1"),
+ classArguments: new[] { ("mscorlib", "System", "Object") },
+ paramCount: 2));
+
+ var setterRef = module.ImportPropertySetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "IDataTemplate"), propertyName: "LoadTemplate");
+ parentContext.IL.Emit(OpCodes.Callvirt, setterRef);
+
+ loadTemplate.Body.Optimize();
+ }
+
+ bool TrySetRuntimeName(XmlName propertyName, VariableDefinition variableDefinition, ValueNode node)
+ {
+ if (propertyName != XmlName.xName)
+ return false;
+
+ var attributes = variableDefinition.VariableType.ResolveCached()
+ .CustomAttributes.Where(attribute => attribute.AttributeType.FullName == "Tizen.NUI.Xaml.RuntimeNamePropertyAttribute").ToList();
+
+ if (!attributes.Any())
+ return false;
+
+ var runTimeName = attributes[0].ConstructorArguments[0].Value as string;
+
+ if (string.IsNullOrEmpty(runTimeName))
+ return false;
+
+ Context.IL.Append(SetPropertyValue(variableDefinition, new XmlName("", runTimeName), node, Context, node));
+ return true;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class SetResourcesVisitor : IXamlNodeVisitor
+ {
+ public SetResourcesVisitor(ILContext context)
+ {
+ Context = context;
+ Module = context.Body.Method.Module;
+ }
+
+ public ILContext Context { get; }
+ ModuleDefinition Module { get; }
+ public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
+ public bool StopOnDataTemplate => true;
+ public bool StopOnResourceDictionary => false;
+ public bool VisitNodeOnDataTemplate => false;
+
+ public void Visit(ValueNode node, INode parentNode)
+ {
+ if (!IsResourceDictionary((IElementNode)parentNode))
+ return;
+
+ node.Accept(new SetPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ }
+
+ public void Visit(MarkupNode node, INode parentNode)
+ {
+ }
+
+
+ public void Visit(ElementNode node, INode parentNode)
+ {
+ XmlName propertyName;
+ //Set ResourcesDictionaries to their parents
+ if (IsResourceDictionary(node) && SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName)) {
+ if ((propertyName.LocalName == "XamlResources" || propertyName.LocalName.EndsWith(".XamlResources", StringComparison.Ordinal))) {
+ Context.IL.Append(SetPropertiesVisitor.SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
+ return;
+ }
+ }
+
+ //Only proceed further if the node is a keyless RD
+ if ( parentNode is IElementNode
+ && IsResourceDictionary((IElementNode)parentNode)
+ && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
+ node.Accept(new SetPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ else if ( parentNode is ListNode
+ && IsResourceDictionary((IElementNode)parentNode.Parent)
+ && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
+ node.Accept(new SetPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
+ }
+
+ public void Visit(RootNode node, INode parentNode)
+ {
+ }
+
+ public void Visit(ListNode node, INode parentNode)
+ {
+ }
+
+ public bool IsResourceDictionary(ElementNode node) => IsResourceDictionary((IElementNode)node);
+
+ bool IsResourceDictionary(IElementNode node)
+ {
+ var parentVar = Context.Variables[(IElementNode)node];
+ return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
+ || parentVar.VariableType.ResolveCached().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
+ }
+
+ public bool SkipChildren(INode node, INode parentNode)
+ {
+ var enode = node as ElementNode;
+ if (enode == null)
+ return false;
+ if ( parentNode is IElementNode
+ && IsResourceDictionary((IElementNode)parentNode)
+ && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
+ return true;
+ if ( parentNode is ListNode
+ && IsResourceDictionary((IElementNode)parentNode.Parent)
+ && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
+ return true;
+ return false;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using MethodAttributes = Mono.Cecil.MethodAttributes;
+using MethodImplAttributes = Mono.Cecil.MethodImplAttributes;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class TypeDefinitionExtensions
+ {
+ public static MethodDefinition AddDefaultConstructor(this TypeDefinition targetType)
+ {
+ var module = targetType.Module;
+ var parentType = module.ImportReference(("mscorlib", "System", "Object"));
+
+ return AddDefaultConstructor(targetType, parentType);
+ }
+
+ public static MethodDefinition AddDefaultConstructor(this TypeDefinition targetType, TypeReference parentType)
+ {
+ var module = targetType.Module;
+ var voidType = module.ImportReference(("mscorlib", "System", "Void"));
+ var methodAttributes = MethodAttributes.Public |
+ MethodAttributes.HideBySig |
+ MethodAttributes.SpecialName |
+ MethodAttributes.RTSpecialName;
+
+ var parentctor = module.ImportCtorReference(parentType, paramCount: 0) ?? module.ImportCtorReference(("mscorlib", "System", "Object"), parameterTypes: null);
+
+ var ctor = new MethodDefinition(".ctor", methodAttributes, voidType)
+ {
+ CallingConvention = MethodCallingConvention.Default,
+ ImplAttributes = (MethodImplAttributes.IL | MethodImplAttributes.Managed)
+ };
+ ctor.Body.InitLocals = true;
+
+ var IL = ctor.Body.GetILProcessor();
+
+ IL.Emit(OpCodes.Ldarg_0);
+ IL.Emit(OpCodes.Call, parentctor);
+ IL.Emit(OpCodes.Ret);
+
+ targetType.Methods.Add(ctor);
+ return ctor;
+ }
+
+ public static IEnumerable<MethodDefinition> AllMethods(this TypeDefinition self)
+ {
+ while (self != null)
+ {
+ foreach (var md in self.Methods)
+ yield return md;
+ self = self.BaseType == null ? null : self.BaseType.ResolveCached();
+ }
+ }
+
+ public static FieldDefinition GetOrCreateField(this TypeDefinition self, string name, Mono.Cecil.FieldAttributes attributes, TypeReference fieldType)
+ {
+ var field = self.Fields.FirstOrDefault(a => a.Name == name);
+
+ if (null == field)
+ {
+ field = new FieldDefinition(name, attributes, fieldType);
+ self.Fields.Add(field);
+ }
+
+ return field;
+ }
+
+ public static MethodDefinition GetOrCreateMethod(this TypeDefinition self, string name, MethodAttributes attributes, Type type)
+ {
+ MethodDefinition method = self.Methods.FirstOrDefault(a => a.Name == name);
+ if (null == method)
+ {
+ method = new MethodDefinition(name, MethodAttributes.Public, self.Module.ImportReference(type));
+ self.Methods.Add(method);
+ }
+
+ return method;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Rocks;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class TypeRefComparer : IEqualityComparer<TypeReference>
+ {
+ static string GetAssembly(TypeReference typeRef)
+ {
+ var md = typeRef.Scope as ModuleDefinition;
+ if (md != null)
+ return md.Assembly.FullName;
+ var anr = typeRef.Scope as AssemblyNameReference;
+ if (anr != null)
+ return anr.FullName;
+ throw new ArgumentOutOfRangeException(nameof(typeRef));
+ }
+
+ public bool Equals(TypeReference x, TypeReference y)
+ {
+ if (x == null)
+ return y == null;
+ if (y == null)
+ return x == null;
+
+ //strip the leading `&` as byref typered fullnames have a `&`
+ var xname = x.FullName.EndsWith("&", StringComparison.InvariantCulture) ? x.FullName.Substring(0, x.FullName.Length - 1) : x.FullName;
+ var yname = y.FullName.EndsWith("&", StringComparison.InvariantCulture) ? y.FullName.Substring(0, y.FullName.Length - 1) : y.FullName;
+ if (xname != yname)
+ return false;
+
+ if ("Tizen.NUI.Binding.BindingBase" == xname)
+ {
+ return true;
+ }
+
+ var xasm = GetAssembly(x);
+ var yasm = GetAssembly(y);
+
+ //standard types comes from either mscorlib. System.Runtime or netstandard. Assume they are equivalent
+ if (( xasm.StartsWith("System.Runtime", StringComparison.Ordinal)
+ || xasm.StartsWith("System", StringComparison.Ordinal)
+ || xasm.StartsWith("mscorlib", StringComparison.Ordinal)
+ || xasm.StartsWith("netstandard", StringComparison.Ordinal)
+ || xasm.StartsWith("System.Xml", StringComparison.Ordinal))
+ && ( yasm.StartsWith("System.Runtime", StringComparison.Ordinal)
+ || yasm.StartsWith("System", StringComparison.Ordinal)
+ || yasm.StartsWith("mscorlib", StringComparison.Ordinal)
+ || yasm.StartsWith("netstandard", StringComparison.Ordinal)
+ || yasm.StartsWith("System.Xml", StringComparison.Ordinal)))
+ return true;
+ return xasm == yasm;
+ }
+
+ public int GetHashCode(TypeReference obj)
+ {
+ return $"{GetAssembly(obj)}//{obj.FullName}".GetHashCode();
+ }
+
+ static TypeRefComparer s_default;
+ public static TypeRefComparer Default => s_default ?? (s_default = new TypeRefComparer());
+ }
+
+ static class TypeReferenceExtensions
+ {
+ public static PropertyDefinition GetProperty(this TypeReference typeRef, Func<PropertyDefinition, bool> predicate,
+ out TypeReference declaringTypeRef)
+ {
+ declaringTypeRef = typeRef;
+ var typeDef = typeRef.ResolveCached();
+ var properties = typeDef.Properties.Where(predicate);
+ if (properties.Any())
+ return properties.Single();
+ if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object")
+ return null;
+ return typeDef.BaseType.ResolveGenericParameters(typeRef).GetProperty(predicate, out declaringTypeRef);
+ }
+
+ public static EventDefinition GetEvent(this TypeReference typeRef, Func<EventDefinition, bool> predicate,
+ out TypeReference declaringTypeRef)
+ {
+ declaringTypeRef = typeRef;
+ var typeDef = typeRef.ResolveCached();
+ var events = typeDef.Events.Where(predicate);
+ if (events.Any()) {
+ var ev = events.Single();
+ return ev.ResolveGenericEvent(declaringTypeRef);
+ }
+ if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object")
+ return null;
+ return typeDef.BaseType.ResolveGenericParameters(typeRef).GetEvent(predicate, out declaringTypeRef);
+ }
+
+ //this resolves generic eventargs (https://bugzilla.xamarin.com/show_bug.cgi?id=57574)
+ static EventDefinition ResolveGenericEvent(this EventDefinition eventDef, TypeReference declaringTypeRef)
+ {
+ if (eventDef == null)
+ throw new ArgumentNullException(nameof(eventDef));
+ if (declaringTypeRef == null)
+ throw new ArgumentNullException(nameof(declaringTypeRef));
+ if (!eventDef.EventType.IsGenericInstance)
+ return eventDef;
+ if (eventDef.EventType.ResolveCached().FullName != "System.EventHandler`1")
+ return eventDef;
+
+ var git = eventDef.EventType as GenericInstanceType;
+ var ga = git.GenericArguments.First();
+ ga = ga.ResolveGenericParameters(declaringTypeRef);
+ git.GenericArguments[0] = ga;
+ eventDef.EventType = git;
+
+ return eventDef;
+
+ }
+ public static FieldDefinition GetField(this TypeReference typeRef, Func<FieldDefinition, bool> predicate,
+ out TypeReference declaringTypeRef)
+ {
+ declaringTypeRef = typeRef;
+ var typeDef = typeRef.ResolveCached();
+ var bp = typeDef.Fields.Where
+ (predicate);
+ if (bp.Any())
+ return bp.Single();
+ if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object")
+ return null;
+ return typeDef.BaseType.ResolveGenericParameters(typeRef).GetField(predicate, out declaringTypeRef);
+ }
+
+ public static bool ImplementsInterface(this TypeReference typeRef, TypeReference @interface)
+ {
+ var typeDef = typeRef.ResolveCached();
+ if (typeDef.Interfaces.Any(tr => tr.InterfaceType.FullName == @interface.FullName))
+ return true;
+ var baseTypeRef = typeDef.BaseType;
+ if (baseTypeRef != null && baseTypeRef.FullName != "System.Object")
+ return baseTypeRef.ImplementsInterface(@interface);
+ return false;
+ }
+
+ public static bool ImplementsGenericInterface(this TypeReference typeRef, string @interface,
+ out GenericInstanceType interfaceReference, out IList<TypeReference> genericArguments)
+ {
+ interfaceReference = null;
+ genericArguments = null;
+ var typeDef = typeRef.ResolveCached();
+ InterfaceImplementation iface;
+ if ((iface = typeDef.Interfaces.FirstOrDefault(tr =>
+ tr.InterfaceType.FullName.StartsWith(@interface, StringComparison.Ordinal) &&
+ tr.InterfaceType.IsGenericInstance && (tr.InterfaceType as GenericInstanceType).HasGenericArguments)) != null)
+ {
+ interfaceReference = iface.InterfaceType as GenericInstanceType;
+ genericArguments = (iface.InterfaceType as GenericInstanceType).GenericArguments;
+ return true;
+ }
+ var baseTypeRef = typeDef.BaseType;
+ if (baseTypeRef != null && baseTypeRef.FullName != "System.Object")
+ return baseTypeRef.ImplementsGenericInterface(@interface, out interfaceReference, out genericArguments);
+ return false;
+ }
+
+ static readonly string[] arrayInterfaces = {
+ "System.ICloneable",
+ "System.Collections.IEnumerable",
+ "System.Collections.IList",
+ "System.Collections.ICollection",
+ "System.Collections.IStructuralComparable",
+ "System.Collections.IStructuralEquatable",
+ };
+
+ static readonly string[] arrayGenericInterfaces = {
+ "System.Collections.Generic.IEnumerable`1",
+ "System.Collections.Generic.IList`1",
+ "System.Collections.Generic.ICollection`1",
+ "System.Collections.Generic.IReadOnlyCollection`1",
+ "System.Collections.Generic.IReadOnlyList`1",
+ };
+
+ public static bool IsInterface(this TypeReference typeRef, string interfaceTypeName)
+ {
+ if (null == typeRef)
+ {
+ return false;
+ }
+ else
+ {
+ var typeDef = typeRef.ResolveCached();
+
+ if (null == typeDef)
+ {
+ return false;
+ }
+ else
+ {
+ foreach (var @interface in typeDef.Interfaces)
+ {
+ if (InheritsFromOrImplements(@interface.InterfaceType, interfaceTypeName)
+ ||
+ InheritsFromOrImplements(@interface.InterfaceType.Resolve(), interfaceTypeName))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+
+ public static bool IsInterface(this TypeReference typeRef, Type interfaceType)
+ {
+ return IsInterface(typeRef, interfaceType.FullName);
+ }
+
+ public static bool InheritsFromOrImplements(this TypeReference typeRef, string typeFullName)
+ {
+ if (null == typeRef)
+ {
+ return false;
+ }
+ else if (typeRef.FullName == typeFullName)
+ {
+ return true;
+ }
+ else
+ {
+ var typeDef = typeRef.ResolveCached();
+
+ if (null == typeDef)
+ {
+ return false;
+ }
+ else
+ {
+ return InheritsFromOrImplements(typeDef.BaseType, typeFullName);
+ }
+ }
+ }
+
+ public static bool InheritsFromOrImplements(this TypeReference typeRef, TypeReference baseClass)
+ {
+ if (TypeRefComparer.Default.Equals(typeRef, baseClass))
+ return true;
+
+ if (typeRef.IsValueType)
+ return false;
+
+ if (typeRef.IsArray) {
+ var array = (ArrayType)typeRef;
+ var arrayType = typeRef.ResolveCached();
+ if (arrayInterfaces.Contains(baseClass.FullName))
+ return true;
+ if (array.IsVector && //generic interfaces are not implemented on multidimensional arrays
+ arrayGenericInterfaces.Contains(baseClass.ResolveCached().FullName) &&
+ baseClass.IsGenericInstance &&
+ TypeRefComparer.Default.Equals((baseClass as GenericInstanceType).GenericArguments[0], arrayType))
+ return true;
+ return baseClass.FullName == "System.Object";
+ }
+
+ if (typeRef.FullName == "System.Object")
+ return false;
+ var typeDef = typeRef.ResolveCached();
+ if (TypeRefComparer.Default.Equals(typeDef, baseClass.ResolveCached()))
+ return true;
+ if (typeDef.Interfaces.Any(ir => TypeRefComparer.Default.Equals(ir.InterfaceType.ResolveGenericParameters(typeRef), baseClass)))
+ return true;
+ if (typeDef.BaseType == null)
+ return false;
+
+ typeRef = typeDef.BaseType.ResolveGenericParameters(typeRef);
+ return typeRef.InheritsFromOrImplements(baseClass);
+ }
+
+ static CustomAttribute GetCustomAttribute(this TypeReference typeRef, TypeReference attribute)
+ {
+ var typeDef = typeRef.ResolveCached();
+ //FIXME: avoid string comparison. make sure the attribute TypeRef is the same one
+ var attr = typeDef.CustomAttributes.SingleOrDefault(ca => ca.AttributeType.FullName == attribute.FullName);
+ if (attr != null)
+ return attr;
+ var baseTypeRef = typeDef.BaseType;
+ if (baseTypeRef != null && baseTypeRef.FullName != "System.Object")
+ return baseTypeRef.GetCustomAttribute(attribute);
+ return null;
+ }
+
+ public static CustomAttribute GetCustomAttribute(this TypeReference typeRef, ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) attributeType)
+ {
+ return typeRef.GetCustomAttribute(module.ImportReference(attributeType));
+ }
+
+ [Obsolete]
+ public static MethodDefinition GetMethod(this TypeReference typeRef, Func<MethodDefinition, bool> predicate)
+ {
+ TypeReference declaringTypeReference;
+ return typeRef.GetMethod(predicate, out declaringTypeReference);
+ }
+
+ [Obsolete]
+ public static MethodDefinition GetMethod(this TypeReference typeRef, Func<MethodDefinition, bool> predicate,
+ out TypeReference declaringTypeRef)
+ {
+ declaringTypeRef = typeRef;
+ var typeDef = typeRef.ResolveCached();
+ var methods = typeDef.Methods.Where(predicate);
+ if (methods.Any())
+ return methods.Single();
+ if (typeDef.BaseType != null && typeDef.BaseType.FullName == "System.Object")
+ return null;
+ if (typeDef.IsInterface)
+ {
+ foreach (var face in typeDef.Interfaces)
+ {
+ var m = face.InterfaceType.GetMethod(predicate);
+ if (m != null)
+ return m;
+ }
+ return null;
+ }
+ return typeDef.BaseType.GetMethod(predicate, out declaringTypeRef);
+ }
+
+ public static IEnumerable<Tuple<MethodDefinition, TypeReference>> GetMethods(this TypeReference typeRef,
+ Func<MethodDefinition, bool> predicate, ModuleDefinition module)
+ {
+ return typeRef.GetMethods((md, tr) => predicate(md), module);
+ }
+
+ public static IEnumerable<Tuple<MethodDefinition, TypeReference>> GetMethods(this TypeReference typeRef,
+ Func<MethodDefinition, TypeReference, bool> predicate, ModuleDefinition module)
+ {
+ var typeDef = typeRef.ResolveCached();
+ foreach (var method in typeDef.Methods.Where(md => predicate(md, typeRef)))
+ yield return new Tuple<MethodDefinition, TypeReference>(method, typeRef);
+ if (typeDef.IsInterface)
+ {
+ foreach (var face in typeDef.Interfaces)
+ {
+ if (face.InterfaceType.IsGenericInstance && typeRef is GenericInstanceType)
+ {
+ int i = 0;
+ foreach (var arg in ((GenericInstanceType)typeRef).GenericArguments)
+ ((GenericInstanceType)face.InterfaceType).GenericArguments[i++] = module.ImportReference(arg);
+ }
+ foreach (var tuple in face.InterfaceType.GetMethods(predicate, module))
+ yield return tuple;
+ }
+ yield break;
+ }
+ if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object")
+ yield break;
+ var baseType = typeDef.BaseType.ResolveGenericParameters(typeRef);
+ foreach (var tuple in baseType.GetMethods(predicate, module))
+ yield return tuple;
+ }
+
+ public static MethodReference GetImplicitOperatorTo(this TypeReference fromType, TypeReference toType, ModuleDefinition module)
+ {
+ if (TypeRefComparer.Default.Equals(fromType, toType))
+ return null;
+
+ var implicitOperatorsOnFromType = fromType.GetMethods(md => md.IsPublic
+ && md.IsStatic
+ && md.IsSpecialName
+ && md.Name == "op_Implicit", module);
+ var implicitOperatorsOnToType = toType.GetMethods(md => md.IsPublic
+ && md.IsStatic
+ && md.IsSpecialName
+ && md.Name == "op_Implicit", module);
+
+ var implicitOperators = implicitOperatorsOnFromType.Concat(implicitOperatorsOnToType).ToList();
+
+ if (implicitOperators.Any()) {
+ foreach (var op in implicitOperators) {
+ var cast = op.Item1;
+ var opDeclTypeRef = op.Item2;
+ var castDef = module.ImportReference(cast).ResolveGenericParameters(opDeclTypeRef, module);
+ var returnType = castDef.ReturnType;
+ if (returnType.IsGenericParameter)
+ returnType = ((GenericInstanceType)opDeclTypeRef).GenericArguments [((GenericParameter)returnType).Position];
+ if (!returnType.InheritsFromOrImplements(toType))
+ continue;
+ var paramType = cast.Parameters[0].ParameterType;
+ if (!fromType.InheritsFromOrImplements(paramType))
+ continue;
+ return castDef;
+ }
+ }
+ return null;
+ }
+
+ public static TypeReference ResolveGenericParameters(this TypeReference self, TypeReference declaringTypeReference)
+ {
+ var genericself = self as GenericInstanceType;
+ if (genericself == null)
+ return self;
+
+ var genericdeclType = declaringTypeReference as GenericInstanceType;
+ if (genericdeclType == null)
+ return self;
+
+ if (!genericself.GenericArguments.Any(arg => arg.IsGenericParameter))
+ return self;
+
+ List<TypeReference> args = new List<TypeReference>();
+ for (var i = 0; i < genericself.GenericArguments.Count; i++) {
+ if (!genericself.GenericArguments[i].IsGenericParameter)
+ args.Add(genericself.GenericArguments[i]);
+ else
+ args.Add(genericdeclType.GenericArguments[(genericself.GenericArguments[i] as GenericParameter).Position]);
+ }
+ return self.GetElementType().MakeGenericInstanceType(args.ToArray());
+ }
+
+ static Dictionary<TypeReference, TypeDefinition> resolves = new Dictionary<TypeReference, TypeDefinition>();
+ public static TypeDefinition ResolveCached(this TypeReference typeReference)
+ {
+ if (resolves.TryGetValue(typeReference, out var typeDefinition))
+ return typeDefinition;
+ return (resolves[typeReference] = typeReference.Resolve());
+ }
+ }
+}
--- /dev/null
+using Mono.Cecil.Cil;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class VariableDefinitionReference
+ {
+ public VariableDefinitionReference(VariableDefinition vardef)
+ {
+ VariableDefinition = vardef;
+ }
+
+ public VariableDefinition VariableDefinition { get; set; }
+
+ public static implicit operator VariableDefinition(VariableDefinitionReference vardefref)
+ {
+ return vardefref.VariableDefinition;
+ }
+ }
+}
--- /dev/null
+using System;
+using Mono.Cecil;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class XamlCAssemblyResolver : DefaultAssemblyResolver
+ {
+ public void AddAssembly(string p)
+ {
+ RegisterAssembly(AssemblyDefinition.ReadAssembly(p, new ReaderParameters
+ {
+ AssemblyResolver = this
+ }));
+ }
+
+ public override AssemblyDefinition Resolve(AssemblyNameReference name)
+ {
+ if (TryResolve(name, out AssemblyDefinition assembly))
+ return assembly;
+ if ( IsMscorlib(name)
+ && ( TryResolve(AssemblyNameReference.Parse("mscorlib"), out assembly)
+ || TryResolve(AssemblyNameReference.Parse("netstandard"), out assembly)
+ || TryResolve(AssemblyNameReference.Parse("System.Runtime"), out assembly)))
+ return assembly;
+ throw new AssemblyResolutionException(name);
+ }
+
+ bool TryResolve(AssemblyNameReference assemblyNameReference, out AssemblyDefinition assembly)
+ {
+ try {
+ assembly = base.Resolve(assemblyNameReference);
+ return true;
+ }
+ catch (AssemblyResolutionException e) {
+ assembly = null;
+ return false;
+ }
+ }
+
+ static bool IsMscorlib(AssemblyNameReference name)
+ {
+ return name.Name == "mscorlib"
+ || name.Name == "System.Runtime"
+ || name.Name == "netstandard";
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml;
+using System.ComponentModel;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Tizen.NUI.Binding;
+using Tizen.NUI.EXaml;
+using Tizen.NUI.EXaml.Build.Tasks;
+using static Microsoft.Build.Framework.MessageImportance;
+using static Mono.Cecil.Cil.OpCodes;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class XamlCTask : XamlTask
+ {
+ bool hasCompiledXamlResources;
+ public bool KeepXamlResources { get; set; }
+ public bool OptimizeIL { get; set; }
+
+ [Obsolete("OutputGeneratedILAsCode is obsolete as of version 2.3.4. This option is no longer available.")]
+ public bool OutputGeneratedILAsCode { get; set; }
+
+ public bool CompileByDefault { get; set; }
+ public bool ForceCompile { get; set; }
+
+ public bool UseInjection { get; set; }
+
+ public IAssemblyResolver DefaultAssemblyResolver { get; set; }
+
+ public string Type { get; set; }
+ public MethodDefinition InitCompForType { get; private set; }
+ internal bool ReadOnly { get; set; }
+
+ public string outputRootPath { get; set; }
+
+ public bool PrintReferenceAssemblies { get; set; }
+
+ private void PrintParam(string logFileName, string log)
+ {
+ FileStream stream = null;
+ if (false == File.Exists(logFileName))
+ {
+ stream = File.Create(logFileName);
+ }
+ else
+ {
+ stream = File.Open(logFileName, FileMode.Append);
+ }
+
+ byte[] buffer = System.Text.Encoding.Default.GetBytes(log + "\n");
+ stream.Write(buffer, 0, buffer.Length);
+ stream.Close();
+ }
+
+ private void PrintParam(string logFileName)
+ {
+ FileStream stream = File.Create(logFileName);
+
+ string str = "Assembly is " + Assembly + "\n";
+ str += "DependencyPaths is " + DependencyPaths + "\n";
+ str += "ReferencePath is " + ReferencePath + "\n";
+ str += "DebugType is " + DebugType + "\n";
+ str += "Type is " + Type + "\n";
+ str += "ReadOnly is " + ReadOnly + "\n";
+
+ byte[] buffer = Encoding.Default.GetBytes(str);
+ stream.Write(buffer, 0, buffer.Length);
+
+ stream.Close();
+ }
+
+ static private TypeDefinition baseTypeDefiniation = null;
+ static public TypeDefinition BaseTypeDefiniation
+ {
+ get
+ {
+ return baseTypeDefiniation;
+ }
+ }
+
+ private void GatherAssemblyInfo(string p)
+ {
+ try
+ {
+ ModuleDefinition module = ModuleDefinition.ReadModule(p);
+
+ if (null == baseTypeDefiniation)
+ {
+ baseTypeDefiniation = module.GetType("Tizen.NUI.Binding.BindableObject");
+ }
+
+ foreach (var attr in module.Assembly.CustomAttributes)
+ {
+ if (attr.AttributeType.FullName == "Tizen.NUI.XmlnsDefinitionAttribute")
+ {
+ string xmlNamespace = attr.ConstructorArguments[0].Value as string;
+ string clrNamespace = attr.ConstructorArguments[1].Value as string;
+
+ int level = 0;
+ string assemblyName = module.Assembly.FullName;
+
+ if (true == attr.HasProperties)
+ {
+ foreach (var property in attr.Properties)
+ {
+ if ("Level" == property.Name)
+ {
+ level = int.Parse(property.Argument.Value.ToString());
+ }
+ if ("AssemblyName" == property.Name)
+ {
+ assemblyName = property.Argument.Value as string;
+ }
+ }
+ }
+
+ XmlnsDefinitionAttribute attribute = new XmlnsDefinitionAttribute(xmlNamespace, clrNamespace, level);
+ attribute.AssemblyName = assemblyName;
+ s_xmlnsDefinitions.Add(attribute);
+ }
+ }
+
+ module.Dispose();
+ }
+ catch (Exception e)
+ {
+ int temp = 0;
+ }
+ }
+
+ public override bool Execute(out IList<Exception> thrownExceptions)
+ {
+ if (true == PrintReferenceAssemblies)
+ {
+ PrintParam(@"XamlC_Log.txt", "ReferencePath is " + ReferencePath);
+ }
+
+ LoggingHelper.LogWarning("Assembly is " + Assembly);
+
+ thrownExceptions = null;
+
+ LoggingHelper.LogMessage(Normal, $"{new string(' ', 0)}Compiling Xaml, assembly: {Assembly}");
+ var skipassembly = !CompileByDefault;
+ bool success = true;
+
+ if (!File.Exists(Assembly))
+ {
+ throw new Exception(String.Format("Assembly file {0} is not exist", Assembly));
+ //LoggingHelper.LogMessage(Normal, $"{new string(' ', 2)}Assembly file not found. Skipping XamlC.");
+ //return true;
+ }
+
+ s_xmlnsDefinitions.Clear();
+
+ var resolver = DefaultAssemblyResolver ?? new XamlCAssemblyResolver();
+ if (resolver is XamlCAssemblyResolver xamlCResolver)
+ {
+ if (!string.IsNullOrEmpty(DependencyPaths))
+ {
+ foreach (var dep in DependencyPaths.Split(';'))
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {dep}");
+ xamlCResolver.AddSearchDirectory(dep);
+ }
+ }
+
+ if (!string.IsNullOrEmpty(ReferencePath))
+ {
+ var paths = ReferencePath.Replace("//", "/").Split(';');
+
+ foreach (var p in paths)
+ {
+ GatherAssemblyInfo(p);
+
+ var searchpath = System.IO.Path.GetDirectoryName(p);
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Adding searchpath {searchpath}");
+ xamlCResolver.AddSearchDirectory(searchpath);
+ }
+ }
+ }
+ else
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Ignoring dependency and reference paths due to an unsupported resolver");
+
+ var debug = DebugSymbols || (!string.IsNullOrEmpty(DebugType) && DebugType.ToLowerInvariant() != "none");
+
+ var readerParameters = new ReaderParameters
+ {
+ AssemblyResolver = resolver,
+ ReadWrite = !ReadOnly,
+ ReadSymbols = debug,
+ };
+
+ using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(System.IO.Path.GetFullPath(Assembly), readerParameters))
+ {
+ if (null != XamlFilePath)
+ {
+ return GenerateEXaml(XamlFilePath, assemblyDefinition.MainModule, out thrownExceptions);
+ }
+
+ CustomAttribute xamlcAttr;
+ if (assemblyDefinition.HasCustomAttributes &&
+ (xamlcAttr =
+ assemblyDefinition.CustomAttributes.FirstOrDefault(
+ ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlCompilationAttribute")) != null)
+ {
+ var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
+ if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
+ skipassembly = true;
+ if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
+ skipassembly = false;
+ }
+
+ foreach (var module in assemblyDefinition.Modules)
+ {
+ var skipmodule = skipassembly;
+ if (module.HasCustomAttributes &&
+ (xamlcAttr =
+ module.CustomAttributes.FirstOrDefault(
+ ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlCompilationAttribute")) != null)
+ {
+ var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
+ if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
+ skipmodule = true;
+ if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
+ skipmodule = false;
+ }
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}Module: {module.Name}");
+ var resourcesToPrune = new List<EmbeddedResource>();
+ foreach (var resource in module.Resources.OfType<EmbeddedResource>())
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Resource: {resource.Name}");
+ string classname;
+ if (!resource.IsXaml(module, out classname))
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}skipped.");
+ continue;
+ }
+ TypeDefinition typeDef = module.GetType(classname);
+ if (typeDef == null)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no type found... skipped.");
+ continue;
+ }
+ var skiptype = skipmodule;
+ if (typeDef.HasCustomAttributes &&
+ (xamlcAttr =
+ typeDef.CustomAttributes.FirstOrDefault(
+ ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlCompilationAttribute")) != null)
+ {
+ var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value;
+ if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip)
+ skiptype = true;
+ if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile)
+ skiptype = false;
+ }
+
+ if (Type != null)
+ skiptype = !(Type == classname);
+
+ if (skiptype && !ForceCompile)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}has XamlCompilationAttribute set to Skip and not Compile... skipped.");
+ continue;
+ }
+
+ bool currentRetOfType;
+ IList<Exception> currentExceptionsOfType;
+
+ if (UseInjection)
+ {
+ currentRetOfType = DoInjection(typeDef, resource, out currentExceptionsOfType);
+ }
+ else
+ {
+ currentRetOfType = GenerateEXaml(typeDef, resource, out currentExceptionsOfType);
+
+ if (currentRetOfType)
+ {
+ InjectionMethodGetEXamlPath(typeDef);
+ }
+ }
+
+ if (null != currentExceptionsOfType)
+ {
+ if (null == thrownExceptions)
+ {
+ thrownExceptions = new List<Exception>();
+ }
+
+ foreach (var e in currentExceptionsOfType)
+ {
+ thrownExceptions.Add(e);
+ }
+ }
+
+ if (false == currentRetOfType)
+ {
+ success = false;
+ continue;
+ }
+
+ resourcesToPrune.Add(resource);
+ }
+
+ if (hasCompiledXamlResources)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Changing the module MVID");
+ module.Mvid = Guid.NewGuid();
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}done.");
+ }
+ if (!KeepXamlResources)
+ {
+ if (resourcesToPrune.Any())
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 4)}Removing compiled xaml resources");
+ foreach (var resource in resourcesToPrune)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Removing {resource.Name}");
+ module.Resources.Remove(resource);
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+ }
+ }
+ }
+
+ if (!hasCompiledXamlResources)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}No compiled resources. Skipping writing assembly.");
+ return success;
+ }
+
+ if (ReadOnly)
+ return success;
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 0)}Writing the assembly");
+ try
+ {
+ assemblyDefinition.Write(new WriterParameters
+ {
+ WriteSymbols = debug,
+ });
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}done.");
+ }
+ catch (Exception e)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 2)}failed.");
+ LoggingHelper.LogErrorFromException(e);
+ (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
+ LoggingHelper.LogMessage(Low, e.StackTrace);
+ success = false;
+ }
+ }
+ return success;
+ }
+
+ bool DoInjection(TypeDefinition typeDef, EmbeddedResource resource, out IList<Exception> thrownExceptions)
+ {
+ thrownExceptions = null;
+
+ var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent");
+ if (initComp == null)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no InitializeComponent found... skipped.");
+ return false;
+ }
+
+ CustomAttribute xamlFilePathAttr;
+ var xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlFilePathAttribute")) != null ?
+ (string)xamlFilePathAttr.ConstructorArguments[0].Value :
+ resource.Name;
+
+ var initCompRuntime = typeDef.Methods.FirstOrDefault(md => md.Name == "__InitComponentRuntime");
+ if (initCompRuntime != null)
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}__InitComponentRuntime already exists... not creating");
+ else
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Creating empty {typeDef.Name}.__InitComponentRuntime");
+ initCompRuntime = new MethodDefinition("__InitComponentRuntime", initComp.Attributes, initComp.ReturnType);
+ initCompRuntime.Body.InitLocals = true;
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Copying body of InitializeComponent to __InitComponentRuntime");
+ initCompRuntime.Body = new MethodBody(initCompRuntime);
+ var iCRIl = initCompRuntime.Body.GetILProcessor();
+ foreach (var instr in initComp.Body.Instructions)
+ iCRIl.Append(instr);
+ initComp.Body.Instructions.Clear();
+ initComp.Body.GetILProcessor().Emit(OpCodes.Ret);
+ initComp.Body.InitLocals = true;
+
+ typeDef.Methods.Add(initCompRuntime);
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+ }
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
+ var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
+ if (rootnode == null)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
+ return false;
+ }
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+
+ hasCompiledXamlResources = true;
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
+ Exception e;
+ if (!TryCoreCompile(initComp, rootnode, out e))
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
+ (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
+ if (e is XamlParseException xpe)
+ LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
+ else if (e is XmlException xe)
+ LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
+ else
+ LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
+
+ if (null != e.StackTrace)
+ {
+ LoggingHelper.LogMessage(Low, e.StackTrace);
+ }
+
+ return false;
+ }
+ if (Type != null)
+ InitCompForType = initComp;
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+
+ if (OptimizeIL)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Optimizing IL");
+ initComp.Body.Optimize();
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+ }
+
+#pragma warning disable 0618
+ if (OutputGeneratedILAsCode)
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Decompiling option has been removed. Use a 3rd party decompiler to admire the beauty of the IL generated");
+#pragma warning restore 0618
+
+ return true;
+ }
+
+ bool GenerateEXaml(TypeDefinition typeDef, EmbeddedResource resource, out IList<Exception> thrownExceptions)
+ {
+ thrownExceptions = null;
+
+ ModuleDefinition module = typeDef.Module;
+
+ CustomAttribute xamlFilePathAttr;
+ var xamlFilePath = typeDef.HasCustomAttributes && (xamlFilePathAttr = typeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "Tizen.NUI.Xaml.XamlFilePathAttribute")) != null ?
+ (string)xamlFilePathAttr.ConstructorArguments[0].Value :
+ resource.Name;
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
+ var rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
+ if (rootnode == null)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
+ return false;
+ }
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+
+ hasCompiledXamlResources = true;
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
+ Exception e;
+
+ var visitorContext = new EXamlContext(typeDef, typeDef.Module);
+
+ if (!TryCoreCompile(rootnode, visitorContext, out e))
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
+ (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
+ if (e is XamlParseException xpe)
+ LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
+ else if (e is XmlException xe)
+ LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
+ else
+ LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
+
+ if (null != e.StackTrace)
+ {
+ LoggingHelper.LogMessage(Low, e.StackTrace);
+ }
+
+ return false;
+ }
+ else
+ {
+ var examlDir = outputRootPath + @"res/examl/";
+ if (Directory.Exists(examlDir))
+ {
+ Directory.CreateDirectory(examlDir);
+ }
+
+ var examlFilePath = examlDir + typeDef.FullName + ".examl";
+
+ EXamlOperation.WriteOpertions(examlFilePath, visitorContext);
+ }
+
+ return true;
+ }
+
+ bool GenerateEXaml(string xamlFilePath, ModuleDefinition module, out IList<Exception> thrownExceptions)
+ {
+ thrownExceptions = null;
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Parsing Xaml");
+ Stream xamlStream = File.Open(xamlFilePath, FileMode.Open);
+
+ string className;
+ if (!CecilExtensions.IsXaml(xamlStream, module, out className))
+ {
+ thrownExceptions.Add(new Exception($"{xamlFilePath} is not xaml format file"));
+ }
+
+ xamlStream.Seek(0, SeekOrigin.Begin);
+ var typeDef = module.GetTypeDefinition(className);
+
+ if (null == typeDef)
+ {
+ throw new Exception($"Can't find type \"{className}\" in assembly \"{module.Assembly.FullName}\"");
+ }
+
+ var rootnode = ParseXaml(xamlStream, typeDef);
+
+ xamlStream.Close();
+
+ if (rootnode == null)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
+ return false;
+ }
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}done.");
+
+ hasCompiledXamlResources = true;
+
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}Replacing {0}.InitializeComponent ()");
+ Exception e;
+
+ var visitorContext = new EXamlContext(typeDef, module);
+
+ if (!TryCoreCompile(rootnode, visitorContext, out e))
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
+ (thrownExceptions = thrownExceptions ?? new List<Exception>()).Add(e);
+ if (e is XamlParseException xpe)
+ LoggingHelper.LogError(null, null, null, xamlFilePath, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source);
+ else if (e is XmlException xe)
+ LoggingHelper.LogError(null, null, null, xamlFilePath, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source);
+ else
+ LoggingHelper.LogError(null, null, null, xamlFilePath, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source);
+
+ if (null != e.StackTrace)
+ {
+ LoggingHelper.LogMessage(Low, e.StackTrace);
+ }
+
+ return false;
+ }
+ else
+ {
+ var examlDir = outputRootPath + @"res/examl/";
+ if (Directory.Exists(examlDir))
+ {
+ Directory.CreateDirectory(examlDir);
+ }
+
+ var examlFilePath = examlDir + typeDef.FullName + ".examl";
+
+ EXamlOperation.WriteOpertions(examlFilePath, visitorContext);
+ }
+
+ return true;
+ }
+
+
+ bool InjectionMethodGetEXamlPath(TypeDefinition typeDef)
+ {
+ var getEXamlPathComp = typeDef.Methods.FirstOrDefault(md => md.Name == "GetEXamlPath");
+ if (getEXamlPathComp == null)
+ {
+ LoggingHelper.LogMessage(Low, $"{new string(' ', 6)}no GetEXamlPath found... skipped.");
+ return false;
+ }
+
+ var examlRelativePath = @"examl/" + typeDef.FullName + ".examl";
+ getEXamlPathComp.Body.Instructions.Clear();
+ getEXamlPathComp.Body.GetILProcessor().Emit(OpCodes.Ldstr, examlRelativePath);
+ getEXamlPathComp.Body.GetILProcessor().Emit(OpCodes.Ret);
+
+ return true;
+ }
+
+ bool TryCoreCompile(MethodDefinition initComp, ILRootNode rootnode, out Exception exception)
+ {
+ try
+ {
+ var body = new MethodBody(initComp);
+ var module = body.Method.Module;
+ var type = initComp.DeclaringType;
+
+ MethodDefinition constructorOfRemoveEventsType;
+ TypeDefinition typeOfRemoveEvents = CreateTypeForRemoveEvents(type, out constructorOfRemoveEventsType);
+
+ var field = type.GetOrCreateField("___Info_Of_RemoveEvent___", FieldAttributes.Private, typeOfRemoveEvents);
+
+ body.InitLocals = true;
+ var il = body.GetILProcessor();
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Newobj, constructorOfRemoveEventsType);
+ il.Emit(OpCodes.Stfld, field);
+
+ var resourcePath = GetPathForType(module, type);
+
+ il.Emit(Nop);
+
+ List<Instruction> insOfAddEvent = new List<Instruction>();
+
+ var visitorContext = new ILContext(il, body, insOfAddEvent, module);
+
+ rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
+ rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null);
+ rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
+ rootnode.Accept(new CreateObjectVisitor(visitorContext), null);
+
+ Set(visitorContext, visitorContext.Variables[rootnode], "IsCreateByXaml", new ValueNode("true", rootnode.NamespaceResolver), null);
+
+ rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null);
+ rootnode.Accept(new SetFieldVisitor(visitorContext), null);
+ rootnode.Accept(new SetResourcesVisitor(visitorContext), null);
+ rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null);
+
+ AddInsOfRemoveEvent(il, visitorContext.InsOfAddEvent, typeOfRemoveEvents);
+
+ il.Emit(Ret);
+ initComp.Body = body;
+ exception = null;
+ return true;
+ }
+ catch (Exception e)
+ {
+ XamlParseException xamlParseException = e as XamlParseException;
+ if (null != xamlParseException)
+ {
+ XamlParseException ret = new XamlParseException(xamlParseException.Message + "\n" + ReferencePath, xamlParseException.XmlInfo, xamlParseException.InnerException);
+ exception = ret;
+ }
+ else
+ {
+ exception = e;
+ }
+
+ return false;
+ }
+ }
+
+ private void AddInsOfRemoveEvent(ILProcessor ilOfInit, List<Instruction> instructions, TypeDefinition typeDef)
+ {
+ MethodDefinition methodCall = typeDef.GetOrCreateMethod("Call", MethodAttributes.Public, typeof(void));
+ methodCall.Body.Instructions.Clear();
+
+ var fieldOfRemoveEvent = typeDef.DeclaringType.Fields.FirstOrDefault(a => a.Name == "___Info_Of_RemoveEvent___");
+
+ var il = methodCall.Body.GetILProcessor();
+
+ foreach (var ins in instructions)
+ {
+ if (ins.OpCode == OpCodes.Ldloc
+ &&
+ ins.Operand is VariableDefinition variable)
+ {
+ var fieldName = "field" + variable.Index;
+ var field = typeDef.GetOrCreateField(fieldName, FieldAttributes.Public, variable.VariableType);
+
+ ilOfInit.Emit(OpCodes.Ldarg_0);
+ ilOfInit.Emit(OpCodes.Ldfld, fieldOfRemoveEvent);
+ ilOfInit.Emit(OpCodes.Ldloc, variable);
+ ilOfInit.Emit(OpCodes.Stfld, field);
+
+ methodCall.Body.Instructions.Add(Instruction.Create(Ldarg_0));
+ methodCall.Body.Instructions.Add(Instruction.Create(Ldfld, field));
+ }
+ else
+ {
+ bool isReplaced = false;
+ if (ins.OpCode == OpCodes.Callvirt && ins.Operand is MethodReference method)
+ {
+ if (method.Name.StartsWith("add_"))
+ {
+ var eventName = method.Name.Substring("add_".Length);
+ TypeReference _;
+ var typeOfEvent = method.DeclaringType.GetEvent(a => a.Name == eventName, out _);
+
+ if (typeOfEvent is EventDefinition)
+ {
+ var methodOfRemoveEvent = typeDef.Module.ImportReference(method.DeclaringType.ResolveCached()?.Methods.FirstOrDefault(a => a.Name == "remove_" + eventName));
+ if (null != methodOfRemoveEvent)
+ {
+ var newIns = Instruction.Create(ins.OpCode, methodOfRemoveEvent);
+ methodCall.Body.Instructions.Add(newIns);
+
+ isReplaced = true;
+ }
+ }
+ }
+ }
+
+ if (false == isReplaced)
+ {
+ methodCall.Body.Instructions.Add(ins);
+ }
+ }
+ }
+
+ methodCall.Body.Instructions.Add(Instruction.Create(Ret));
+
+ var removeEventMethod = typeDef.DeclaringType.Methods.FirstOrDefault(a => a.Name == "RemoveEventsInXaml");
+ if (null != removeEventMethod)
+ {
+ removeEventMethod.Body.Instructions.Clear();
+ var ilRemoveEvent = removeEventMethod.Body.GetILProcessor();
+
+ ilRemoveEvent.Emit(Ldarg_0);
+ ilRemoveEvent.Emit(Ldfld, fieldOfRemoveEvent);
+ ilRemoveEvent.Emit(Dup);
+
+ var insOfCall = Instruction.Create(Call, methodCall.Resolve());
+
+ ilRemoveEvent.Emit(Brtrue_S, insOfCall);
+ ilRemoveEvent.Emit(Pop);
+
+ var endIns = Instruction.Create(Ret);
+
+ ilRemoveEvent.Emit(Br_S, endIns);
+ ilRemoveEvent.Append(insOfCall);
+
+ ilRemoveEvent.Append(endIns);
+ }
+ }
+
+ TypeDefinition CreateTypeForRemoveEvents(TypeDefinition typeDef, out MethodDefinition constructor)
+ {
+ var module = typeDef.Module;
+
+ var name = "___Type___For___RemoveEvent___";
+ var nestType = typeDef.NestedTypes.FirstOrDefault(a => a.Name == name);
+
+ if (null == nestType)
+ {
+ nestType = new TypeDefinition(typeDef.Namespace, name, TypeAttributes.NestedPrivate | TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed | TypeAttributes.AnsiClass);
+ nestType.BaseType = module.ImportReference(typeof(object));
+ typeDef.NestedTypes.Add(nestType);
+
+ constructor = nestType.AddDefaultConstructor();
+ }
+ else
+ {
+ constructor = nestType.Methods.FirstOrDefault(a => a.IsConstructor);
+ }
+
+ return nestType;
+ }
+
+ bool TryCoreCompile(ILRootNode rootnode, EXamlContext visitorContext, out Exception exception)
+ {
+ try
+ {
+ XmlTypeExtensions.s_xmlnsDefinitions?.Clear();
+ XmlTypeExtensions.s_xmlnsDefinitions = null;
+
+ visitorContext.Values[rootnode] = new EXamlCreateObject(visitorContext, null, rootnode.TypeReference);
+
+ rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
+ rootnode.Accept(new EXamlExpandMarkupsVisitor(visitorContext), null);
+ rootnode.Accept(new PruneIgnoredNodesVisitor(), null);
+ rootnode.Accept(new EXamlCreateObjectVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetNamescopesAndRegisterNamesVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetFieldVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetResourcesVisitor(visitorContext), null);
+ rootnode.Accept(new EXamlSetPropertiesVisitor(visitorContext, true), null);
+
+ exception = null;
+ return true;
+ }
+ catch (Exception e)
+ {
+ XamlParseException xamlParseException = e as XamlParseException;
+ if (null != xamlParseException)
+ {
+ XamlParseException ret = new XamlParseException(xamlParseException.Message + "\n" + ReferencePath, xamlParseException.XmlInfo, xamlParseException.InnerException);
+ exception = ret;
+ }
+ else
+ {
+ exception = e;
+ }
+
+ return false;
+ }
+ }
+
+ private void Set(ILContext Context, VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo)
+ {
+ var module = Context.Body.Method.Module;
+ TypeReference declaringTypeReference;
+ var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
+ if (null == property)
+ {
+ return;
+ }
+ var propertySetter = property.SetMethod;
+
+ module.ImportReference(parent.VariableType.ResolveCached());
+ var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
+ propertySetterRef.ImportTypes(module);
+ var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
+ var valueNode = node as ValueNode;
+ var elementNode = node as IElementNode;
+
+ if (parent.VariableType.IsValueType)
+ Context.IL.Emit(OpCodes.Ldloca, parent);
+ else
+ Context.IL.Emit(OpCodes.Ldloc, parent);
+
+ if (valueNode != null)
+ {
+ foreach (var instruction in valueNode.PushConvertedValue(Context, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(Context, propertyRef: property), false, true))
+ {
+ Context.IL.Append(instruction);
+ }
+
+ if (parent.VariableType.IsValueType)
+ Context.IL.Emit(OpCodes.Call, propertySetterRef);
+ else
+ Context.IL.Emit(OpCodes.Callvirt, propertySetterRef);
+ }
+ }
+
+ internal static string GetPathForType(ModuleDefinition module, TypeReference type)
+ {
+ foreach (var ca in type.Module.GetCustomAttributes())
+ {
+ if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
+ continue;
+ if (!TypeRefComparer.Default.Equals(ca.ConstructorArguments[2].Value as TypeReference, type))
+ continue;
+ return ca.ConstructorArguments[1].Value as string;
+ }
+ return null;
+ }
+
+ internal static string GetResourceIdForPath(ModuleDefinition module, string path)
+ {
+ foreach (var ca in module.GetCustomAttributes())
+ {
+ if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
+ continue;
+ if (ca.ConstructorArguments[1].Value as string != path)
+ continue;
+ return ca.ConstructorArguments[0].Value as string;
+ }
+ return null;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.IO;
+using System.Xml;
+using System.ComponentModel;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class XamlGTask : Task
+ {
+ [Required]
+ public ITaskItem[] XamlFiles { get; set; }
+
+ [Required]
+ public ITaskItem[] OutputFiles { get; set; }
+
+ public string Language { get; set; }
+ public string AssemblyName { get; set; }
+ public string DependencyPaths { get; set; }
+ public string ReferencePath { get; set; }
+ public bool AddXamlCompilationAttribute { get; set; }
+ public bool PrintReferenceAssemblies { get; set; }
+
+ private void PrintParam(string logFileName, string log)
+ {
+ FileStream stream = null;
+ if (false == File.Exists(logFileName))
+ {
+ stream = File.Create(logFileName);
+ }
+ else
+ {
+ stream = File.Open(logFileName, FileMode.Append);
+ }
+
+ byte[] buffer = System.Text.Encoding.Default.GetBytes(log + "\n");
+ stream.Write(buffer, 0, buffer.Length);
+ stream.Close();
+ }
+
+ public override bool Execute()
+ {
+ if (true == PrintReferenceAssemblies)
+ {
+ PrintParam(@"XamlG_Log.txt", "ReferencePath is " + ReferencePath);
+ }
+
+ //PrintParam(@"G:\XamlG_Log.txt", "ReferencePath is " + ReferencePath);
+ bool success = true;
+ //Log.LogMessage(MessageImportance.Normal, "Generating code behind for XAML files");
+
+ //NOTE: should not happen due to [Required], but there appears to be a place this is class is called directly
+ if (XamlFiles == null || OutputFiles == null) {
+ //Log.LogMessage("Skipping XamlG");
+ return true;
+ }
+
+ if (XamlFiles.Length != OutputFiles.Length) {
+ Log.LogError("\"{2}\" refers to {0} item(s), and \"{3}\" refers to {1} item(s). They must have the same number of items.", XamlFiles.Length, OutputFiles.Length, "XamlFiles", "OutputFiles");
+ return false;
+ }
+
+ for (int i = 0; i < XamlFiles.Length; i++) {
+ var xamlFile = XamlFiles[i];
+ var outputFile = OutputFiles[i].ItemSpec;
+ if (System.IO.Path.DirectorySeparatorChar == '/' && outputFile.Contains(@"\"))
+ outputFile = outputFile.Replace('\\','/');
+ else if (System.IO.Path.DirectorySeparatorChar == '\\' && outputFile.Contains(@"/"))
+ outputFile = outputFile.Replace('/', '\\');
+
+ var generator = new XamlGenerator(xamlFile, Language, AssemblyName, outputFile, ReferencePath, Log);
+ generator.AddXamlCompilationAttribute = AddXamlCompilationAttribute;
+ generator.ReferencePath = ReferencePath;
+
+ try {
+ if (!generator.Execute()) {
+ //If Execute() fails, the file still needs to exist because it is added to the <Compile/> ItemGroup
+ File.WriteAllText (outputFile, string.Empty);
+ }
+ }
+ 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+using System;
+using System.CodeDom;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.CSharp;
+using Mono.Cecil;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ class XamlGenerator
+ {
+ internal XamlGenerator()
+ {
+ }
+
+ private class XmlnsInfo
+ {
+ public void Add(ModuleDefinition module, string nameSpace, int level)
+ {
+ foreach (TypeDefinition type in module.Types)
+ {
+ if (type.Namespace == nameSpace
+ &&
+ type.IsPublic == true
+ &&
+ type.IsClass == true)
+ {
+ bool needUpdate = false;
+ if (true == classNameToNameSpace.ContainsKey(type.Name))
+ {
+ NameSpaceInfo info = classNameToNameSpace[type.Name];
+
+ if (level > info.level)
+ {
+ needUpdate = true;
+ }
+ }
+ else
+ {
+ needUpdate = true;
+ }
+
+ if (true == needUpdate)
+ {
+ classNameToNameSpace[type.Name] = new NameSpaceInfo(type.Namespace, level);
+ }
+ }
+ }
+ }
+
+ public string GetNameSpace(string nameSpace)
+ {
+ NameSpaceInfo ret;
+
+ classNameToNameSpace.TryGetValue(nameSpace, out ret);
+
+ return ret?.nameSpace;
+ }
+
+ private class NameSpaceInfo
+ {
+ internal NameSpaceInfo(string nameSpace, int level)
+ {
+ this.nameSpace = nameSpace;
+ this.level = level;
+ }
+
+ internal string nameSpace;
+ internal int level;
+ }
+
+ private Dictionary<string, NameSpaceInfo> classNameToNameSpace = new Dictionary<string, NameSpaceInfo>();
+ }
+
+ static private Dictionary<string, XmlnsInfo> xmlnsNameToInfo = new Dictionary<string, XmlnsInfo>();
+
+ internal string ReferencePath
+ {
+ set
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ List<ModuleDefinition> assemblyList = new List<ModuleDefinition>();
+
+ var paths = value.Replace("//", "/").Split(';');
+ foreach (var p in paths)
+ {
+ ModuleDefinition module = ModuleDefinition.ReadModule(p);
+
+ foreach (var attr in module.Assembly.CustomAttributes)
+ {
+ if (attr.AttributeType.FullName == "Tizen.NUI.XmlnsDefinitionAttribute")
+ {
+ string xmlNamespace = attr.ConstructorArguments[0].Value as string;
+ string clrNamespace = attr.ConstructorArguments[1].Value as string;
+
+ int level = 0;
+ string assemblyName = module.Assembly.FullName;
+
+ if (true == attr.HasProperties)
+ {
+ foreach (var property in attr.Properties)
+ {
+ if ("Level" == property.Name)
+ {
+ level = int.Parse(property.Argument.Value.ToString());
+ }
+ if ("AssemblyName" == property.Name)
+ {
+ assemblyName = property.Argument.Value as string;
+ }
+ }
+ }
+
+ XmlnsInfo xmlsInfo = null;
+
+ if (xmlnsNameToInfo.ContainsKey(xmlNamespace))
+ {
+ xmlsInfo = xmlnsNameToInfo[xmlNamespace];
+ }
+ else
+ {
+ xmlsInfo = new XmlnsInfo();
+ xmlnsNameToInfo.Add(xmlNamespace, xmlsInfo);
+ }
+
+ xmlsInfo.Add(module, clrNamespace, level);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public XamlGenerator(
+ ITaskItem taskItem,
+ string language,
+ string assemblyName,
+ string outputFile,
+ string ReferencePath,
+ TaskLoggingHelper logger)
+ : this(
+ taskItem.ItemSpec,
+ language,
+ taskItem.GetMetadata("ManifestResourceName"),
+ taskItem.GetMetadata("TargetPath"),
+ assemblyName,
+ outputFile,
+ logger)
+ {
+ this.ReferencePath = ReferencePath;
+ }
+
+ static int generatedTypesCount;
+ internal static CodeDomProvider Provider = new CSharpCodeProvider();
+
+ public string XamlFile { 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 string RootClrNamespace { get; private set; }
+ public string RootType { get; private set; }
+ public bool AddXamlCompilationAttribute { get; set; }
+ bool GenerateDefaultCtor { get; set; }
+ bool HideFromIntellisense { get; set; }
+ bool XamlResourceIdOnly { get; set; }
+ internal IEnumerable<CodeMemberField> NamedFields { get; set; }
+ internal CodeTypeReference BaseType { get; set; }
+
+ public XamlGenerator(
+ string xamlFile,
+ string language,
+ string resourceId,
+ string targetPath,
+ string assemblyName,
+ string outputFile,
+ TaskLoggingHelper logger = null)
+ {
+ XamlFile = xamlFile;
+ Language = language;
+ ResourceId = resourceId;
+ TargetPath = targetPath;
+ AssemblyName = assemblyName;
+ OutputFile = outputFile;
+ Logger = logger;
+ }
+
+ //returns true if a file is generated
+ public bool Execute()
+ {
+ Logger?.LogMessage(MessageImportance.Low, "Source: {0}", XamlFile);
+ Logger?.LogMessage(MessageImportance.Low, " Language: {0}", Language);
+ Logger?.LogMessage(MessageImportance.Low, " ResourceID: {0}", ResourceId);
+ Logger?.LogMessage(MessageImportance.Low, " TargetPath: {0}", TargetPath);
+ Logger?.LogMessage(MessageImportance.Low, " AssemblyName: {0}", AssemblyName);
+ Logger?.LogMessage(MessageImportance.Low, " OutputFile {0}", OutputFile);
+
+ using (StreamReader reader = File.OpenText(XamlFile))
+ if (!ParseXaml(reader))
+ return false;
+
+ GenerateCode(OutputFile);
+
+ return true;
+ }
+
+ internal bool ParseXaml(TextReader xaml)
+ {
+ var xmlDoc = new XmlDocument();
+ xmlDoc.Load(xaml);
+
+ // if the following xml processing instruction is present
+ //
+ // <?xaml-comp compile="true" ?>
+ //
+ // we will generate a xaml.g.cs file with the default ctor calling InitializeComponent, and a XamlCompilation attribute
+ var hasXamlCompilationProcessingInstruction = GetXamlCompilationProcessingInstruction(xmlDoc);
+
+ var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
+ nsmgr.AddNamespace("__f__", XamlParser.XFUri);
+
+ var root = xmlDoc.SelectSingleNode("/*", nsmgr);
+ if (root == null) {
+ Logger?.LogMessage(MessageImportance.Low, " No root node found");
+ return false;
+ }
+
+ foreach (XmlAttribute attr in root.Attributes) {
+ if (attr.Name == "xmlns")
+ nsmgr.AddNamespace("", attr.Value); //Add default xmlns
+ if (attr.Prefix != "xmlns")
+ continue;
+ nsmgr.AddNamespace(attr.LocalName, attr.Value);
+ }
+
+ var rootClass = root.Attributes["Class", XamlParser.X2006Uri]
+ ?? root.Attributes["Class", XamlParser.X2009Uri];
+
+ if (rootClass != null) {
+ string rootType, rootNs, rootAsm, targetPlatform;
+ XmlnsHelper.ParseXmlns(rootClass.Value, out rootType, out rootNs, out rootAsm, out targetPlatform);
+ RootType = rootType;
+ RootClrNamespace = rootNs;
+ }
+ else if (hasXamlCompilationProcessingInstruction) {
+ RootClrNamespace = "__XamlGeneratedCode__";
+ RootType = $"__Type{generatedTypesCount++}";
+ GenerateDefaultCtor = true;
+ AddXamlCompilationAttribute = true;
+ HideFromIntellisense = true;
+ }
+ else { // rootClass == null && !hasXamlCompilationProcessingInstruction) {
+ XamlResourceIdOnly = true; //only generate the XamlResourceId assembly attribute
+ return true;
+ }
+
+ NamedFields = GetCodeMemberFields(root, nsmgr);
+ var typeArguments = GetAttributeValue(root, "TypeArguments", XamlParser.X2006Uri, XamlParser.X2009Uri);
+ var xmlType = new XmlType(root.NamespaceURI, root.LocalName, typeArguments != null ? TypeArgumentsParser.ParseExpression(typeArguments, nsmgr, null) : null);
+ BaseType = GetType(xmlType, root.GetNamespaceOfPrefix);
+
+ return true;
+ }
+
+ static System.Version version = typeof(XamlGenerator).Assembly.GetName().Version;
+ static CodeAttributeDeclaration GeneratedCodeAttrDecl =>
+ new CodeAttributeDeclaration(new CodeTypeReference($"global::{typeof(GeneratedCodeAttribute).FullName}"),
+ new CodeAttributeArgument(new CodePrimitiveExpression("Tizen.NUI.Xaml.Build.Tasks.XamlG")),
+ new CodeAttributeArgument(new CodePrimitiveExpression($"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}")));
+
+ void GenerateCode(string outFilePath)
+ {
+ //Create the target directory if required
+ Directory.CreateDirectory(System.IO.Path.GetDirectoryName(outFilePath));
+
+ 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('\\', '/'))), //use forward slashes, paths are uris-like
+ new CodeAttributeArgument(RootType == null ? (CodeExpression)new CodePrimitiveExpression(null) : new CodeTypeOfExpression($"global::{RootClrNamespace}.{RootType}"))
+ ));
+ if (XamlResourceIdOnly)
+ goto writeAndExit;
+
+ if (RootType == null)
+ throw new Exception("Something went wrong while executing XamlG");
+
+ var declNs = new CodeNamespace(RootClrNamespace);
+ ccu.Namespaces.Add(declNs);
+
+ var declType = new CodeTypeDeclaration(RootType) {
+ IsPartial = true,
+ CustomAttributes = {
+ new CodeAttributeDeclaration(new CodeTypeReference(XamlCTask.xamlNameSpace + ".XamlFilePathAttribute"),
+ new CodeAttributeArgument(new CodePrimitiveExpression(XamlFile))),
+ }
+ };
+ if (AddXamlCompilationAttribute)
+ declType.CustomAttributes.Add(
+ new CodeAttributeDeclaration(new CodeTypeReference(XamlCTask.xamlNameSpace + ".XamlCompilationAttribute"),
+ new CodeAttributeArgument(new CodeSnippetExpression($"global::{typeof(XamlCompilationOptions).FullName}.Compile"))));
+ if (HideFromIntellisense)
+ declType.CustomAttributes.Add(
+ new CodeAttributeDeclaration(new CodeTypeReference($"global::{typeof(System.ComponentModel.EditorBrowsableAttribute).FullName}"),
+ new CodeAttributeArgument(new CodeSnippetExpression($"global::{typeof(System.ComponentModel.EditorBrowsableState).FullName}.{nameof(System.ComponentModel.EditorBrowsableState.Never)}"))));
+
+ declType.BaseTypes.Add(BaseType);
+
+ declNs.Types.Add(declType);
+
+ //Create a default ctor calling InitializeComponent
+ if (GenerateDefaultCtor) {
+ var ctor = new CodeConstructor {
+ Attributes = MemberAttributes.Public,
+ CustomAttributes = { GeneratedCodeAttrDecl },
+ Statements = {
+ new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "InitializeComponent")
+ }
+ };
+
+ declType.Members.Add(ctor);
+ }
+
+ //Create InitializeComponent()
+ var initcomp = new CodeMemberMethod {
+ Name = "InitializeComponent",
+ CustomAttributes = { GeneratedCodeAttrDecl }
+ };
+
+ declType.Members.Add(initcomp);
+
+ //Create and initialize fields
+ var loadExaml_invoke = new CodeMethodInvokeExpression(
+ new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.EXaml.EXamlExtensions")),
+ "LoadFromEXamlByRelativePath", new CodeThisReferenceExpression(),
+ new CodeMethodInvokeExpression()
+ { Method = new CodeMethodReferenceExpression() { MethodName = "GetEXamlPath" } });
+
+ CodeAssignStatement assignEXamlObject = new CodeAssignStatement(
+ new CodeVariableReferenceExpression("eXamlData"), loadExaml_invoke);
+
+ initcomp.Statements.Add(assignEXamlObject);
+
+ foreach (var namedField in NamedFields) {
+ declType.Members.Add(namedField);
+
+ var find_invoke = new CodeMethodInvokeExpression(
+ new CodeMethodReferenceExpression(
+ new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.Binding.NameScopeExtensions")),
+ "FindByName", namedField.Type),
+ new CodeThisReferenceExpression(), new CodePrimitiveExpression(namedField.Name));
+
+ CodeAssignStatement assign = new CodeAssignStatement(
+ new CodeVariableReferenceExpression(namedField.Name), find_invoke);
+
+ initcomp.Statements.Add(assign);
+ }
+
+ declType.Members.Add(new CodeMemberField
+ {
+ Name = "eXamlData",
+ Type = new CodeTypeReference("System.Object"),
+ Attributes = MemberAttributes.Private,
+ CustomAttributes = { GeneratedCodeAttrDecl }
+ });
+
+ var getEXamlPathcomp = new CodeMemberMethod()
+ {
+ Name = "GetEXamlPath",
+ ReturnType = new CodeTypeReference(typeof(string)),
+ CustomAttributes = { GeneratedCodeAttrDecl }
+ };
+
+ getEXamlPathcomp.Statements.Add(new CodeMethodReturnStatement(new CodeDefaultValueExpression(new CodeTypeReference(typeof(string)))));
+
+ declType.Members.Add(getEXamlPathcomp);
+
+ GenerateMethodExitXaml(declType);
+
+ writeAndExit:
+ //write the result
+ using (var writer = new StreamWriter(outFilePath))
+ Provider.GenerateCodeFromCompileUnit(ccu, writer, new CodeGeneratorOptions());
+ }
+
+ private static void GenerateMethodExitXaml(CodeTypeDeclaration declType)
+ {
+ var removeEventsComp = new CodeMemberMethod()
+ {
+ Name = "RemoveEventsInXaml",
+ CustomAttributes = { GeneratedCodeAttrDecl }
+ };
+
+ removeEventsComp.Statements.Add(new CodeMethodInvokeExpression(
+ new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.EXaml.EXamlExtensions")),
+ "RemoveEventsInXaml", new CodeVariableReferenceExpression("eXamlData")));
+
+ declType.Members.Add(removeEventsComp);
+
+ var exitXamlComp = new CodeMemberMethod()
+ {
+ Name = "ExitXaml",
+ CustomAttributes = { GeneratedCodeAttrDecl }
+ };
+
+ exitXamlComp.Statements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression()
+ {
+ MethodName = "RemoveEventsInXaml",
+ }));
+
+ var disposeXamlElements_invoke = new CodeMethodInvokeExpression(
+ new CodeTypeReferenceExpression(new CodeTypeReference($"global::Tizen.NUI.EXaml.EXamlExtensions")),
+ "DisposeXamlElements", new CodeThisReferenceExpression());
+
+ exitXamlComp.Statements.Add(disposeXamlElements_invoke);
+
+ declType.Members.Add(exitXamlComp);
+ }
+
+ static IEnumerable<CodeMemberField> GetCodeMemberFields(XmlNode root, XmlNamespaceManager nsmgr)
+ {
+ var xPrefix = nsmgr.LookupPrefix(XamlParser.X2006Uri) ?? nsmgr.LookupPrefix(XamlParser.X2009Uri);
+ if (xPrefix == null)
+ yield break;
+
+ XmlNodeList names =
+ root.SelectNodes(
+ "//*[@" + xPrefix + ":Name" +
+ "][not(ancestor:: __f__:DataTemplate) and not(ancestor:: __f__:ControlTemplate) and not(ancestor:: __f__:Style) and not(ancestor:: __f__:VisualStateManager.VisualStateGroups)]", nsmgr);
+ foreach (XmlNode node in names) {
+ var name = GetAttributeValue(node, "Name", XamlParser.X2006Uri, XamlParser.X2009Uri);
+ var typeArguments = GetAttributeValue(node, "TypeArguments", XamlParser.X2006Uri, XamlParser.X2009Uri);
+ var fieldModifier = GetAttributeValue(node, "FieldModifier", XamlParser.X2006Uri, XamlParser.X2009Uri);
+
+ var xmlType = new XmlType(node.NamespaceURI, node.LocalName,
+ typeArguments != null
+ ? TypeArgumentsParser.ParseExpression(typeArguments, nsmgr, null)
+ : null);
+
+ var access = MemberAttributes.Public;
+ if (fieldModifier != null) {
+ switch (fieldModifier.ToLowerInvariant()) {
+ default:
+ case "private":
+ access = MemberAttributes.Private;
+ break;
+ case "public":
+ access = MemberAttributes.Public;
+ break;
+ case "protected":
+ access = MemberAttributes.Family;
+ break;
+ case "internal":
+ case "notpublic": //WPF syntax
+ access = MemberAttributes.Assembly;
+ break;
+ }
+ }
+
+ yield return new CodeMemberField {
+ Name = name,
+ Type = GetType(xmlType, node.GetNamespaceOfPrefix),
+ Attributes = access,
+ CustomAttributes = { GeneratedCodeAttrDecl }
+ };
+ }
+ }
+
+ static bool GetXamlCompilationProcessingInstruction(XmlDocument xmlDoc)
+ {
+ var instruction = xmlDoc.SelectSingleNode("processing-instruction('xaml-comp')") as XmlProcessingInstruction;
+ if (instruction == null)
+ return false;
+
+ var parts = instruction.Data.Split(' ', '=');
+ string compileValue = null;
+ var indexOfCompile = Array.IndexOf(parts, "compile");
+ if (indexOfCompile != -1)
+ compileValue = parts[indexOfCompile + 1].Trim('"', '\'');
+ return compileValue.Equals("true", StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ static CodeTypeReference GetType(XmlType xmlType,
+ Func<string, string> getNamespaceOfPrefix = null)
+ {
+ var type = xmlType.Name;
+ var ns = GetClrNamespace(xmlType.NamespaceUri, xmlType.Name);
+ if (ns != null)
+ type = $"{ns}.{type}";
+
+ if (xmlType.TypeArguments != null)
+ type = $"{type}`{xmlType.TypeArguments.Count}";
+
+ var returnType = new CodeTypeReference(type);
+ if (ns != null)
+ returnType.Options |= CodeTypeReferenceOptions.GlobalReference;
+
+ if (xmlType.TypeArguments != null)
+ foreach (var typeArg in xmlType.TypeArguments)
+ returnType.TypeArguments.Add(GetType(typeArg, getNamespaceOfPrefix));
+
+ return returnType;
+ }
+
+ static string GetClrNamespace(string namespaceuri, string className)
+ {
+ XmlnsInfo xmlnsInfo = null;
+
+ xmlnsNameToInfo.TryGetValue(namespaceuri, out xmlnsInfo);
+
+ if (null != xmlnsInfo)
+ {
+ string nameSpace = xmlnsInfo.GetNameSpace(className);
+
+ if (null != nameSpace)
+ {
+ return nameSpace;
+ }
+ }
+
+ if (namespaceuri == "http://tizen.org/Tizen.NUI/2018/XAML")
+ return "Tizen.NUI.Xaml";
+ if (namespaceuri == XamlParser.XFUri)
+ return "Tizen.NUI.Xaml";
+ if (namespaceuri == XamlParser.X2009Uri)
+ return "System";
+ //if (namespaceuri != XamlParser.X2006Uri && !namespaceuri.StartsWith("clr-namespace", StringComparison.InvariantCulture) && !namespaceuri.StartsWith("using", StringComparison.InvariantCulture))
+ // throw new Exception($"Can't load types from xmlns {namespaceuri}");
+ return XmlnsHelper.ParseNamespaceFromXmlns(namespaceuri);
+ }
+
+ static string GetAttributeValue(XmlNode node, string localName, params string[] namespaceURIs)
+ {
+ if (node == null)
+ throw new ArgumentNullException(nameof(node));
+ if (localName == null)
+ throw new ArgumentNullException(nameof(localName));
+ if (namespaceURIs == null)
+ throw new ArgumentNullException(nameof(namespaceURIs));
+ foreach (var namespaceURI in namespaceURIs) {
+ var attr = node.Attributes[localName, namespaceURI];
+ if (attr == null)
+ continue;
+ return attr.Value;
+ }
+ return null;
+ }
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Xml;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+using Mono.Cecil;
+
+using Tizen.NUI.Xaml;
+using Mono.Cecil.Cil;
+using Mono.Cecil.Pdb;
+using Mono.Cecil.Mdb;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ [LoadInSeparateAppDomain]
+ public abstract class XamlTask : MarshalByRefObject, ITask
+ {
+ internal const string nuiAssemblyName = "Tizen.NUI";
+ internal const string nuiNameSpace = "Tizen.NUI";
+
+ internal const string xamlAssemblyName = "Tizen.NUI";
+ internal const string xamlNameSpace = "Tizen.NUI.Xaml";
+
+ internal const string bindingAssemblyName = "Tizen.NUI";
+ internal const string bindingNameSpace = "Tizen.NUI.Binding";
+ internal const string bindingInternalNameSpace = "Tizen.NUI.Binding.Internals";
+
+ [Required]
+ public string Assembly { get; set; }
+ public string DependencyPaths { get; set; }
+ public string ReferencePath { get; set; }
+ [Obsolete("this is no longer used")]
+ public int Verbosity { get; set; }
+ public bool DebugSymbols { get; set; }
+ public string DebugType { get; set; }
+ public string XamlFilePath { get; set; }
+
+ protected TaskLoggingHelper LoggingHelper { get; }
+
+ internal XamlTask()
+ {
+ LoggingHelper = new TaskLoggingHelper(this);
+ }
+
+ public IBuildEngine BuildEngine { get; set; }
+ public ITaskHost HostObject { get; set; }
+
+ public bool Execute()
+ {
+ IList<Exception> _;
+ return Execute(out _);
+ }
+
+ public abstract bool Execute(out IList<Exception> thrownExceptions);
+
+ internal static ILRootNode ParseXaml(Stream stream, TypeReference typeReference)
+ {
+ ILRootNode rootnode = null;
+ using (var reader = XmlReader.Create(stream)) {
+ while (reader.Read()) {
+ //Skip until element
+ if (reader.NodeType == XmlNodeType.Whitespace)
+ continue;
+ if (reader.NodeType != XmlNodeType.Element) {
+ Debug.WriteLine("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
+ continue;
+ }
+
+ XamlParser.ParseXaml(
+ rootnode = new ILRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), typeReference, reader as IXmlNamespaceResolver), reader);
+ break;
+ }
+ }
+ return rootnode;
+ }
+
+ internal static string GetResourceIdForPath(ModuleDefinition module, string path)
+ {
+ foreach (var ca in module.GetCustomAttributes())
+ {
+ if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
+ continue;
+ if (ca.ConstructorArguments[1].Value as string != path)
+ continue;
+ return ca.ConstructorArguments[0].Value as string;
+ }
+ return null;
+ }
+
+ internal static string GetPathForType(ModuleDefinition module, TypeReference type)
+ {
+ foreach (var ca in type.Module.GetCustomAttributes())
+ {
+ if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((xamlAssemblyName, xamlNameSpace, "XamlResourceIdAttribute"))))
+ continue;
+ if (!TypeRefComparer.Default.Equals(ca.ConstructorArguments[2].Value as TypeReference, type))
+ continue;
+ return ca.ConstructorArguments[1].Value as string;
+ }
+ return null;
+ }
+
+ internal static IList<XmlnsDefinitionAttribute> s_xmlnsDefinitions
+ {
+ get;
+ } = new List<XmlnsDefinitionAttribute>();
+ }
+
+ public static class CecilExtensions
+ {
+ public static bool IsXaml(this EmbeddedResource resource, ModuleDefinition module, out string classname)
+ {
+ classname = null;
+ if (!resource.Name.EndsWith(".xaml", StringComparison.InvariantCulture))
+ return false;
+
+ using (var resourceStream = resource.GetResourceStream()) {
+ var xmlDoc = new XmlDocument();
+ xmlDoc.Load(resourceStream);
+
+ var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
+
+ var root = xmlDoc.SelectSingleNode("/*", nsmgr);
+ if (root == null)
+ return false;
+
+ var rootClass = root.Attributes["Class", XamlParser.X2006Uri] ??
+ root.Attributes["Class", XamlParser.X2009Uri];
+ if (rootClass != null) {
+ classname = rootClass.Value;
+ return true;
+ }
+
+ //no x:Class, but it might be a RD without x:Class and with <?xaml-comp compile="true" ?>
+ //in that case, it has a XamlResourceIdAttribute
+ var typeRef = GetTypeForResourceId(module, resource.Name);
+ if (typeRef != null) {
+ classname = typeRef.FullName;
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ public static bool IsXaml(Stream resourceStream, ModuleDefinition module, out string classname)
+ {
+ classname = null;
+
+ var xmlDoc = new XmlDocument();
+ xmlDoc.Load(resourceStream);
+
+ var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
+
+ var root = xmlDoc.SelectSingleNode("/*", nsmgr);
+ if (root == null)
+ return false;
+
+ var rootClass = root.Attributes["Class", XamlParser.X2006Uri] ??
+ root.Attributes["Class", XamlParser.X2009Uri];
+ if (rootClass != null)
+ {
+ classname = rootClass.Value;
+ return true;
+ }
+
+ return false;
+ }
+
+ static TypeReference GetTypeForResourceId(ModuleDefinition module, string resourceId)
+ {
+ foreach (var ca in module.GetCustomAttributes()) {
+ if (!TypeRefComparer.Default.Equals(ca.AttributeType, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlResourceIdAttribute"))))
+ continue;
+ if (ca.ConstructorArguments[0].Value as string != resourceId)
+ continue;
+ return ca.ConstructorArguments[2].Value as TypeReference;
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+using Mono.Cecil;
+using Mono.Cecil.Rocks;
+using Tizen.NUI.Binding;
+using Tizen.NUI.Xaml;
+
+namespace Tizen.NUI.Xaml.Build.Tasks
+{
+ static class XmlTypeExtensions
+ {
+ static internal IList<XmlnsDefinitionAttribute> s_xmlnsDefinitions;
+
+ static void GatherXmlnsDefinitionAttributes()
+ {
+ //this could be extended to look for [XmlnsDefinition] in all assemblies
+ s_xmlnsDefinitions = XamlTask.s_xmlnsDefinitions.OrderByDescending(a => a.Level).ToList(); ;
+ }
+
+ public static TypeReference GetTypeReference(string xmlType, ModuleDefinition module, BaseNode node)
+ {
+ var split = xmlType.Split(':');
+ if (split.Length > 2)
+ throw new XamlParseException($"Type \"{xmlType}\" is invalid", node as IXmlLineInfo);
+
+ string prefix, name;
+ if (split.Length == 2) {
+ prefix = split[0];
+ name = split[1];
+ } else {
+ prefix = "";
+ name = split[0];
+ }
+ var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? "";
+ return GetTypeReference(new XmlType(namespaceuri, name, null), module, node as IXmlLineInfo);
+ }
+
+ public static TypeReference GetTypeReference(string namespaceURI, string typename, ModuleDefinition module, IXmlLineInfo xmlInfo)
+ {
+ return new XmlType(namespaceURI, typename, null).GetTypeReference(module, xmlInfo);
+ }
+
+ public static TypeReference GetTypeReference(this XmlType xmlType, ModuleDefinition module, IXmlLineInfo xmlInfo, bool fromAllAssembly = false)
+ {
+ if (s_xmlnsDefinitions == null)
+ GatherXmlnsDefinitionAttributes();
+
+ var namespaceURI = xmlType.NamespaceUri;
+ var elementName = xmlType.Name;
+ var typeArguments = xmlType.TypeArguments;
+
+ if (elementName.Contains("-"))
+ {
+ elementName = elementName.Replace('-', '+');
+ }
+
+ var lookupAssemblies = new List<XmlnsDefinitionAttribute>();
+
+ var lookupNames = new List<string>();
+
+ if (true == fromAllAssembly)
+ {
+ foreach (var xmlnsDef in s_xmlnsDefinitions)
+ {
+ lookupAssemblies.Add(xmlnsDef);
+ }
+ }
+ else
+ {
+ foreach (var xmlnsDef in s_xmlnsDefinitions)
+ {
+ if (xmlnsDef.XmlNamespace != namespaceURI)
+ continue;
+ lookupAssemblies.Add(xmlnsDef);
+ }
+ }
+
+ if (lookupAssemblies.Count == 0) {
+ string ns;
+ string typename;
+ string asmstring;
+ string targetPlatform;
+
+ XmlnsHelper.ParseXmlns(namespaceURI, out typename, out ns, out asmstring, out targetPlatform);
+ asmstring = asmstring ?? module.Assembly.Name.Name;
+ if (ns != null)
+ lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns, 0) {
+ AssemblyName = asmstring
+ });
+ }
+
+ lookupNames.Add(elementName);
+ lookupNames.Add(elementName + "Extension");
+
+ for (var i = 0; i < lookupNames.Count; i++)
+ {
+ var name = lookupNames[i];
+ if (name.Contains(":"))
+ name = name.Substring(name.LastIndexOf(':') + 1);
+ if (typeArguments != null)
+ name += "`" + typeArguments.Count; //this will return an open generic Type
+ lookupNames[i] = name;
+ }
+
+ TypeReference type = null;
+ foreach (var asm in lookupAssemblies)
+ {
+ if (type != null)
+ break;
+ foreach (var name in lookupNames)
+ {
+ if (type != null)
+ break;
+
+ var clrNamespace = asm.ClrNamespace;
+ var typeName = name.Replace('+', '/'); //Nested types
+ var idx = typeName.LastIndexOf('.');
+ if (idx >= 0) {
+ clrNamespace += '.' + typeName.Substring(0, typeName.LastIndexOf('.'));
+ typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
+ }
+ type = module.GetTypeDefinition((asm.AssemblyName, clrNamespace, typeName));
+ }
+ }
+
+ if (type != null && typeArguments != null && type.HasGenericParameters)
+ {
+ type =
+ module.ImportReference(type)
+ .MakeGenericInstanceType(typeArguments.Select(x => GetTypeReference(x, module, xmlInfo)).ToArray());
+ }
+
+ if (type == null)
+ throw new XamlParseException(string.Format("Type {0} not found in xmlns {1}", elementName, namespaceURI), xmlInfo);
+
+ return module.ImportReference(type);
+ }
+
+ public static TypeReference GetTypeExtensionReference(this XmlType xmlType, ModuleDefinition module, IXmlLineInfo xmlInfo, bool fromAllAssembly = false)
+ {
+ if (s_xmlnsDefinitions == null)
+ GatherXmlnsDefinitionAttributes();
+
+ var namespaceURI = xmlType.NamespaceUri;
+ var elementName = xmlType.Name;
+ var typeArguments = xmlType.TypeArguments;
+
+ if (elementName.Contains("-"))
+ {
+ elementName = elementName.Replace('-', '+');
+ }
+
+ var lookupAssemblies = new List<XmlnsDefinitionAttribute>();
+
+ var lookupNames = new List<string>();
+
+ if (true == fromAllAssembly)
+ {
+ foreach (var xmlnsDef in s_xmlnsDefinitions)
+ {
+ lookupAssemblies.Add(xmlnsDef);
+ }
+ }
+ else
+ {
+ foreach (var xmlnsDef in s_xmlnsDefinitions)
+ {
+ if (xmlnsDef.XmlNamespace != namespaceURI)
+ continue;
+ lookupAssemblies.Add(xmlnsDef);
+ }
+ }
+
+ if (lookupAssemblies.Count == 0)
+ {
+ string ns;
+ string typename;
+ string asmstring;
+ string targetPlatform;
+
+ XmlnsHelper.ParseXmlns(namespaceURI, out typename, out ns, out asmstring, out targetPlatform);
+ asmstring = asmstring ?? module.Assembly.Name.Name;
+ if (ns != null)
+ lookupAssemblies.Add(new XmlnsDefinitionAttribute(namespaceURI, ns, 0)
+ {
+ AssemblyName = asmstring
+ });
+ }
+
+ lookupNames.Add(elementName + "Extension");
+
+ for (var i = 0; i < lookupNames.Count; i++)
+ {
+ var name = lookupNames[i];
+ if (name.Contains(":"))
+ name = name.Substring(name.LastIndexOf(':') + 1);
+ if (typeArguments != null)
+ name += "`" + typeArguments.Count; //this will return an open generic Type
+ lookupNames[i] = name;
+ }
+
+ TypeReference type = null;
+ foreach (var asm in lookupAssemblies)
+ {
+ if (type != null)
+ break;
+ foreach (var name in lookupNames)
+ {
+ if (type != null)
+ break;
+
+ var clrNamespace = asm.ClrNamespace;
+ var typeName = name.Replace('+', '/'); //Nested types
+ var idx = typeName.LastIndexOf('.');
+ if (idx >= 0)
+ {
+ clrNamespace += '.' + typeName.Substring(0, typeName.LastIndexOf('.'));
+ typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
+ }
+ type = module.GetTypeDefinition((asm.AssemblyName, clrNamespace, typeName));
+
+ if (null == type)
+ {
+ type = module.GetTypeDefinition((module.Assembly.Name.Name, clrNamespace, typeName));
+ }
+ }
+ }
+
+ if (type != null && typeArguments != null && type.HasGenericParameters)
+ {
+ type =
+ module.ImportReference(type)
+ .MakeGenericInstanceType(typeArguments.Select(x => GetTypeReference(x, module, xmlInfo)).ToArray());
+ }
+
+ if (type == null)
+ throw new XamlParseException(string.Format("Type {0} not found in xmlns {1}", elementName, namespaceURI), xmlInfo);
+
+ return module.ImportReference(type);
+ }
+ }
+}
\ No newline at end of file