diff --git a/Perspex.Base/Binding.cs b/Perspex.Base/Binding.cs
new file mode 100644
index 0000000000..702b48ae1e
--- /dev/null
+++ b/Perspex.Base/Binding.cs
@@ -0,0 +1,66 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex
+{
+ public enum BindingMode
+ {
+ Default,
+ OneWay,
+ TwoWay,
+ OneTime,
+ OneWayToSource,
+ }
+
+ public struct Binding
+ {
+ public BindingMode Mode
+ {
+ get;
+ set;
+ }
+
+ public BindingPriority Priority
+ {
+ get;
+ set;
+ }
+
+ public PerspexProperty Property
+ {
+ get;
+ set;
+ }
+
+ public PerspexObject Source
+ {
+ get;
+ set;
+ }
+
+ public static Binding operator !(Binding binding)
+ {
+ return binding.WithMode(BindingMode.TwoWay);
+ }
+
+ public static Binding operator ~(Binding binding)
+ {
+ return binding.WithMode(BindingMode.TwoWay);
+ }
+
+ public Binding WithMode(BindingMode mode)
+ {
+ this.Mode = mode;
+ return this;
+ }
+
+ public Binding WithPriority(BindingPriority priority)
+ {
+ this.Priority = priority;
+ return this;
+ }
+ }
+}
diff --git a/Perspex.Base/Contract.cs b/Perspex.Base/Contract.cs
new file mode 100644
index 0000000000..721d9f17bd
--- /dev/null
+++ b/Perspex.Base/Contract.cs
@@ -0,0 +1,23 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex
+{
+ using System;
+
+ public static class Contract
+ {
+ public static void Requires(bool condition) where TException : Exception, new()
+ {
+#if DEBUG
+ if (!condition)
+ {
+ throw new TException();
+ }
+#endif
+ }
+ }
+}
diff --git a/Perspex.Base/IDescription.cs b/Perspex.Base/IDescription.cs
new file mode 100644
index 0000000000..557c9c858f
--- /dev/null
+++ b/Perspex.Base/IDescription.cs
@@ -0,0 +1,13 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex
+{
+ public interface IDescription
+ {
+ string Description { get; }
+ }
+}
diff --git a/Perspex.Base/IObservableDescription.cs b/Perspex.Base/IObservableDescription.cs
new file mode 100644
index 0000000000..fb7fb3e415
--- /dev/null
+++ b/Perspex.Base/IObservableDescription.cs
@@ -0,0 +1,13 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex
+{
+ public interface IObservableDescription
+ {
+ string Description { get; }
+ }
+}
diff --git a/Perspex.Base/Perspex.Base.csproj b/Perspex.Base/Perspex.Base.csproj
new file mode 100644
index 0000000000..9603bdf991
--- /dev/null
+++ b/Perspex.Base/Perspex.Base.csproj
@@ -0,0 +1,85 @@
+
+
+
+
+ 11.0
+ Debug
+ AnyCPU
+ {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
+ Library
+ Properties
+ Perspex
+ Perspex.Base
+ en-US
+ 512
+ {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Profile7
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\packages\Splat.1.3.3\lib\Portable-net45+win+wpa81+wp80\Splat.dll
+
+
+ ..\packages\Rx-Core.2.1.30214.0\lib\Portable-Net45+WinRT45+WP8\System.Reactive.Core.dll
+
+
+ ..\packages\Rx-Interfaces.2.1.30214.0\lib\Portable-Net45+WinRT45+WP8\System.Reactive.Interfaces.dll
+
+
+ ..\packages\Rx-Linq.2.1.30214.0\lib\Portable-Net45+WinRT45+WP8\System.Reactive.Linq.dll
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/Perspex.Base/PerspexList.cs b/Perspex.Base/PerspexList.cs
new file mode 100644
index 0000000000..209699a388
--- /dev/null
+++ b/Perspex.Base/PerspexList.cs
@@ -0,0 +1,50 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Collections.Specialized;
+ using System.Reactive.Linq;
+
+ public class PerspexList : ObservableCollection
+ {
+ public PerspexList()
+ {
+ this.Initialize();
+ }
+
+ public PerspexList(IEnumerable items)
+ : base(items)
+ {
+ this.Initialize();
+ }
+
+ public IObservable Changed
+ {
+ get;
+ private set;
+ }
+
+ public void AddRange(IEnumerable items)
+ {
+ foreach (T item in items)
+ {
+ this.Add(item);
+ }
+ }
+
+ private void Initialize()
+ {
+ this.Changed = Observable.FromEvent(
+ handler => (sender, e) => handler(e),
+ handler => this.CollectionChanged += handler,
+ handler => this.CollectionChanged -= handler);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Perspex.Base/PerspexObject.cs b/Perspex.Base/PerspexObject.cs
new file mode 100644
index 0000000000..1cc3e4a65e
--- /dev/null
+++ b/Perspex.Base/PerspexObject.cs
@@ -0,0 +1,646 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Reactive.Linq;
+ using System.Reflection;
+ using Splat;
+
+
+ ///
+ /// The priority of a binding.
+ ///
+ public enum BindingPriority
+ {
+ ///
+ /// A local value.
+ ///
+ LocalValue,
+
+ ///
+ /// A triggered style binding.
+ ///
+ ///
+ /// A style trigger is a selector such as .class which overrides a
+ /// binding. In this way, a basic control can have
+ /// for example a Background from the templated parent which changes when the
+ /// control has the :pointerover class.
+ ///
+ StyleTrigger,
+
+ ///
+ /// A binding to a property on the templated parent.
+ ///
+ TemplatedParent,
+
+ ///
+ /// A style binding.
+ ///
+ Style,
+
+ ///
+ /// The binding is uninitialized.
+ ///
+ Unset = int.MaxValue,
+ }
+
+ ///
+ /// An object with support.
+ ///
+ ///
+ /// This class is analogous to DependencyObject in WPF.
+ ///
+ public class PerspexObject : IEnableLogger
+ {
+ ///
+ /// The registered properties by type.
+ ///
+ private static Dictionary> registered =
+ new Dictionary>();
+
+ ///
+ /// The parent object that inherited values are inherited from.
+ ///
+ private PerspexObject inheritanceParent;
+
+ ///
+ /// The set values/bindings on this object.
+ ///
+ private Dictionary values =
+ new Dictionary();
+
+ ///
+ /// Raised when a value changes on this object/
+ ///
+ public event EventHandler PropertyChanged;
+
+ ///
+ /// Gets or sets the parent object that inherited values
+ /// are inherited from.
+ ///
+ protected PerspexObject InheritanceParent
+ {
+ get
+ {
+ return this.inheritanceParent;
+ }
+
+ set
+ {
+ if (this.inheritanceParent != value)
+ {
+ if (this.inheritanceParent != null)
+ {
+ this.inheritanceParent.PropertyChanged -= this.ParentPropertyChanged;
+ }
+
+ var inherited = (from property in GetProperties(this.GetType())
+ where property.Inherits
+ select new
+ {
+ Property = property,
+ Value = this.GetValue(property),
+ }).ToList();
+
+ this.inheritanceParent = value;
+
+ foreach (var i in inherited)
+ {
+ object newValue = this.GetValue(i.Property);
+
+ if (!object.Equals(i.Value, newValue))
+ {
+ this.RaisePropertyChanged(i.Property, i.Value, newValue);
+ }
+ }
+
+ if (this.inheritanceParent != null)
+ {
+ this.inheritanceParent.PropertyChanged += this.ParentPropertyChanged;
+ }
+ }
+ }
+ }
+
+
+ ///
+ /// Gets or sets the value of a .
+ ///
+ /// The property.
+ public object this[PerspexProperty property]
+ {
+ get { return this.GetValue(property); }
+ set { this.SetValue(property, value); }
+ }
+
+ ///
+ /// Gets or sets a binding for a .
+ ///
+ /// The binding information.
+ public Binding this[Binding binding]
+ {
+ get
+ {
+ return new Binding
+ {
+ Mode = binding.Mode,
+ Priority = binding.Priority,
+ Property = binding.Property,
+ Source = this,
+ };
+ }
+
+ set
+ {
+ BindingMode mode = (binding.Mode == BindingMode.Default) ?
+ binding.Property.DefaultBindingMode :
+ binding.Mode;
+
+ switch (mode)
+ {
+ case BindingMode.Default:
+ case BindingMode.OneWay:
+ this.Bind(binding.Property, value.Source.GetObservable(value.Property), binding.Priority);
+ break;
+ case BindingMode.OneTime:
+ this.SetValue(binding.Property, value.Source.GetValue(value.Property));
+ break;
+ case BindingMode.OneWayToSource:
+ value.Source.Bind(value.Property, this.GetObservable(binding.Property), binding.Priority);
+ break;
+ case BindingMode.TwoWay:
+ this.BindTwoWay(binding.Property, value.Source, value.Property);
+ break;
+ }
+ }
+ }
+
+ ///
+ /// Gets all s registered on a type.
+ ///
+ /// The type.
+ /// A collection of definitions.
+ public static IEnumerable GetProperties(Type type)
+ {
+ Contract.Requires(type != null);
+
+ TypeInfo i = type.GetTypeInfo();
+
+ while (type != null)
+ {
+ List list;
+
+ if (registered.TryGetValue(type, out list))
+ {
+ foreach (PerspexProperty p in list)
+ {
+ yield return p;
+ }
+ }
+
+ type = type.GetTypeInfo().BaseType;
+ }
+ }
+
+ ///
+ /// Registers a on a type.
+ ///
+ /// The type.
+ /// The property.
+ ///
+ /// You won't usually want to call this method directly, instead use the
+ /// method.
+ ///
+ public static void Register(Type type, PerspexProperty property)
+ {
+ Contract.Requires(type != null);
+ Contract.Requires(property != null);
+
+ List list;
+
+ if (!registered.TryGetValue(type, out list))
+ {
+ list = new List();
+ registered.Add(type, list);
+ }
+
+ if (!list.Contains(property))
+ {
+ list.Add(property);
+ }
+ }
+
+ ///
+ /// Clears a 's local value.
+ ///
+ /// The property.
+ public void ClearValue(PerspexProperty property)
+ {
+ Contract.Requires(property != null);
+
+ this.SetValue(property, PerspexProperty.UnsetValue);
+ }
+
+ ///
+ /// Gets an observable for a .
+ ///
+ /// The property.
+ /// An observable.
+ public IObservable