Browse Source

Merge branch 'master' into feature/1078-findancestor-bindings

pull/1085/head
Steven Kirk 9 years ago
committed by GitHub
parent
commit
261f5830f3
  1. 2
      build.cake
  2. 2
      docs/tutorial/from-wpf.md
  3. 5
      src/Avalonia.Base/Utilities/WeakObservable.cs
  4. 24
      src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
  5. 8
      src/Markup/Avalonia.Markup/Data/IndexerNode.cs
  6. 10
      src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs
  7. 7
      src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessorPlugin.cs
  8. 6
      src/Markup/Avalonia.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs
  9. 2
      src/Markup/Avalonia.Markup/Data/PropertyAccessorNode.cs
  10. 12
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_AvaloniaProperty.cs

2
build.cake

@ -193,7 +193,7 @@ Task("Run-Net-Core-Unit-Tests")
Task("Run-Unit-Tests")
.IsDependentOn("Run-Net-Core-Unit-Tests")
.IsDependentOn("Build")
.IsDependentOn("Run-Leak-Tests")
//.IsDependentOn("Run-Leak-Tests")
.WithCriteria(() => !parameters.SkipTests)
.Does(() =>
{

2
docs/tutorial/from-wpf.md

@ -161,7 +161,7 @@ the same way that event class listeners are added](../spec/working-with-properti
## RenderTransforms and RenderTransformOrigin
RenderTransformOrigins are different in WPF and Avalonia: If you apply a `RenderTransform`, keep in mind that our default value for the RenderTransformOrigin is `RelativePoint.Middle`. In WPF the default value is `RelativePoint.TopLeft` (0, 0). In controls like Viewbox (currently being developed) the same code will lead to a different rendering behavior:
RenderTransformOrigins are different in WPF and Avalonia: If you apply a `RenderTransform`, keep in mind that our default value for the RenderTransformOrigin is `RelativePoint.Center`. In WPF the default value is `RelativePoint.TopLeft` (0, 0). In controls like Viewbox (currently being developed) the same code will lead to a different rendering behavior:
In WPF:
![WPF](https://files.gitter.im/AvaloniaUI/Avalonia/cDrM/image.png)

5
src/Avalonia.Base/Utilities/WeakObservable.cs

@ -16,12 +16,13 @@ namespace Avalonia.Utilities
/// Converts a .NET event conforming to the standard .NET event pattern into an observable
/// sequence, subscribing weakly.
/// </summary>
/// <typeparam name="TTarget">The type of target.</typeparam>
/// <typeparam name="TEventArgs">The type of the event args.</typeparam>
/// <param name="target">Object instance that exposes the event to convert.</param>
/// <param name="eventName">Name of the event to convert.</param>
/// <returns></returns>
public static IObservable<EventPattern<object, TEventArgs>> FromEventPattern<TEventArgs>(
object target,
public static IObservable<EventPattern<object, TEventArgs>> FromEventPattern<TTarget, TEventArgs>(
TTarget target,
string eventName)
where TEventArgs : EventArgs
{

24
src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs

@ -17,22 +17,23 @@ namespace Avalonia.Utilities
/// <summary>
/// Subscribes to an event on an object using a weak subscription.
/// </summary>
/// <typeparam name="T">The type of the event arguments.</typeparam>
/// <typeparam name="TTarget">The type of the target.</typeparam>
/// <typeparam name="TEventArgs">The type of the event arguments.</typeparam>
/// <param name="target">The event source.</param>
/// <param name="eventName">The name of the event.</param>
/// <param name="subscriber">The subscriber.</param>
public static void Subscribe<T>(object target, string eventName, IWeakSubscriber<T> subscriber)
where T : EventArgs
public static void Subscribe<TTarget, TEventArgs>(TTarget target, string eventName, IWeakSubscriber<TEventArgs> subscriber)
where TEventArgs : EventArgs
{
var dic = SubscriptionTypeStorage<T>.Subscribers.GetOrCreateValue(target);
Subscription<T> sub;
var dic = SubscriptionTypeStorage<TEventArgs>.Subscribers.GetOrCreateValue(target);
Subscription<TEventArgs> sub;
if (!dic.TryGetValue(eventName, out sub))
{
dic[eventName] = sub = new Subscription<T>(dic, target, eventName);
dic[eventName] = sub = new Subscription<TEventArgs>(dic, typeof(TTarget), target, eventName);
}
sub.Add(new WeakReference<IWeakSubscriber<T>>(subscriber));
sub.Add(new WeakReference<IWeakSubscriber<TEventArgs>>(subscriber));
}
/// <summary>
@ -84,19 +85,18 @@ namespace Avalonia.Utilities
private WeakReference<IWeakSubscriber<T>>[] _data = new WeakReference<IWeakSubscriber<T>>[16];
private int _count = 0;
public Subscription(SubscriptionDic<T> sdic, object target, string eventName)
public Subscription(SubscriptionDic<T> sdic, Type targetType, object target, string eventName)
{
_sdic = sdic;
_target = target;
_eventName = eventName;
var t = target.GetType();
Dictionary<string, EventInfo> evDic;
if (!Accessors.TryGetValue(t, out evDic))
Accessors[t] = evDic = new Dictionary<string, EventInfo>();
if (!Accessors.TryGetValue(targetType, out evDic))
Accessors[targetType] = evDic = new Dictionary<string, EventInfo>();
if (!evDic.TryGetValue(eventName, out _info))
{
var ev = t.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName);
var ev = targetType.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName);
if (ev == null)
{

8
src/Markup/Avalonia.Markup/Data/IndexerNode.cs

@ -33,8 +33,8 @@ namespace Avalonia.Markup.Data
if (incc != null)
{
inputs.Add(WeakObservable.FromEventPattern<NotifyCollectionChangedEventArgs>(
target,
inputs.Add(WeakObservable.FromEventPattern<INotifyCollectionChanged, NotifyCollectionChangedEventArgs>(
incc,
nameof(incc.CollectionChanged))
.Where(x => ShouldUpdate(x.Sender, x.EventArgs))
.Select(_ => GetValue(target)));
@ -42,8 +42,8 @@ namespace Avalonia.Markup.Data
if (inpc != null)
{
inputs.Add(WeakObservable.FromEventPattern<PropertyChangedEventArgs>(
target,
inputs.Add(WeakObservable.FromEventPattern<INotifyPropertyChanged, PropertyChangedEventArgs>(
inpc,
nameof(inpc.PropertyChanged))
.Where(x => ShouldUpdate(x.Sender, x.EventArgs))
.Select(_ => GetValue(target)));

10
src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs

@ -13,7 +13,15 @@ namespace Avalonia.Markup.Data.Plugins
public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin
{
/// <inheritdoc/>
public bool Match(WeakReference reference) => reference.Target is AvaloniaObject;
public bool Match(object obj, string propertyName)
{
if (obj is AvaloniaObject a)
{
return AvaloniaPropertyRegistry.Instance.FindRegistered(a, propertyName) != null;
}
return false;
}
/// <summary>
/// Starts monitoring the value of a property on an object.

7
src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessorPlugin.cs

@ -14,9 +14,10 @@ namespace Avalonia.Markup.Data.Plugins
/// <summary>
/// Checks whether this plugin can handle accessing the properties of the specified object.
/// </summary>
/// <param name="reference">A weak reference to the object.</param>
/// <returns>True if the plugin can handle the object; otherwise false.</returns>
bool Match(WeakReference reference);
/// <param name="obj">The object.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>True if the plugin can handle the property on the object; otherwise false.</returns>
bool Match(object obj, string propertyName);
/// <summary>
/// Starts monitoring the value of a property on an object.

6
src/Markup/Avalonia.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs

@ -19,7 +19,7 @@ namespace Avalonia.Markup.Data.Plugins
public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
{
/// <inheritdoc/>
public bool Match(WeakReference reference) => true;
public bool Match(object obj, string propertyName) => true;
/// <summary>
/// Starts monitoring the value of a property on an object.
@ -36,7 +36,7 @@ namespace Avalonia.Markup.Data.Plugins
Contract.Requires<ArgumentNullException>(propertyName != null);
var instance = reference.Target;
var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(_ => _.Name == propertyName);
var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(x => x.Name == propertyName);
if (p != null)
{
@ -138,7 +138,7 @@ namespace Avalonia.Markup.Data.Plugins
if (inpc != null)
{
WeakSubscriptionManager.Subscribe<PropertyChangedEventArgs>(
WeakSubscriptionManager.Subscribe(
inpc,
nameof(inpc.PropertyChanged),
this);

2
src/Markup/Avalonia.Markup/Data/PropertyAccessorNode.cs

@ -37,7 +37,7 @@ namespace Avalonia.Markup.Data
protected override IObservable<object> StartListeningCore(WeakReference reference)
{
var plugin = ExpressionObserver.PropertyAccessors.FirstOrDefault(x => x.Match(reference));
var plugin = ExpressionObserver.PropertyAccessors.FirstOrDefault(x => x.Match(reference.Target, PropertyName));
var accessor = plugin?.Start(reference, PropertyName);
if (_enableValidation && Next == null)

12
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_AvaloniaProperty.cs

@ -30,6 +30,16 @@ namespace Avalonia.Markup.UnitTests.Data
Assert.Null(((IAvaloniaObjectDebug)data).GetPropertyChangedSubscribers());
}
[Fact]
public async Task Should_Get_Simple_ClrProperty_Value()
{
var data = new Class1();
var target = new ExpressionObserver(data, "ClrProperty");
var result = await target.Take(1);
Assert.Equal("clr-property", result);
}
[Fact]
public void Should_Track_Simple_Property_Value()
{
@ -69,6 +79,8 @@ namespace Avalonia.Markup.UnitTests.Data
{
public static readonly StyledProperty<string> FooProperty =
AvaloniaProperty.Register<Class1, string>("Foo", defaultValue: "foo");
public string ClrProperty { get; } = "clr-property";
}
}
}

Loading…
Cancel
Save