You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on May 1, 2024. It is now read-only.
AppThemeBindingExtension does not work in a MultiBinding as conversion code needs the property type ( and targetObject is the MultiBinding, targetProperty isnull ) -
Given the extension returns a BindingBase it should be usable in a MultiBinding Bindings property - IList<BindingBase>
Actual Behavior
"Cannot determine property to provide the value for."
Basic Information
Version with issue: Current / probably all versions
Last known good version:
Workaround
Create a new extension - AppThemeBindingInMultiBindingExtension
Reflection due to internals.
Markup extension service IValueConverterProvider is internal.
TypeConversionExtensions is internal.
AppThemeBinding is internal.
Provide the property type for conversion or don't convert.
<Label.TextColor>
<MultiBinding Converter="{StaticResource MyConverter}">
<Binding Path="ServerReceiver"/>
<!-- if using conversion-->
<!--<markupExtensions:AppThemeBindingInMultiBindingExtension Light="Black" Dark="White" BindableProperty="{x:Static Label.TextColorProperty}"/>-->
<!-- no conversion -->
<markupExtensions:AppThemeBindingInMultiBindingExtension Light="{StaticResource LightLabelTextColor}" Dark="{StaticResource DarkLabelTextColor}" />
</MultiBinding>
</Label.TextColor>
public static class XamlParseExceptionLineInfoHelper
{
public static XamlParseException CreateException(string message, IServiceProvider serviceProvider, Exception innerException = null)
{
return new XamlParseException(message, GetLineInfo(serviceProvider), innerException);
}
private static IXmlLineInfo GetLineInfo(IServiceProvider serviceProvider)
{
IXmlLineInfoProvider xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
if (xmlLineInfoProvider == null)
{
return new XmlLineInfo();
}
return xmlLineInfoProvider.XmlLineInfo;
}
}
public class AppThemeBindingReflection
{
private static readonly Type appThemeBindingType;
private static readonly PropertyInfo lightPropertyInfo;
private static readonly PropertyInfo darkPropertyInfo;
private static readonly PropertyInfo defaultPropertyInfo;
static AppThemeBindingReflection()
{
var types = typeof(OnPlatform<>).Assembly.GetTypes();
appThemeBindingType = types.First(t => t.Name == "AppThemeBinding");
lightPropertyInfo = appThemeBindingType.GetProperty("Light");
darkPropertyInfo = appThemeBindingType.GetProperty("Dark");
defaultPropertyInfo = appThemeBindingType.GetProperty("Default");
}
public BindingBase AppThemeBinding { get; }
public AppThemeBindingReflection()
{
AppThemeBinding = (BindingBase)Activator.CreateInstance(appThemeBindingType);
}
public void SetLight(object value)
{
lightPropertyInfo.SetValue(AppThemeBinding, value);
}
public void SetDark(object value)
{
darkPropertyInfo.SetValue(AppThemeBinding, value);
}
public void SetDefault(object value)
{
defaultPropertyInfo.SetValue(AppThemeBinding, value);
}
}
[ContentProperty("Default")]
public class AppThemeBindingInMultiBindingExtension : IMarkupExtension<BindingBase>
{
#region reflection
private static readonly Type iValueConverterProviderType;
private static readonly MethodInfo convertWithValueConverterMethodInfo;
private static readonly MethodInfo convertToMethodInfo;
#endregion
static AppThemeBindingInMultiBindingExtension()
{
var types = typeof(OnPlatform<>).Assembly.GetTypes();
var typeConverterExtensionsType = types.First(t => t.Name == "TypeConversionExtensions");
convertToMethodInfo = typeConverterExtensionsType.GetMethods(BindingFlags.Static | BindingFlags.NonPublic).First(m => m.GetParameters()[2].ParameterType == typeof(Func<MemberInfo>));
iValueConverterProviderType = types.First(t => t.Name == "IValueConverterProvider");
convertWithValueConverterMethodInfo = iValueConverterProviderType.GetMethod("Convert");
}
#region light, dark, default
private object _default;
private bool _hasdefault;
private object _light;
private bool _haslight;
private object _dark;
private bool _hasdark;
public object Default
{
get
{
return _default;
}
set
{
_default = value;
_hasdefault = true;
}
}
public object Light
{
get
{
return _light;
}
set
{
_light = value;
_haslight = true;
}
}
public object Dark
{
get
{
return _dark;
}
set
{
_dark = value;
_hasdark = true;
}
}
#endregion
public BindableProperty BindableProperty { get; set; }
private BindingBase GetConfiguredAppThemeBinding(Func<object,object> converter)
{
var appThemeBindingReflection = new AppThemeBindingReflection();
if (_haslight)
{
appThemeBindingReflection.SetLight(converter(Light));
}
if (_hasdark)
{
appThemeBindingReflection.SetDark(converter(Dark));
}
if (_hasdefault)
{
appThemeBindingReflection.SetDefault(converter(Default));
}
return appThemeBindingReflection.AppThemeBinding;
}
private BindingBase WithoutConversion()
{
return GetConfiguredAppThemeBinding(themeValue => themeValue);
}
private BindingBase WithConversion(IServiceProvider serviceProvider)
{
var toType = BindableProperty.ReturnType;
object valueConverterProvider = serviceProvider.GetService(iValueConverterProviderType);
Func<object, object> convertWithValueConverterProvider = themeValue => convertWithValueConverterMethodInfo.Invoke(valueConverterProvider, new object[] { themeValue, toType, (Func<MemberInfo>)minforetriever, serviceProvider });
Func<object, object> converter = valueConverterProvider == null ? convertWithValueConverterProvider :
themeValue =>
{
var args = new object[] { themeValue, toType, (Func<MemberInfo>)minforetriever, serviceProvider, null };
var converted = convertToMethodInfo.Invoke(null, args);
var exception = (Exception)args[4];
if (exception != null)
{
throw exception;
}
return converted;
};
return GetConfiguredAppThemeBinding(converter);
MemberInfo minforetriever()
{
MemberInfo memberInfo = null;
try
{
memberInfo = BindableProperty.DeclaringType.GetRuntimeProperty(BindableProperty.PropertyName);
}
catch (AmbiguousMatchException innerException)
{
throw XamlParseExceptionLineInfoHelper.CreateException($"Multiple properties with name '{BindableProperty.DeclaringType}.{BindableProperty.PropertyName}' found.", serviceProvider, innerException);
}
if (memberInfo != null)
{
return memberInfo;
}
try
{
return BindableProperty.DeclaringType.GetRuntimeMethod("Get" + BindableProperty.PropertyName, new Type[1]
{
typeof(BindableObject)
});
}
catch (AmbiguousMatchException innerException2)
{
throw XamlParseExceptionLineInfoHelper.CreateException($"Multiple methods with name '{BindableProperty.DeclaringType}.Get{BindableProperty.PropertyName}' found.", serviceProvider, innerException2);
}
}
}
public object ProvideValue(IServiceProvider serviceProvider)
{
return ((IMarkupExtension<BindingBase>)this).ProvideValue(serviceProvider);
}
BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceProvider)
{
if (Default == null && Light == null && Dark == null)
{
throw XamlParseExceptionLineInfoHelper.CreateException("AppThemeBindingExtension requires a non-null value to be specified for at least one theme or Default.", serviceProvider);
}
if (BindableProperty == null)
{
return WithoutConversion();
}
return WithConversion(serviceProvider);
}
}
The text was updated successfully, but these errors were encountered:
Description
AppThemeBindingExtension does not work in a MultiBinding as conversion code needs the property type ( and targetObject is the MultiBinding, targetProperty isnull ) -
Xamarin.Forms/Xamarin.Forms.Xaml/MarkupExtensions/AppThemeBindingExtension.cs
Line 67 in caab66b
Steps to Reproduce
<Label.TextColor> <MultiBinding Converter="{StaticResource MyConverter}"> <Binding Path="ServerReceiver"/> <AppThemeBinding Light="Black" Dark="White" /> </MultiBinding> </Label.TextColor>
Expected Behavior
Given the extension returns a BindingBase it should be usable in a MultiBinding Bindings property -
IList<BindingBase>
Actual Behavior
"Cannot determine property to provide the value for."
Basic Information
Workaround
Create a new extension - AppThemeBindingInMultiBindingExtension
Reflection due to internals.
Markup extension service IValueConverterProvider is internal.
TypeConversionExtensions is internal.
AppThemeBinding is internal.
Provide the property type for conversion or don't convert.
The text was updated successfully, but these errors were encountered: