summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Core/Style.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Core/Style.cs')
-rw-r--r--Xamarin.Forms.Core/Style.cs184
1 files changed, 184 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core/Style.cs b/Xamarin.Forms.Core/Style.cs
new file mode 100644
index 00000000..8d27f010
--- /dev/null
+++ b/Xamarin.Forms.Core/Style.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace Xamarin.Forms
+{
+ [ContentProperty("Setters")]
+ public sealed class Style : IStyle
+ {
+ internal const string StyleClassPrefix = "Xamarin.Forms.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).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);
+ }
+ }
+} \ No newline at end of file