diff options
Diffstat (limited to 'Xamarin.Forms.Core/MergedStyle.cs')
-rw-r--r-- | Xamarin.Forms.Core/MergedStyle.cs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/MergedStyle.cs b/Xamarin.Forms.Core/MergedStyle.cs new file mode 100644 index 00000000..9f9c68bf --- /dev/null +++ b/Xamarin.Forms.Core/MergedStyle.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Xamarin.Forms +{ + public partial class VisualElement + { + sealed class MergedStyle : IStyle + { + ////If the base type is one of these, stop registering dynamic resources further + ////The last one (typeof(Element)) is a safety guard as we might be creating VisualElement directly in internal code + static readonly IList<Type> s_stopAtTypes = new List<Type> { typeof(View), typeof(Layout<>), typeof(VisualElement), typeof(Element) }; + + readonly BindableProperty _classStyleProperty = BindableProperty.Create("ClassStyle", typeof(IList<Style>), typeof(VisualElement), default(IList<Style>), + propertyChanged: (bindable, oldvalue, newvalue) => ((VisualElement)bindable)._mergedStyle.OnClassStyleChanged()); + + readonly List<BindableProperty> _implicitStyles = new List<BindableProperty>(); + + IStyle _classStyle; + + IStyle _implicitStyle; + + IStyle _style; + + string _styleClass; + + public MergedStyle(Type targetType, BindableObject target) + { + Target = target; + TargetType = targetType; + RegisterImplicitStyles(); + Apply(Target); + } + + public IStyle Style + { + get { return _style; } + set { SetStyle(ImplicitStyle, ClassStyle, value); } + } + + public string StyleClass + { + get { return _styleClass; } + set + { + string val = string.IsNullOrWhiteSpace(value) ? null : value.Trim(); + if (_styleClass == val) + return; + + if (_styleClass != null) + Target.RemoveDynamicResource(_classStyleProperty); + + _styleClass = val; + + if (_styleClass != null) + Target.SetDynamicResource(_classStyleProperty, Forms.Style.StyleClassPrefix + _styleClass); + } + } + + public BindableObject Target { get; } + + IStyle ClassStyle + { + get { return _classStyle; } + set { SetStyle(ImplicitStyle, value, Style); } + } + + IStyle ImplicitStyle + { + get { return _implicitStyle; } + set { SetStyle(value, ClassStyle, Style); } + } + + public void Apply(BindableObject bindable) + { + ImplicitStyle?.Apply(bindable); + ClassStyle?.Apply(bindable); + Style?.Apply(bindable); + } + + public Type TargetType { get; } + + public void UnApply(BindableObject bindable) + { + Style?.UnApply(bindable); + ClassStyle?.UnApply(bindable); + ImplicitStyle?.UnApply(bindable); + } + + void OnClassStyleChanged() + { + var classStyles = Target.GetValue(_classStyleProperty) as IList<Style>; + if (classStyles == null) + ClassStyle = null; + else + { + ClassStyle = classStyles.FirstOrDefault(s => s.CanBeAppliedTo(TargetType)); + } + } + + void OnImplicitStyleChanged() + { + var first = true; + foreach (BindableProperty implicitStyleProperty in _implicitStyles) + { + var implicitStyle = (Style)Target.GetValue(implicitStyleProperty); + if (implicitStyle != null) + { + if (first || implicitStyle.ApplyToDerivedTypes) + { + ImplicitStyle = implicitStyle; + return; + } + } + first = false; + } + } + + void RegisterImplicitStyles() + { + Type type = TargetType; + while (true) + { + BindableProperty implicitStyleProperty = BindableProperty.Create("ImplicitStyle", typeof(Style), typeof(VisualElement), default(Style), + propertyChanged: (bindable, oldvalue, newvalue) => ((VisualElement)bindable)._mergedStyle.OnImplicitStyleChanged()); + Target.SetDynamicResource(implicitStyleProperty, type.FullName); + _implicitStyles.Add(implicitStyleProperty); + type = type.GetTypeInfo().BaseType; + if (s_stopAtTypes.Contains(type)) + return; + } + } + + void SetStyle(IStyle implicitStyle, IStyle classStyle, IStyle style) + { + bool shouldReApplyStyle = implicitStyle != ImplicitStyle || classStyle != ClassStyle || Style != style; + bool shouldReApplyClassStyle = implicitStyle != ImplicitStyle || classStyle != ClassStyle; + bool shouldReApplyImplicitStyle = implicitStyle != ImplicitStyle && (Style as Style == null || ((Style)Style).CanCascade); + + if (shouldReApplyStyle) + Style?.UnApply(Target); + if (shouldReApplyClassStyle) + ClassStyle?.UnApply(Target); + if (shouldReApplyImplicitStyle) + ImplicitStyle?.UnApply(Target); + + _implicitStyle = implicitStyle; + _classStyle = classStyle; + _style = style; + + if (shouldReApplyImplicitStyle) + ImplicitStyle?.Apply(Target); + if (shouldReApplyClassStyle) + ClassStyle?.Apply(Target); + if (shouldReApplyStyle) + Style?.Apply(Target); + } + } + } +}
\ No newline at end of file |