Browse Source

Refactored binding somewhat.

- Simplified PerpsexObject interface to a simplified single interface,
IPerspexObject
- Moved GetObservable etc to extension method
pull/396/head
Steven Kirk 11 years ago
parent
commit
30a756fb83
  1. 2
      samples/TestApplicationShared/GalleryStyle.cs
  2. 49
      src/Markup/Perspex.Markup.Xaml/Data/Binding.cs
  3. 4
      src/Markup/Perspex.Markup.Xaml/Data/IXamlBinding.cs
  4. 6
      src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs
  5. 4
      src/Perspex.Animation/Animate.cs
  6. 95
      src/Perspex.Base/IObservablePropertyBag.cs
  7. 60
      src/Perspex.Base/IPerspexObject.cs
  8. 3
      src/Perspex.Base/Perspex.Base.csproj
  9. 93
      src/Perspex.Base/PerspexObject.cs
  10. 140
      src/Perspex.Base/PerspexObjectExtensions.cs
  11. 4
      src/Perspex.Controls/Presenters/ScrollContentPresenter.cs
  12. 8
      src/Perspex.Controls/Presenters/TextPresenter.cs
  13. 2
      src/Perspex.Controls/Primitives/AccessText.cs
  14. 8
      src/Perspex.Controls/Primitives/ScrollBar.cs
  15. 2
      src/Perspex.Controls/Primitives/TemplatedControl.cs
  16. 2
      src/Perspex.Controls/Primitives/Track.cs
  17. 2
      src/Perspex.Controls/RadioButton.cs
  18. 10
      src/Perspex.Controls/ScrollViewer.cs
  19. 8
      src/Perspex.Controls/TextBlock.cs
  20. 4
      src/Perspex.Controls/TextBox.cs
  21. 4
      src/Perspex.Controls/TopLevel.cs
  22. 2
      src/Perspex.Diagnostics/DevTools.cs
  23. 2
      src/Perspex.Diagnostics/Views/ControlDetailsView.cs
  24. 2
      src/Perspex.Diagnostics/Views/LogicalTreeView.cs
  25. 2
      src/Perspex.Diagnostics/Views/VisualTreeView.cs
  26. 4
      src/Perspex.SceneGraph/Animation/CrossFade.cs
  27. 2
      src/Perspex.SceneGraph/Media/MatrixTransform.cs
  28. 2
      src/Perspex.SceneGraph/Media/RotateTransform.cs
  29. 4
      src/Perspex.SceneGraph/Media/TranslateTransform.cs
  30. 2
      src/Perspex.Styling/Styling/IStyleable.cs
  31. 9
      src/Perspex.Styling/Styling/ITemplatedControl.cs
  32. 2
      src/Perspex.Styling/Styling/Selectors.cs
  33. 124
      tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs
  34. 40
      tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs
  35. 5
      tests/Perspex.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs
  36. 53
      tests/Perspex.Styling.UnitTests/SelectorTests_Child.cs
  37. 52
      tests/Perspex.Styling.UnitTests/SelectorTests_Descendent.cs
  38. 53
      tests/Perspex.Styling.UnitTests/TestControlBase.cs
  39. 57
      tests/Perspex.Styling.UnitTests/TestTemplatedControl.cs

2
samples/TestApplicationShared/GalleryStyle.cs

@ -23,7 +23,7 @@ namespace TestApplication
{
Setters = new[]
{
new Setter (TemplatedControl.TemplateProperty, new FuncControlTemplate<TabControl> (TabControlTemplate))
new Setter (TemplatedControl.TemplateProperty, new FuncControlTemplate<TabControl>(TabControlTemplate))
}
},

49
src/Markup/Perspex.Markup.Xaml/Data/Binding.cs

@ -55,7 +55,7 @@ namespace Perspex.Markup.Xaml.Data
/// </summary>
/// <param name="instance">The target instance.</param>
/// <param name="property">The target property.</param>
public void Bind(IObservablePropertyBag instance, PerspexProperty property)
public void Bind(IPerspexObject instance, PerspexProperty property)
{
Contract.Requires<ArgumentNullException>(instance != null);
Contract.Requires<ArgumentNullException>(property != null);
@ -67,7 +67,8 @@ namespace Perspex.Markup.Xaml.Data
if (subject != null)
{
Bind(instance, property, subject);
var mode = Mode == BindingMode.Default ? property.DefaultBindingMode : Mode;
instance.Bind(property, subject, mode, Priority);
}
}
@ -81,7 +82,7 @@ namespace Perspex.Markup.Xaml.Data
/// </param>
/// <returns>An <see cref="ISubject{object}"/>.</returns>
public ISubject<object> CreateSubject(
IObservablePropertyBag target,
IPerspexObject target,
Type targetType,
bool targetIsDataContext = false)
{
@ -125,42 +126,6 @@ namespace Perspex.Markup.Xaml.Data
ConverterParameter);
}
/// <summary>
/// Applies a binding subject to a property on an instance.
/// </summary>
/// <param name="target">The target instance.</param>
/// <param name="property">The target property.</param>
/// <param name="subject">The binding subject.</param>
internal void Bind(IObservablePropertyBag target, PerspexProperty property, ISubject<object> subject)
{
Contract.Requires<ArgumentNullException>(target != null);
Contract.Requires<ArgumentNullException>(property != null);
Contract.Requires<ArgumentNullException>(subject != null);
var mode = Mode == BindingMode.Default ?
property.DefaultBindingMode : Mode;
switch (mode)
{
case BindingMode.Default:
case BindingMode.OneWay:
target.Bind(property, subject, Priority);
break;
case BindingMode.TwoWay:
target.BindTwoWay(property, subject, Priority);
break;
case BindingMode.OneTime:
target.GetObservable(Control.DataContextProperty).Subscribe(dataContext =>
{
subject.Take(1).Subscribe(x => target.SetValue(property, x, Priority));
});
break;
case BindingMode.OneWayToSource:
target.GetObservable(property).Subscribe(subject);
break;
}
}
private static PathInfo ParsePath(string path)
{
var result = new PathInfo();
@ -209,7 +174,7 @@ namespace Perspex.Markup.Xaml.Data
}
private ExpressionObserver CreateDataContextSubject(
IObservablePropertyBag target,
IPerspexObject target,
string path,
bool targetIsDataContext)
{
@ -231,7 +196,7 @@ namespace Perspex.Markup.Xaml.Data
{
return new ExpressionObserver(
target.GetObservable(Visual.VisualParentProperty)
.OfType<IObservablePropertyBag>()
.OfType<IPerspexObject>()
.Select(x => x.GetObservable(Control.DataContextProperty))
.Switch(),
path);
@ -239,7 +204,7 @@ namespace Perspex.Markup.Xaml.Data
}
private ExpressionObserver CreateTemplatedParentSubject(
IObservablePropertyBag target,
IPerspexObject target,
string path)
{
Contract.Requires<ArgumentNullException>(target != null);

4
src/Markup/Perspex.Markup.Xaml/Data/IXamlBinding.cs

@ -16,7 +16,7 @@ namespace Perspex.Markup.Xaml.Data
/// </summary>
/// <param name="instance">The target instance.</param>
/// <param name="property">The target property.</param>
void Bind(IObservablePropertyBag instance, PerspexProperty property);
void Bind(IPerspexObject instance, PerspexProperty property);
/// <summary>
/// Creates a subject that can be used to get and set the value of the binding.
@ -28,7 +28,7 @@ namespace Perspex.Markup.Xaml.Data
/// </param>
/// <returns>An <see cref="ISubject{object}"/>.</returns>
ISubject<object> CreateSubject(
IObservablePropertyBag target,
IPerspexObject target,
Type targetType,
bool targetIsDataContext = false);
}

6
src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs

@ -48,7 +48,7 @@ namespace Perspex.Markup.Xaml.Data
/// </summary>
/// <param name="instance">The target instance.</param>
/// <param name="property">The target property.</param>
public void Bind(IObservablePropertyBag instance, PerspexProperty property)
public void Bind(IPerspexObject instance, PerspexProperty property)
{
var subject = CreateSubject(instance, property.PropertyType);
@ -68,7 +68,7 @@ namespace Perspex.Markup.Xaml.Data
/// </param>
/// <returns>An <see cref="ISubject{object}"/>.</returns>
public ISubject<object> CreateSubject(
IObservablePropertyBag target,
IPerspexObject target,
Type targetType,
bool targetIsDataContext = false)
{
@ -91,7 +91,7 @@ namespace Perspex.Markup.Xaml.Data
/// <param name="target">The target instance.</param>
/// <param name="property">The target property.</param>
/// <param name="subject">The binding subject.</param>
internal void Bind(IObservablePropertyBag target, PerspexProperty property, ISubject<object> subject)
internal void Bind(IPerspexObject target, PerspexProperty property, ISubject<object> subject)
{
var mode = Mode == BindingMode.Default ?
property.DefaultBindingMode : Mode;

4
src/Perspex.Animation/Animate.cs

@ -96,7 +96,7 @@ namespace Perspex.Animation
/// <param name="duration">The duration of the animation.</param>
/// <returns>An <see cref="Animation"/> that can be used to track or stop the animation.</returns>
public static Animation Property(
IObservablePropertyBag target,
IPerspexObject target,
PerspexProperty property,
object start,
object finish,
@ -119,7 +119,7 @@ namespace Perspex.Animation
/// <param name="duration">The duration of the animation.</param>
/// <returns>An <see cref="Animation"/> that can be used to track or stop the animation.</returns>
public static Animation<T> Property<T>(
IObservablePropertyBag target,
IPerspexObject target,
PerspexProperty<T> property,
T start,
T finish,

95
src/Perspex.Base/IObservablePropertyBag.cs

@ -1,95 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Subjects;
namespace Perspex
{
/// <summary>
/// Interface for getting/setting <see cref="PerspexProperty"/> bindings on an object.
/// </summary>
public interface IObservablePropertyBag : IPropertyBag
{
/// <summary>
/// Binds a <see cref="PerspexProperty"/> to an observable.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="source">The observable.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
IDisposable Bind(
PerspexProperty property,
IObservable<object> source,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Binds a <see cref="PerspexProperty"/> to an observable.
/// </summary>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="property">The property.</param>
/// <param name="source">The observable.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
IDisposable Bind<T>(
PerspexProperty<T> property,
IObservable<T> source,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Initiates a two-way binding between <see cref="PerspexProperty"/>s.
/// </summary>
/// <param name="property">The property on this object.</param>
/// <param name="source">The source object.</param>
/// <param name="sourceProperty">The property on the source object.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
/// <remarks>
/// The binding is first carried out from <paramref name="source"/> to this.
/// </remarks>
IDisposable BindTwoWay(
PerspexProperty property,
PerspexObject source,
PerspexProperty sourceProperty,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Initiates a two-way binding between a <see cref="PerspexProperty"/> and an
/// <see cref="ISubject{Object}"/>.
/// </summary>
/// <param name="property">The property on this object.</param>
/// <param name="source">The subject to bind to.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
/// <remarks>
/// The binding is first carried out from <paramref name="source"/> to this.
/// </remarks>
IDisposable BindTwoWay(
PerspexProperty property,
ISubject<object> source,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>An observable.</returns>
IObservable<object> GetObservable(PerspexProperty property);
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="property">The property.</param>
/// <returns>An observable.</returns>
IObservable<T> GetObservable<T>(PerspexProperty<T> property);
}
}

60
src/Perspex.Base/IPropertyBag.cs → src/Perspex.Base/IPerspexObject.cs

@ -1,23 +1,19 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Perspex
{
/// <summary>
/// Interface for getting/setting <see cref="PerspexProperty"/> values on an object.
/// </summary>
public interface IPropertyBag
public interface IPerspexObject
{
/// <summary>
/// Gets the object that inherited <see cref="PerspexProperty"/> values are inherited from.
/// Raised when a <see cref="PerspexProperty"/> value changes on this object.
/// </summary>
IPropertyBag InheritanceParent { get; }
/// <summary>
/// Clears a <see cref="PerspexProperty"/>'s local value.
/// </summary>
/// <param name="property">The property.</param>
void ClearValue(PerspexProperty property);
event EventHandler<PerspexPropertyChangedEventArgs> PropertyChanged;
/// <summary>
/// Gets a <see cref="PerspexProperty"/> value.
@ -34,13 +30,6 @@ namespace Perspex
/// <returns>The value.</returns>
T GetValue<T>(PerspexProperty<T> property);
/// <summary>
/// Checks whether a <see cref="PerspexProperty"/> is registered on this object.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>True if the property is registered, otherwise false.</returns>
bool IsRegistered(PerspexProperty property);
/// <summary>
/// Checks whether a <see cref="PerspexProperty"/> is set on this object.
/// </summary>
@ -54,7 +43,10 @@ namespace Perspex
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <param name="priority">The priority of the value.</param>
void SetValue(PerspexProperty property, object value, BindingPriority priority = BindingPriority.LocalValue);
void SetValue(
PerspexProperty property,
object value,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Sets a <see cref="PerspexProperty"/> value.
@ -63,6 +55,38 @@ namespace Perspex
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <param name="priority">The priority of the value.</param>
void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue);
void SetValue<T>(
PerspexProperty<T> property,
T value,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Binds a <see cref="PerspexProperty"/> to an observable.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="source">The observable.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
IDisposable Bind(
PerspexProperty property,
IObservable<object> source,
BindingPriority priority = BindingPriority.LocalValue);
/// <summary>
/// Binds a <see cref="PerspexProperty"/> to an observable.
/// </summary>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="property">The property.</param>
/// <param name="source">The observable.</param>
/// <param name="priority">The priority of the binding.</param>
/// <returns>
/// A disposable which can be used to terminate the binding.
/// </returns>
IDisposable Bind<T>(
PerspexProperty<T> property,
IObservable<T> source,
BindingPriority priority = BindingPriority.LocalValue);
}
}

3
src/Perspex.Base/Perspex.Base.csproj

@ -45,8 +45,7 @@
<Compile Include="BindingDescriptor.cs" />
<Compile Include="Collections\PerspexDictionary.cs" />
<Compile Include="Diagnostics\PerspexObjectExtensions.cs" />
<Compile Include="IObservablePropertyBag.cs" />
<Compile Include="IPropertyBag.cs" />
<Compile Include="IPerspexObject.cs" />
<Compile Include="Metadata\ContentAttribute.cs" />
<Compile Include="PerspexDisposable.cs" />
<Compile Include="PerspexLocator.cs" />

93
src/Perspex.Base/PerspexObject.cs

@ -23,7 +23,7 @@ namespace Perspex
/// <remarks>
/// This class is analogous to DependencyObject in WPF.
/// </remarks>
public class PerspexObject : IObservablePropertyBag, INotifyPropertyChanged
public class PerspexObject : IPerspexObject, INotifyPropertyChanged
{
/// <summary>
/// The parent object that inherited values are inherited from.
@ -89,11 +89,6 @@ namespace Perspex
remove { _inpcChanged -= value; }
}
/// <summary>
/// Gets the object that inherited <see cref="PerspexProperty"/> values are inherited from.
/// </summary>
IPropertyBag IPropertyBag.InheritanceParent => InheritanceParent;
/// <summary>
/// Gets or sets the parent object that inherited <see cref="PerspexProperty"/> values
/// are inherited from.
@ -188,7 +183,7 @@ namespace Perspex
SetValue(binding.Property, sourceBinding.Source.GetValue(sourceBinding.Property), binding.Priority);
break;
case BindingMode.OneWayToSource:
sourceBinding.Source.Bind(sourceBinding.Property, GetObservable(binding.Property), binding.Priority);
sourceBinding.Source.Bind(sourceBinding.Property, this.GetObservable(binding.Property), binding.Priority);
break;
case BindingMode.TwoWay:
BindTwoWay(binding.Property, sourceBinding.Source, sourceBinding.Property);
@ -223,81 +218,6 @@ namespace Perspex
SetValue(property, PerspexProperty.UnsetValue);
}
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>An observable.</returns>
public IObservable<object> GetObservable(PerspexProperty property)
{
Contract.Requires<ArgumentNullException>(property != null);
return new PerspexObservable<object>(
observer =>
{
EventHandler<PerspexPropertyChangedEventArgs> handler = (s, e) =>
{
if (e.Property == property)
{
observer.OnNext(e.NewValue);
}
};
observer.OnNext(GetValue(property));
PropertyChanged += handler;
return Disposable.Create(() =>
{
PropertyChanged -= handler;
});
},
GetDescription(property));
}
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <typeparam name="T">The property type.</typeparam>
/// <param name="property">The property.</param>
/// <returns>An observable.</returns>
public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
{
Contract.Requires<ArgumentNullException>(property != null);
return GetObservable((PerspexProperty)property).Cast<T>();
}
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="property">The property.</param>
/// <returns>An observable which when subscribed pushes the old and new values of the
/// property each time it is changed.</returns>
public IObservable<Tuple<T, T>> GetObservableWithHistory<T>(PerspexProperty<T> property)
{
return new PerspexObservable<Tuple<T, T>>(
observer =>
{
EventHandler<PerspexPropertyChangedEventArgs> handler = (s, e) =>
{
if (e.Property == property)
{
observer.OnNext(Tuple.Create((T)e.OldValue, (T)e.NewValue));
}
};
PropertyChanged += handler;
return Disposable.Create(() =>
{
PropertyChanged -= handler;
});
},
GetDescription(property));
}
/// <summary>
/// Gets a <see cref="PerspexProperty"/> value.
/// </summary>
@ -589,7 +509,7 @@ namespace Perspex
return new CompositeDisposable(
Bind(property, source.GetObservable(sourceProperty)),
source.Bind(sourceProperty, GetObservable(property)));
source.Bind(sourceProperty, this.GetObservable(property)));
}
/// <summary>
@ -619,7 +539,7 @@ namespace Perspex
return new CompositeDisposable(
Bind(property, source),
GetObservable(property).Subscribe(source));
this.GetObservable(property).Subscribe(source));
}
/// <summary>
@ -638,11 +558,6 @@ namespace Perspex
}
/// <inheritdoc/>
bool IPropertyBag.IsRegistered(PerspexProperty property)
{
return PerspexPropertyRegistry.Instance.IsRegistered(this, property);
}
/// <summary>
/// Gets all priority values set on the object.
/// </summary>

140
src/Perspex.Base/PerspexObjectExtensions.cs

@ -2,8 +2,10 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Perspex.Reactive;
namespace Perspex
{
@ -12,6 +14,131 @@ namespace Perspex
/// </summary>
public static class PerspexObjectExtensions
{
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <param name="o">The object.</param>
/// <param name="property">The property.</param>
/// <returns>An observable.</returns>
public static IObservable<object> GetObservable(this IPerspexObject o, PerspexProperty property)
{
Contract.Requires<ArgumentNullException>(o != null);
Contract.Requires<ArgumentNullException>(property != null);
return new PerspexObservable<object>(
observer =>
{
EventHandler<PerspexPropertyChangedEventArgs> handler = (s, e) =>
{
if (e.Property == property)
{
observer.OnNext(e.NewValue);
}
};
observer.OnNext(o.GetValue(property));
o.PropertyChanged += handler;
return Disposable.Create(() =>
{
o.PropertyChanged -= handler;
});
},
GetDescription(o, property));
}
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <param name="o">The object.</param>
/// <typeparam name="T">The property type.</typeparam>
/// <param name="property">The property.</param>
/// <returns>An observable.</returns>
public static IObservable<T> GetObservable<T>(this IPerspexObject o, PerspexProperty<T> property)
{
Contract.Requires<ArgumentNullException>(o != null);
Contract.Requires<ArgumentNullException>(property != null);
return o.GetObservable((PerspexProperty)property).Cast<T>();
}
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <param name="o">The object.</param>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="property">The property.</param>
/// <returns>
/// An observable which when subscribed pushes the old and new values of the property each
/// time it is changed.
/// </returns>
public static IObservable<Tuple<T, T>> GetObservableWithHistory<T>(
this IPerspexObject o,
PerspexProperty<T> property)
{
Contract.Requires<ArgumentNullException>(o != null);
Contract.Requires<ArgumentNullException>(property != null);
return new PerspexObservable<Tuple<T, T>>(
observer =>
{
EventHandler<PerspexPropertyChangedEventArgs> handler = (s, e) =>
{
if (e.Property == property)
{
observer.OnNext(Tuple.Create((T)e.OldValue, (T)e.NewValue));
}
};
o.PropertyChanged += handler;
return Disposable.Create(() =>
{
o.PropertyChanged -= handler;
});
},
GetDescription(o, property));
}
/// <summary>
/// Binds a property to a subject according to a <see cref="BindingMode"/>.
/// </summary>
/// <param name="o">The object.</param>
/// <param name="property">The property to bind.</param>
/// <param name="source">The binding source.</param>
/// <param name="mode">The binding mode.</param>
/// <param name="priority">The binding priority.</param>
/// <returns></returns>
public static IDisposable Bind(
this IPerspexObject o,
PerspexProperty property,
ISubject<object> source,
BindingMode mode,
BindingPriority priority = BindingPriority.LocalValue)
{
Contract.Requires<ArgumentNullException>(o != null);
Contract.Requires<ArgumentNullException>(property != null);
Contract.Requires<ArgumentNullException>(source != null);
switch (mode)
{
case BindingMode.Default:
case BindingMode.OneWay:
return o.Bind(property, source, priority);
case BindingMode.TwoWay:
return new CompositeDisposable(
o.Bind(property, source, priority),
o.GetObservable(property).Subscribe(source));
case BindingMode.OneTime:
return source.Take(1).Subscribe(x => o.SetValue(property, x, priority));
case BindingMode.OneWayToSource:
return o.GetObservable(property).Subscribe(source);
default:
throw new ArgumentException("Invalid binding mode.");
}
}
/// <summary>
/// Subscribes to a property changed notifications for changes that originate from a
/// <typeparamref name="TTarget"/>.
@ -52,6 +179,17 @@ namespace Perspex
return observable.Subscribe(e => SubscribeAdapter(e, handler));
}
/// <summary>
/// Gets a description of a property that van be used in observables.
/// </summary>
/// <param name="o">The object.</param>
/// <param name="property">The property</param>
/// <returns>The description.</returns>
private static string GetDescription(IPerspexObject o, PerspexProperty property)
{
return $"{o.GetType().Name}.{property.Name}";
}
/// <summary>
/// Observer method for <see cref="AddClassHandler{TTarget}(IObservable{PerspexPropertyChangedEventArgs},
/// Func{TTarget, Action{PerspexPropertyChangedEventArgs}})"/>.

4
src/Perspex.Controls/Presenters/ScrollContentPresenter.cs

@ -61,7 +61,7 @@ namespace Perspex.Controls.Presenters
{
AddHandler(RequestBringIntoViewEvent, BringIntoViewRequested);
GetObservable(ChildProperty).Subscribe(ChildChanged);
this.GetObservable(ChildProperty).Subscribe(ChildChanged);
}
/// <summary>
@ -236,7 +236,7 @@ namespace Perspex.Controls.Presenters
{
scrollable.InvalidateScroll = () => UpdateFromScrollable(scrollable);
_scrollableSubscription = new CompositeDisposable(
GetObservable(OffsetProperty).Skip(1).Subscribe(x => scrollable.Offset = x),
this.GetObservable(OffsetProperty).Skip(1).Subscribe(x => scrollable.Offset = x),
Disposable.Create(() => scrollable.InvalidateScroll = null));
UpdateFromScrollable(scrollable);
}

8
src/Perspex.Controls/Presenters/TextPresenter.cs

@ -33,15 +33,15 @@ namespace Perspex.Controls.Presenters
_caretTimer.Interval = TimeSpan.FromMilliseconds(500);
_caretTimer.Tick += CaretTimerTick;
_canScrollHorizontally = GetObservable(TextWrappingProperty)
_canScrollHorizontally = this.GetObservable(TextWrappingProperty)
.Select(x => x == TextWrapping.NoWrap);
Observable.Merge(
GetObservable(SelectionStartProperty),
GetObservable(SelectionEndProperty))
this.GetObservable(SelectionStartProperty),
this.GetObservable(SelectionEndProperty))
.Subscribe(_ => InvalidateFormattedText());
GetObservable(CaretIndexProperty)
this.GetObservable(CaretIndexProperty)
.Subscribe(CaretIndexChanged);
}

2
src/Perspex.Controls/Primitives/AccessText.cs

@ -37,7 +37,7 @@ namespace Perspex.Controls.Primitives
/// </summary>
public AccessText()
{
GetObservable(TextProperty).Subscribe(TextChanged);
this.GetObservable(TextProperty).Subscribe(TextChanged);
}
/// <summary>

8
src/Perspex.Controls/Primitives/ScrollBar.cs

@ -36,10 +36,10 @@ namespace Perspex.Controls.Primitives
public ScrollBar()
{
var isVisible = Observable.Merge(
GetObservable(MinimumProperty).Select(_ => Unit.Default),
GetObservable(MaximumProperty).Select(_ => Unit.Default),
GetObservable(ViewportSizeProperty).Select(_ => Unit.Default),
GetObservable(VisibilityProperty).Select(_ => Unit.Default))
this.GetObservable(MinimumProperty).Select(_ => Unit.Default),
this.GetObservable(MaximumProperty).Select(_ => Unit.Default),
this.GetObservable(ViewportSizeProperty).Select(_ => Unit.Default),
this.GetObservable(VisibilityProperty).Select(_ => Unit.Default))
.Select(_ => CalculateIsVisible());
Bind(IsVisibleProperty, isVisible, BindingPriority.Style);
}

2
src/Perspex.Controls/Primitives/TemplatedControl.cs

@ -231,7 +231,7 @@ namespace Perspex.Controls.Primitives
// If the binding is a template binding, then complete when the Template changes.
if (source.Priority == BindingPriority.TemplatedParent)
{
var templateChanged = GetObservable(TemplateProperty).Skip(1);
var templateChanged = this.GetObservable(TemplateProperty).Skip(1);
result.SourceObservable = result.Source.GetObservable(result.Property)
.TakeUntil(templateChanged);

2
src/Perspex.Controls/Primitives/Track.cs

@ -38,7 +38,7 @@ namespace Perspex.Controls.Primitives
public Track()
{
GetObservableWithHistory(ThumbProperty).Subscribe(val =>
this.GetObservableWithHistory(ThumbProperty).Subscribe(val =>
{
if (val.Item1 != null)
{

2
src/Perspex.Controls/RadioButton.cs

@ -12,7 +12,7 @@ namespace Perspex.Controls
{
public RadioButton()
{
GetObservable(IsCheckedProperty).Subscribe(IsCheckedChanged);
this.GetObservable(IsCheckedProperty).Subscribe(IsCheckedChanged);
}
protected override void Toggle()

10
src/Perspex.Controls/ScrollViewer.cs

@ -135,8 +135,8 @@ namespace Perspex.Controls
public ScrollViewer()
{
var extentAndViewport = Observable.CombineLatest(
GetObservable(ExtentProperty),
GetObservable(ViewportProperty))
this.GetObservable(ExtentProperty),
this.GetObservable(ViewportProperty))
.Select(x => new { Extent = x[0], Viewport = x[1] });
Bind(
@ -155,15 +155,15 @@ namespace Perspex.Controls
VerticalScrollBarMaximumProperty,
extentAndViewport.Select(x => Max(x.Extent.Height - x.Viewport.Height, 0)));
GetObservable(OffsetProperty).Subscribe(x =>
this.GetObservable(OffsetProperty).Subscribe(x =>
{
SetValue(HorizontalScrollBarValueProperty, x.X);
SetValue(VerticalScrollBarValueProperty, x.Y);
});
var scrollBarOffset = Observable.CombineLatest(
GetObservable(HorizontalScrollBarValueProperty),
GetObservable(VerticalScrollBarValueProperty))
this.GetObservable(HorizontalScrollBarValueProperty),
this.GetObservable(VerticalScrollBarValueProperty))
.Select(x => new Vector(x[0], x[1]))
.Subscribe(x => Offset = x);
}

8
src/Perspex.Controls/TextBlock.cs

@ -106,10 +106,10 @@ namespace Perspex.Controls
public TextBlock()
{
Observable.Merge(
GetObservable(TextProperty).Select(_ => Unit.Default),
GetObservable(TextAlignmentProperty).Select(_ => Unit.Default),
GetObservable(FontSizeProperty).Select(_ => Unit.Default),
GetObservable(FontStyleProperty).Select(_ => Unit.Default))
this.GetObservable(TextProperty).Select(_ => Unit.Default),
this.GetObservable(TextAlignmentProperty).Select(_ => Unit.Default),
this.GetObservable(FontSizeProperty).Select(_ => Unit.Default),
this.GetObservable(FontStyleProperty).Select(_ => Unit.Default))
.Subscribe(_ =>
{
InvalidateFormattedText();

4
src/Perspex.Controls/TextBox.cs

@ -73,7 +73,7 @@ namespace Perspex.Controls
public TextBox()
{
var canScrollHorizontally = GetObservable(AcceptsReturnProperty)
var canScrollHorizontally = this.GetObservable(AcceptsReturnProperty)
.Select(x => !x);
Bind(
@ -81,7 +81,7 @@ namespace Perspex.Controls
canScrollHorizontally,
BindingPriority.Style);
var horizontalScrollBarVisibility = GetObservable(AcceptsReturnProperty)
var horizontalScrollBarVisibility = this.GetObservable(AcceptsReturnProperty)
.Select(x => x ? ScrollBarVisibility.Auto : ScrollBarVisibility.Hidden);
Bind(

4
src/Perspex.Controls/TopLevel.cs

@ -115,8 +115,8 @@ namespace Perspex.Controls
_accessKeyHandler?.SetOwner(this);
styler?.ApplyStyles(this);
GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl.ClientSize = x);
GetObservable(PointerOverElementProperty)
this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl.ClientSize = x);
this.GetObservable(PointerOverElementProperty)
.Select(
x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>())
.Switch().Subscribe(cursor => PlatformImpl.SetCursor(cursor?.PlatformCursor));

2
src/Perspex.Diagnostics/DevTools.cs

@ -21,7 +21,7 @@ namespace Perspex.Diagnostics
public DevTools()
{
_viewModel = new DevToolsViewModel();
GetObservable(RootProperty).Subscribe(x => _viewModel.Root = x);
this.GetObservable(RootProperty).Subscribe(x => _viewModel.Root = x);
InitializeComponent();
}

2
src/Perspex.Diagnostics/Views/ControlDetailsView.cs

@ -19,7 +19,7 @@ namespace Perspex.Diagnostics.Views
public ControlDetailsView()
{
InitializeComponent();
GetObservable(DataContextProperty)
this.GetObservable(DataContextProperty)
.Subscribe(x => ViewModel = (ControlDetailsViewModel)x);
}

2
src/Perspex.Diagnostics/Views/LogicalTreeView.cs

@ -20,7 +20,7 @@ namespace Perspex.Diagnostics.Views
public LogicalTreeView()
{
InitializeComponent();
GetObservable(DataContextProperty)
this.GetObservable(DataContextProperty)
.Subscribe(x => ViewModel = (LogicalTreeViewModel)x);
}

2
src/Perspex.Diagnostics/Views/VisualTreeView.cs

@ -21,7 +21,7 @@ namespace Perspex.Diagnostics.Views
public VisualTreeView()
{
InitializeComponent();
GetObservable(DataContextProperty)
this.GetObservable(DataContextProperty)
.Subscribe(x => ViewModel = (VisualTreeViewModel)x);
}

4
src/Perspex.SceneGraph/Animation/CrossFade.cs

@ -58,7 +58,7 @@ namespace Perspex.Animation
if (from != null)
{
tasks.Add(Animate.Property(
(IObservablePropertyBag)from,
(IPerspexObject)from,
Visual.OpacityProperty,
from.Opacity,
0,
@ -72,7 +72,7 @@ namespace Perspex.Animation
to.IsVisible = true;
tasks.Add(Animate.Property(
(IObservablePropertyBag)to,
(IPerspexObject)to,
Visual.OpacityProperty,
0,
1,

2
src/Perspex.SceneGraph/Media/MatrixTransform.cs

@ -21,7 +21,7 @@ namespace Perspex.Media
/// </summary>
public MatrixTransform()
{
GetObservable(MatrixProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(MatrixProperty).Subscribe(_ => RaiseChanged());
}
/// <summary>

2
src/Perspex.SceneGraph/Media/RotateTransform.cs

@ -21,7 +21,7 @@ namespace Perspex.Media
/// </summary>
public RotateTransform()
{
GetObservable(AngleProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(AngleProperty).Subscribe(_ => RaiseChanged());
}
/// <summary>

4
src/Perspex.SceneGraph/Media/TranslateTransform.cs

@ -27,8 +27,8 @@ namespace Perspex.Media
/// </summary>
public TranslateTransform()
{
GetObservable(XProperty).Subscribe(_ => RaiseChanged());
GetObservable(YProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(XProperty).Subscribe(_ => RaiseChanged());
this.GetObservable(YProperty).Subscribe(_ => RaiseChanged());
}
/// <summary>

2
src/Perspex.Styling/Styling/IStyleable.cs

@ -10,7 +10,7 @@ namespace Perspex.Styling
/// <summary>
/// Interface for styleable elements.
/// </summary>
public interface IStyleable : IObservablePropertyBag, INamed
public interface IStyleable : IPerspexObject, INamed
{
/// <summary>
/// Raised when the control's style should be removed.

9
src/Perspex.Styling/Styling/ITemplatedControl.cs

@ -5,14 +5,7 @@ using System;
namespace Perspex.Styling
{
public interface ITemplatedControl
public interface ITemplatedControl : IPerspexObject
{
/// <summary>
/// Gets an observable for a <see cref="PerspexProperty"/>.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="property">The property to get the observable for.</param>
/// <returns>The observable.</returns>
IObservable<T> GetObservable<T>(PerspexProperty<T> property);
}
}

2
src/Perspex.Styling/Styling/Selectors.cs

@ -240,7 +240,7 @@ namespace Perspex.Styling
private static SelectorMatch MatchPropertyEquals(IStyleable x, PerspexProperty property, object value)
{
if (!x.IsRegistered(property))
if (!PerspexPropertyRegistry.Instance.IsRegistered(x, property))
{
return SelectorMatch.False;
}

124
tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs

@ -1,14 +1,11 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Moq;
using Perspex.Controls;
using Perspex.Markup.Data;
using Perspex.Markup.Xaml.Data;
using ReactiveUI;
using Xunit;
namespace Perspex.Markup.Xaml.UnitTests.Data
@ -18,101 +15,101 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
[Fact]
public void OneWay_Binding_Should_Be_Set_Up()
{
var target = CreateTarget();
var source = new Source { Foo = "foo" };
var target = new TextBlock { DataContext = source };
var binding = new Binding
{
Path = "Foo",
Mode = BindingMode.OneWay,
};
binding.Bind(target.Object, TextBox.TextProperty);
binding.Bind(target, TextBox.TextProperty);
target.Verify(x => x.Bind(
TextBox.TextProperty,
It.IsAny<IObservable<object>>(),
BindingPriority.LocalValue));
Assert.Equal("foo", target.Text);
source.Foo = "bar";
Assert.Equal("bar", target.Text);
target.Text = "baz";
Assert.Equal("bar", source.Foo);
}
[Fact]
public void TwoWay_Binding_Should_Be_Set_Up()
{
var target = CreateTarget();
var source = new Source { Foo = "foo" };
var target = new TextBlock { DataContext = source };
var binding = new Binding
{
Path = "Foo",
Mode = BindingMode.TwoWay,
};
binding.Bind(target.Object, TextBox.TextProperty);
binding.Bind(target, TextBox.TextProperty);
target.Verify(x => x.BindTwoWay(
TextBox.TextProperty,
It.IsAny<ISubject<object>>(),
BindingPriority.LocalValue));
Assert.Equal("foo", target.Text);
source.Foo = "bar";
Assert.Equal("bar", target.Text);
target.Text = "baz";
Assert.Equal("baz", source.Foo);
}
[Fact]
public void OneTime_Binding_Should_Be_Set_Up()
{
var dataContext = new BehaviorSubject<object>(null);
var expression = new BehaviorSubject<object>(null);
var target = CreateTarget(dataContext: dataContext);
var source = new Source { Foo = "foo" };
var target = new TextBlock { DataContext = source };
var binding = new Binding
{
Path = "Foo",
Mode = BindingMode.OneTime,
};
binding.Bind(target.Object, TextBox.TextProperty, expression);
binding.Bind(target, TextBox.TextProperty);
target.Verify(x => x.SetValue(
(PerspexProperty)TextBox.TextProperty,
null,
BindingPriority.LocalValue));
target.ResetCalls();
expression.OnNext("foo");
dataContext.OnNext(1);
target.Verify(x => x.SetValue(
(PerspexProperty)TextBox.TextProperty,
"foo",
BindingPriority.LocalValue));
Assert.Equal("foo", target.Text);
source.Foo = "bar";
Assert.Equal("foo", target.Text);
target.Text = "baz";
Assert.Equal("bar", source.Foo);
}
[Fact]
public void OneWayToSource_Binding_Should_Be_Set_Up()
{
var textObservable = new Mock<IObservable<string>>();
var expression = new Mock<ISubject<object>>();
var target = CreateTarget(text: textObservable.Object);
var source = new Source { Foo = "foo" };
var target = new TextBlock { DataContext = source, Text = "bar" };
var binding = new Binding
{
Path = "Foo",
Mode = BindingMode.OneWayToSource,
};
binding.Bind(target.Object, TextBox.TextProperty, expression.Object);
binding.Bind(target, TextBox.TextProperty);
textObservable.Verify(x => x.Subscribe(expression.Object));
Assert.Equal("bar", source.Foo);
target.Text = "baz";
Assert.Equal("baz", source.Foo);
source.Foo = "quz";
Assert.Equal("baz", target.Text);
}
[Fact]
public void Default_BindingMode_Should_Be_Used()
{
var target = CreateTarget(null);
// Default for TextBox.Text is two-way.
var source = new Source { Foo = "foo" };
var target = new TextBlock { DataContext = source };
var binding = new Binding
{
Path = "Foo",
};
binding.Bind(target.Object, TextBox.TextProperty);
binding.Bind(target, TextBox.TextProperty);
// Default for TextBox.Text is two-way.
target.Verify(x => x.BindTwoWay(
TextBox.TextProperty,
It.IsAny<ISubject<object>>(),
BindingPriority.LocalValue));
Assert.Equal("foo", target.Text);
source.Foo = "bar";
Assert.Equal("bar", target.Text);
target.Text = "baz";
Assert.Equal("baz", source.Foo);
}
[Fact]
@ -164,13 +161,13 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
[Fact]
public void Should_Use_DefaultValueConverter_When_No_Converter_Specified()
{
var target = CreateTarget(null);
var target = new TextBlock(); ;
var binding = new Binding
{
Path = "Foo",
};
var result = binding.CreateSubject(target.Object, TextBox.TextProperty.PropertyType);
var result = binding.CreateSubject(target, TextBox.TextProperty.PropertyType);
Assert.IsType<DefaultValueConverter>(((ExpressionSubject)result).Converter);
}
@ -178,7 +175,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
[Fact]
public void Should_Use_Supplied_Converter()
{
var target = CreateTarget(null);
var target = new TextBlock();
var converter = new Mock<IValueConverter>();
var binding = new Binding
{
@ -186,7 +183,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
Path = "Foo",
};
var result = binding.CreateSubject(target.Object, TextBox.TextProperty.PropertyType);
var result = binding.CreateSubject(target, TextBox.TextProperty.PropertyType);
Assert.Same(converter.Object, ((ExpressionSubject)result).Converter);
}
@ -194,7 +191,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
[Fact]
public void Should_Pass_ConverterParameter_To_Supplied_Converter()
{
var target = CreateTarget();
var target = new TextBlock();
var converter = new Mock<IValueConverter>();
var binding = new Binding
{
@ -203,7 +200,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
Path = "Bar",
};
var result = binding.CreateSubject(target.Object, TextBox.TextProperty.PropertyType);
var result = binding.CreateSubject(target, TextBox.TextProperty.PropertyType);
Assert.Same("foo", ((ExpressionSubject)result).ConverterParameter);
}
@ -261,24 +258,15 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
Assert.Equal(2, vm.Bar);
}
private Mock<IObservablePropertyBag> CreateTarget(object dataContext)
{
return CreateTarget(dataContext: Observable.Never<object>().StartWith(dataContext));
}
private Mock<IObservablePropertyBag> CreateTarget(
IObservable<object> dataContext = null,
IObservable<string> text = null)
public class Source : ReactiveObject
{
var result = new Mock<IObservablePropertyBag>();
dataContext = dataContext ?? Observable.Never<object>().StartWith((object)null);
text = text ?? Observable.Never<string>().StartWith((string)null);
private string _foo;
result.Setup(x => x.GetObservable(Control.DataContextProperty)).Returns(dataContext);
result.Setup(x => x.GetObservable((PerspexProperty)Control.DataContextProperty)).Returns(dataContext);
result.Setup(x => x.GetObservable((PerspexProperty)TextBox.TextProperty)).Returns(text);
return result;
public string Foo
{
get { return _foo; }
set { this.RaiseAndSetIfChanged(ref _foo, value); }
}
}
private class OldDataContextViewModel
@ -297,7 +285,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
public OldDataContextTest()
{
Bind(BarProperty, GetObservable(FooProperty));
Bind(BarProperty, this.GetObservable(FooProperty));
}
}
}

40
tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs

@ -48,46 +48,26 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
binding.Bind(target.Object, TextBox.TextProperty);
target.Verify(x => x.BindTwoWay(
target.Verify(x => x.Bind(
TextBox.TextProperty,
It.IsAny<ISubject<object>>(),
BindingPriority.TemplatedParent));
}
[Fact]
public void OneWayToSource_Binding_Should_Be_Set_Up()
{
var textObservable = new Mock<IObservable<string>>();
var expression = new Mock<ISubject<object>>();
var target = CreateTarget(text: textObservable.Object);
var binding = new Binding
{
Path = "Foo",
Mode = BindingMode.OneWayToSource,
};
binding.Bind(target.Object, TextBox.TextProperty, expression.Object);
textObservable.Verify(x => x.Subscribe(expression.Object));
}
private Mock<IObservablePropertyBag> CreateTarget(ITemplatedControl templatedParent)
private Mock<IPerspexObject> CreateTarget(ITemplatedControl templatedParent)
{
return CreateTarget(templatedParent: Observable.Never<ITemplatedControl>().StartWith(templatedParent));
return CreateTarget(templatedParent: templatedParent);
}
private Mock<IObservablePropertyBag> CreateTarget(
IObservable<ITemplatedControl> templatedParent = null,
IObservable<string> text = null)
private Mock<IPerspexObject> CreateTarget(
ITemplatedControl templatedParent = null,
string text = null)
{
var result = new Mock<IObservablePropertyBag>();
templatedParent = templatedParent ?? Observable.Never<ITemplatedControl>().StartWith((ITemplatedControl)null);
text = text ?? Observable.Never<string>().StartWith((string)null);
var result = new Mock<IPerspexObject>();
result.Setup(x => x.GetObservable(Control.TemplatedParentProperty)).Returns(templatedParent);
result.Setup(x => x.GetObservable((PerspexProperty)Control.TemplatedParentProperty)).Returns(templatedParent);
result.Setup(x => x.GetObservable((PerspexProperty)TextBox.TextProperty)).Returns(text);
result.Setup(x => x.GetValue(Control.TemplatedParentProperty)).Returns(templatedParent);
result.Setup(x => x.GetValue((PerspexProperty)Control.TemplatedParentProperty)).Returns(templatedParent);
result.Setup(x => x.GetValue((PerspexProperty)TextBox.TextProperty)).Returns(text);
return result;
}
}

5
tests/Perspex.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Moq;
using Perspex.Controls;
using Perspex.Markup.Xaml.Data;
@ -31,10 +30,8 @@ namespace Perspex.Markup.Xaml.UnitTests.Data
}
};
var target = new Mock<IObservablePropertyBag>();
var target = new Mock<IPerspexObject>();
target.Setup(x => x.GetValue(Control.DataContextProperty)).Returns(source);
target.Setup(x => x.GetObservable(Control.DataContextProperty)).Returns(
Observable.Never<object>().StartWith(source));
var subject = binding.CreateSubject(target.Object, typeof(string));
var result = await subject.Take(1);

53
tests/Perspex.Styling.UnitTests/SelectorTests_Child.cs

@ -6,11 +6,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Styling;
using Xunit;
namespace Perspex.Styling.UnitTests
@ -80,6 +77,8 @@ namespace Perspex.Styling.UnitTests
Classes = new Classes();
}
public event EventHandler<PerspexPropertyChangedEventArgs> PropertyChanged;
public Classes Classes { get; }
public string Name { get; set; }
@ -96,42 +95,29 @@ namespace Perspex.Styling.UnitTests
IObservable<Unit> IStyleable.StyleDetach { get; }
public IPropertyBag InheritanceParent
{
get
{
throw new NotImplementedException();
}
}
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{
throw new NotImplementedException();
}
public void SetValue(PerspexProperty property, object value, BindingPriority priority)
public object GetValue(PerspexProperty property)
{
throw new NotImplementedException();
}
public IObservable<object> GetObservable(PerspexProperty property)
public T GetValue<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public bool IsRegistered(PerspexProperty property)
public void SetValue(PerspexProperty property, object value, BindingPriority priority)
{
throw new NotImplementedException();
}
public void ClearValue(PerspexProperty property)
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public object GetValue(PerspexProperty property)
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{
throw new NotImplementedException();
}
@ -145,31 +131,6 @@ namespace Perspex.Styling.UnitTests
{
throw new NotImplementedException();
}
public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public T GetValue<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, PerspexObject source, PerspexProperty sourceProperty, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, ISubject<object> source, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
}
public class TestLogical1 : TestLogical

52
tests/Perspex.Styling.UnitTests/SelectorTests_Descendent.cs

@ -5,11 +5,9 @@ using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Styling;
using Xunit;
namespace Perspex.Styling.UnitTests
@ -110,6 +108,8 @@ namespace Perspex.Styling.UnitTests
Classes = new Classes();
}
public event EventHandler<PerspexPropertyChangedEventArgs> PropertyChanged;
public Classes Classes { get; }
public string Name { get; set; }
@ -124,44 +124,31 @@ namespace Perspex.Styling.UnitTests
public ITemplatedControl TemplatedParent { get; }
public IPropertyBag InheritanceParent
{
get
{
throw new NotImplementedException();
}
}
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
IObservable<Unit> IStyleable.StyleDetach { get; }
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{
throw new NotImplementedException();
}
public void SetValue(PerspexProperty property, object value, BindingPriority priority)
public object GetValue(PerspexProperty property)
{
throw new NotImplementedException();
}
public IObservable<object> GetObservable(PerspexProperty property)
public T GetValue<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public bool IsRegistered(PerspexProperty property)
public void SetValue(PerspexProperty property, object value, BindingPriority priority)
{
throw new NotImplementedException();
}
public void ClearValue(PerspexProperty property)
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public object GetValue(PerspexProperty property)
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{
throw new NotImplementedException();
}
@ -175,31 +162,6 @@ namespace Perspex.Styling.UnitTests
{
throw new NotImplementedException();
}
public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public T GetValue<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, PerspexObject source, PerspexProperty sourceProperty, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, ISubject<object> source, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
}
public class TestLogical1 : TestLogical

53
tests/Perspex.Styling.UnitTests/TestControlBase.cs

@ -3,7 +3,6 @@
using System;
using System.Reactive;
using System.Reactive.Subjects;
using Perspex.Collections;
using Perspex.Controls;
@ -17,6 +16,8 @@ namespace Perspex.Styling.UnitTests
SubscribeCheckObservable = new TestObservable();
}
public event EventHandler<PerspexPropertyChangedEventArgs> PropertyChanged;
public string Name { get; set; }
public virtual Classes Classes { get; set; }
@ -31,79 +32,41 @@ namespace Perspex.Styling.UnitTests
set;
}
public IPropertyBag InheritanceParent
{
get
{
throw new NotImplementedException();
}
}
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
IObservable<Unit> IStyleable.StyleDetach { get; }
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{
throw new NotImplementedException();
}
public void SetValue(PerspexProperty property, object value, BindingPriority priority)
{
throw new NotImplementedException();
}
public IObservable<object> GetObservable(PerspexProperty property)
{
throw new NotImplementedException();
}
public bool IsRegistered(PerspexProperty property)
{
throw new NotImplementedException();
}
public void ClearValue(PerspexProperty property)
{
throw new NotImplementedException();
}
public object GetValue(PerspexProperty property)
{
throw new NotImplementedException();
}
public bool IsSet(PerspexProperty property)
{
throw new NotImplementedException();
}
public IDisposable Bind<T>(PerspexProperty<T> property, IObservable<T> source, BindingPriority priority = BindingPriority.LocalValue)
public T GetValue<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
public void SetValue(PerspexProperty property, object value, BindingPriority priority)
{
throw new NotImplementedException();
}
public T GetValue<T>(PerspexProperty<T> property)
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
public bool IsSet(PerspexProperty property)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, PerspexObject source, PerspexProperty sourceProperty, BindingPriority priority = BindingPriority.LocalValue)
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, ISubject<object> source, BindingPriority priority = BindingPriority.LocalValue)
public IDisposable Bind<T>(PerspexProperty<T> property, IObservable<T> source, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}

57
tests/Perspex.Styling.UnitTests/TestTemplatedControl.cs

@ -2,9 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Subjects;
using Perspex.Collections;
using Perspex.Controls;
@ -12,6 +10,8 @@ namespace Perspex.Styling.UnitTests
{
public abstract class TestTemplatedControl : ITemplatedControl, IStyleable
{
public event EventHandler<PerspexPropertyChangedEventArgs> PropertyChanged;
public abstract Classes Classes
{
get;
@ -32,29 +32,16 @@ namespace Perspex.Styling.UnitTests
get;
}
public abstract IEnumerable<IVisual> VisualChildren
{
get;
}
public IPropertyBag InheritanceParent
{
get
{
throw new NotImplementedException();
}
}
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
IObservable<Unit> IStyleable.StyleDetach { get; }
public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
public object GetValue(PerspexProperty property)
{
throw new NotImplementedException();
}
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
public T GetValue<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
@ -64,27 +51,12 @@ namespace Perspex.Styling.UnitTests
throw new NotImplementedException();
}
public IObservable<object> GetObservable(PerspexProperty property)
{
throw new NotImplementedException();
}
public bool IsRegistered(PerspexProperty property)
{
throw new NotImplementedException();
}
public void ClearValue(PerspexProperty property)
{
throw new NotImplementedException();
}
public object GetValue(PerspexProperty property)
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public bool IsSet(PerspexProperty property)
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{
throw new NotImplementedException();
}
@ -94,22 +66,7 @@ namespace Perspex.Styling.UnitTests
throw new NotImplementedException();
}
public T GetValue<T>(PerspexProperty<T> property)
{
throw new NotImplementedException();
}
public void SetValue<T>(PerspexProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, PerspexObject source, PerspexProperty sourceProperty, BindingPriority priority = BindingPriority.LocalValue)
{
throw new NotImplementedException();
}
public IDisposable BindTwoWay(PerspexProperty property, ISubject<object> source, BindingPriority priority = BindingPriority.LocalValue)
public bool IsSet(PerspexProperty property)
{
throw new NotImplementedException();
}

Loading…
Cancel
Save