maui-linux/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs

747 строки
28 KiB
C#
Исходник Обычный вид История

2016-03-22 23:02:25 +03:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
using Xamarin.Forms.Internals;
2019-09-12 03:35:40 +03:00
using Xamarin.Forms.Xaml.Diagnostics;
2016-03-22 23:02:25 +03:00
using Xamarin.Forms.Xaml.Internals;
using static System.String;
2016-03-22 23:02:25 +03:00
namespace Xamarin.Forms.Xaml
{
class ApplyPropertiesVisitor : IXamlNodeVisitor
2016-03-22 23:02:25 +03:00
{
public static readonly IList<XmlName> Skips = new List<XmlName> {
2016-03-22 23:02:25 +03:00
XmlName.xKey,
XmlName.xTypeArguments,
XmlName.xArguments,
XmlName.xFactoryMethod,
XmlName.xName,
XmlName.xDataType
2016-03-22 23:02:25 +03:00
};
public ApplyPropertiesVisitor(HydrationContext context, bool stopOnResourceDictionary = false)
2016-03-22 23:02:25 +03:00
{
Context = context;
StopOnResourceDictionary = stopOnResourceDictionary;
}
Dictionary<INode, object> Values => Context.Values;
HydrationContext Context { get; }
2016-03-22 23:02:25 +03:00
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
public bool StopOnDataTemplate => true;
2016-03-22 23:02:25 +03:00
public bool StopOnResourceDictionary { get; }
public bool VisitNodeOnDataTemplate => true;
public bool SkipChildren(INode node, INode parentNode) => false;
public bool IsResourceDictionary(ElementNode node) => Context.Types.TryGetValue(node, out var type) && typeof(ResourceDictionary).IsAssignableFrom(type);
2016-03-22 23:02:25 +03:00
public void Visit(ValueNode node, INode parentNode)
{
var parentElement = parentNode as IElementNode;
var value = Values [node];
if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
return;
2016-03-22 23:02:25 +03:00
XmlName propertyName;
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
if (TryGetPropertyName(node, parentNode, out propertyName)) {
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
if (TrySetRuntimeName(propertyName, source, value, node))
return;
2016-03-22 23:02:25 +03:00
if (Skips.Contains(propertyName))
return;
if (parentElement.SkipProperties.Contains(propertyName))
return;
if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
2016-03-22 23:02:25 +03:00
return;
SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
} else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
2016-03-22 23:02:25 +03:00
// Collection element, implicit content, or implicit collection element.
var contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo());
if (contentProperty != null) {
2016-03-22 23:02:25 +03:00
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;
}
}
2016-03-22 23:02:25 +03:00
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;
}
if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null)
return;
if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) {
2016-03-22 23:02:25 +03:00
if (Skips.Contains(propertyName))
return;
if (parentElement.SkipProperties.Contains(propertyName))
return;
if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
return;
ProvideValue(ref value, node, source, propertyName);
SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
}
else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null)
return;
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;
2016-03-22 23:02:25 +03:00
// 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);
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
addMethod.Invoke(source, new[] { value });
return;
}
if (xpe == null && (contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null) {
2016-03-22 23:02:25 +03:00
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;
}
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);
else
throw xpe;
}
else if (IsCollectionItem(node, parentNode) && parentNode is ListNode) {
if (!Values.TryGetValue(parentNode.Parent, out var source) && Context.ExceptionHandler != null)
return;
ProvideValue(ref value, node, source, XmlName.Empty);
2016-03-22 23:02:25 +03:00
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;
2016-03-22 23:02:25 +03:00
2019-09-05 15:18:03 +03:00
var collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _, out _) as IEnumerable;
if (collection == null)
xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
if (xpe == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, node, out xpe))
return;
2016-03-22 23:02:25 +03:00
MethodInfo addMethod;
if (xpe == null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null) {
addMethod.Invoke(collection, new[] { value });
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;
2016-03-22 23:02:25 +03:00
}
}
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
2016-03-22 23:02:25 +03:00
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) {
2016-03-22 23:02:25 +03:00
if (kvp.Value != node)
continue;
name = kvp.Key;
return true;
}
return false;
}
internal static bool IsCollectionItem(INode node, INode parentNode)
2016-03-22 23:02:25 +03:00
{
var parentList = parentNode as IListNode;
if (parentList == null)
return false;
return parentList.CollectionItems.Contains(node);
}
internal static string GetContentPropertyName(TypeInfo typeInfo)
{
while (typeInfo != null) {
2016-03-22 23:02:25 +03:00
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 && propertyName != XmlName.Empty)
((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = GetTargetProperty(source, propertyName, Context, node);
try {
if (markupExtension != null)
value = markupExtension.ProvideValue(serviceProvider);
else if (valueProvider != null)
value = valueProvider.ProvideValue(serviceProvider);
} catch (Exception e) {
if (Context.ExceptionHandler != null)
Context.ExceptionHandler(e);
else
throw e;
}
}
2016-03-22 23:02:25 +03:00
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;
2016-03-22 23:02:25 +03:00
return null;
}
static bool GetRealNameAndType(ref Type elementType, string namespaceURI, ref string localname,
HydrationContext context, IXmlLineInfo lineInfo)
2016-03-22 23:02:25 +03:00
{
var dotIdx = localname.IndexOf('.');
if (dotIdx > 0) {
2016-03-22 23:02:25 +03:00
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);
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
2016-03-22 23:02:25 +03:00
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
// F# does not support public fields, so allow internal (Assembly) as well as public
const BindingFlags supportedFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
var bindableFieldInfo = elementType.GetFields(supportedFlags)
.FirstOrDefault(fi => (fi.IsAssembly || fi.IsPublic) && fi.Name == localName + "Property");
#endif
2016-03-22 23:02:25 +03:00
Exception exception = null;
if (exception == null && bindableFieldInfo == null) {
2016-03-22 23:02:25 +03:00
exception =
new XamlParseException(
Format("BindableProperty {0} not found on {1}", localName + "Property", elementType.Name), lineInfo);
2016-03-22 23:02:25 +03:00
}
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)
2016-03-22 23:02:25 +03:00
{
var localName = propertyName.LocalName;
2016-03-22 23:02:25 +03:00
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;
2016-03-22 23:02:25 +03:00
//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);
2016-03-22 23:02:25 +03:00
//If the target is an event, connect
if (xpe == null && TryConnectEvent(xamlelement, localName, attached, value, rootElement, lineInfo, out xpe))
return;
2016-03-22 23:02:25 +03:00
//If Value is DynamicResource and it's a BP, SetDynamicResource
if (xpe == null && TrySetDynamicResource(xamlelement, property, value, lineInfo, out xpe))
2016-03-22 23:02:25 +03:00
return;
//If value is BindingBase, SetBinding
if (xpe == null && TrySetBinding(xamlelement, property, localName, value, lineInfo, out xpe))
return;
2016-03-22 23:02:25 +03:00
//If it's a BindableProberty, SetValue
if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe))
2016-03-22 23:02:25 +03:00
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;
2016-03-22 23:02:25 +03:00
//If it's an already initialized property, add to it
if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe))
2016-03-22 23:02:25 +03:00
return;
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
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;
}
2019-09-05 15:18:03 +03:00
public static object GetPropertyValue(object xamlElement, XmlName propertyName, HydrationContext context, IXmlLineInfo lineInfo, out Exception xpe, out object targetProperty)
{
var localName = propertyName.LocalName;
2019-09-05 15:18:03 +03:00
xpe = null;
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
2019-09-05 15:18:03 +03:00
if (xpe == null && TryGetValue(xamlElement, property, attached, out var value, lineInfo, out xpe, out targetProperty))
return value;
//If it's a normal property, get it
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);
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;
foreach (var mi in rootElement.GetType().GetRuntimeMethods()) {
if (mi.Name == (string)value) {
try {
eventInfo.AddEventHandler(element, mi.CreateDelegate(eventInfo.EventHandlerType, mi.IsStatic ? null : rootElement));
return true;
} catch (ArgumentException) {
// incorrect method signature
}
}
2016-03-22 23:02:25 +03:00
}
exception = new XamlParseException($"No method {value} with correct signature found on type {rootElement.GetType()}", lineInfo);
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, exception:out exception) as BindingBase;
if (exception != null)
return false;
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;
2016-03-22 23:02:25 +03:00
if (property != null)
exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support native bindings", lineInfo);
2016-03-22 23:02:25 +03:00
return false;
}
2016-03-22 23:02:25 +03:00
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 = () =>
{
try {
return property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new[] { typeof(BindableObject) });
} catch (AmbiguousMatchException e) {
throw new XamlParseException($"Multiple methods with name '{property.DeclaringType}.Get{property.PropertyName}' found.", lineInfo, innerException: e);
}
};
else
minforetriever = () =>
{
try {
return property.DeclaringType.GetRuntimeProperty(property.PropertyName);
} catch (AmbiguousMatchException e) {
throw new XamlParseException($"Multiple properties with name '{property.DeclaringType}.{property.PropertyName}' found.", lineInfo, innerException: e);
}
};
var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider, out exception);
if (exception != null)
return false;
if (bindable != null) {
2016-03-22 23:02:25 +03:00
//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<>);
2016-03-22 23:02:25 +03:00
if ((convertedValue == null && (!property.ReturnTypeInfo.IsValueType || nullable)) ||
(property.ReturnType.IsInstanceOfType(convertedValue))) {
try {
bindable.SetValue(property, convertedValue);
return true;
}
catch (Exception e) {
exception = e;
return false;
}
2016-03-22 23:02:25 +03:00
}
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
// This might be a collection; see if we can add to it
return TryAddValue(bindable, property, value, serviceProvider, out exception);
2016-03-22 23:02:25 +03:00
}
if (nativeBindingService != null && nativeBindingService.TrySetValue(element, property, convertedValue))
return true;
2016-03-22 23:02:25 +03:00
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);
2016-03-22 23:02:25 +03:00
MethodInfo setter;
if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null)
return false;
2016-03-22 23:02:25 +03:00
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, out exception);
if (exception != null || (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue)))
return false;
try {
setter.Invoke(element, new object[] { convertedValue });
return true;
}
catch (Exception e) {
exception = e;
return false;
}
}
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;
#if NETSTANDARD1_0
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;
}
}
#else
while (elementType != null && propertyInfo == null) {
try {
propertyInfo = elementType.GetProperty(localName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly);
} catch (AmbiguousMatchException e) {
throw new XamlParseException($"Multiple properties with name '{elementType}.{localName}' found.", lineInfo, innerException: e);
}
elementType = elementType.BaseType;
}
#endif
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;
2019-09-05 15:18:03 +03:00
if (!(GetPropertyValue(element, propertyName, context, lineInfo, out _, out var targetProperty) is IEnumerable collection))
return false;
if (exception == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, lineInfo, out exception))
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)
((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty;
try {
addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func<TypeConverter>)null, serviceProvider, out exception) });
}
catch (Exception e) {
exception = e;
}
return exception == null;
2016-03-22 23:02:25 +03:00
}
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 Style)
resourceDictionary.Add((Style)value);
else if (value is ResourceDictionary)
resourceDictionary.Add((ResourceDictionary)value);
else if (value is StyleSheets.StyleSheet)
resourceDictionary.Add((StyleSheets.StyleSheet)value);
else {
exception = new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
return false;
}
return true;
}
2016-03-22 23:02:25 +03:00
void SetTemplate(ElementTemplate dt, INode node)
{
#pragma warning disable 0612
((IDataTemplate)dt).LoadTemplate = () => {
2016-03-22 23:02:25 +03:00
#pragma warning restore 0612
var cnode = node.Clone();
var context = new HydrationContext { ParentContext = Context, RootAssembly = Context.RootAssembly, RootElement = Context.RootElement, ExceptionHandler = Context.ExceptionHandler };
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];
2016-03-22 23:02:25 +03:00
};
}
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
static bool TryAddValue(BindableObject bindable, BindableProperty property, object value, XamlServiceProvider serviceProvider, out Exception exception)
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
{
exception = null;
if (property?.ReturnTypeInfo?.GenericTypeArguments == null)
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
return false;
if (property.ReturnType == null)
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
return false;
if (property.ReturnTypeInfo.GenericTypeArguments.Length != 1 || !property.ReturnTypeInfo.GenericTypeArguments[0].IsInstanceOfType(value))
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
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);
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
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, out exception) });
return exception == null;
VisualStateManager phase 1 (#1405) * Port from old VSM branch * Add PS and notes * Checkpoint: entry text UWP mostly working, need to check on background colors * Remove irrelevant samples from the EntryDisabledStatesGallery Make Background color work on UWP Entry with VSM * Add platform specific for disabling legacy colors on Android * Add OnPlatform example to visual state manager gallery * Add example OnIdiom in Visual State Manager * Add platform specific for disabling legacy color mode on iOS Entry * Add gallery for Button disabled states Handling legacy colors for Buttons on Android * Split out disabled states galleries; disabled legacy handling for Picker * TimePicker disabled states * DatePicker color management on Android * Color management for pre-AppCompat button * Button legacy color handling on iOS * Consolidate Platform Specifics; legacy colors working for iOS Picker and DatePicker * Fix broken search bar color management SearchBar color management working with VSM Add test page for SearchBar disabled color management Consolidate legacy color management check code into extension method on Android * Legacy color management for Editor on Android * Fix legacy color stuff for SearchBar Cancel button on iOS * C# 7 cleanup * Add colors for Cancel Button * Make sure VisualStateGroup collections set by styles are distinct objects * Validation example * Make common state names consts * Make the Windows VSM and Forms VSM work together * Update galleries for Windows * Make new methods internal * Split gallery classes and add more explanation to validation example * Remove debugging statements * Add a quick code-only example * Make legacy color management work for fast button renderer * Remove old TODO * Update docs * Move RunTimeNamePropertyAttribute to Xamarin.Forms.Xaml namespace * Verify XF namespace when looking for VisualState * Use nameof * Make common states constants public * Cast VisualElement directly so it crashes if the property is set on the wrong type * Collection -> IList for VisualStateManager * Setting fromStyle to true * Remove extraneous `private set` * Seal VSM classes * Use constraints instead of == * Add teardown method; use constraints rather than == * Remove null checking with GetVisualStateGroups * Don't explicitly initialize collections on elements * Actually, turns out that fromStyle:false *was* correct * Direct casts * Use GetIsDefault check in GoToState * Validate parents in FindTypeForVisualState * Validate group and state names on Add * Fixed check for setter collection * Fix issues with "duplicate" names when VisualStateGroups declared directly on VisualElements * Add gallery example for VSGs directly on VisualElements * Update docs * Fix bug where initial TextColor isn't set for FastRenderer Button * Move to explicit VisualStateGroupList in Setter * Fix return types for unit tests * Using string.CompareOrdinal in GetState * Update docs * Add check for null/empty VisualState Name properties
2018-01-05 12:11:51 +03:00
}
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;
}
2016-03-22 23:02:25 +03:00
}
}