41 changed files with 36 additions and 611 deletions
@ -1,35 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
|
|||
namespace Avalonia.Controls.Templates |
|||
{ |
|||
/// <summary>
|
|||
/// Selects a member of an object using a <see cref="Func{TObject, TMember}"/>.
|
|||
/// </summary>
|
|||
public class FuncMemberSelector<TObject, TMember> : IMemberSelector |
|||
{ |
|||
private readonly Func<TObject, TMember> _selector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="FuncMemberSelector{TObject, TMember}"/>
|
|||
/// class.
|
|||
/// </summary>
|
|||
/// <param name="selector">The selector.</param>
|
|||
public FuncMemberSelector(Func<TObject, TMember> selector) |
|||
{ |
|||
this._selector = selector; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Selects a member of an object.
|
|||
/// </summary>
|
|||
/// <param name="o">The object.</param>
|
|||
/// <returns>The selected member.</returns>
|
|||
public object Select(object o) |
|||
{ |
|||
return (o is TObject) ? _selector((TObject)o) : default(TMember); |
|||
} |
|||
} |
|||
} |
|||
@ -1,18 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
namespace Avalonia.Controls.Templates |
|||
{ |
|||
/// <summary>
|
|||
/// Selects a member of an object.
|
|||
/// </summary>
|
|||
public interface IMemberSelector |
|||
{ |
|||
/// <summary>
|
|||
/// Selects a member of an object.
|
|||
/// </summary>
|
|||
/// <param name="o">The object.</param>
|
|||
/// <returns>The selected member.</returns>
|
|||
object Select(object o); |
|||
} |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
// Copyright (c) The Avalonia 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 Avalonia.Markup.Xaml.Templates; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Converters |
|||
{ |
|||
using System.ComponentModel; |
|||
|
|||
public class MemberSelectorTypeConverter : TypeConverter |
|||
{ |
|||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
|||
{ |
|||
return sourceType == typeof(string); |
|||
} |
|||
|
|||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
|||
{ |
|||
return MemberSelector.Parse((string)value); |
|||
} |
|||
} |
|||
} |
|||
@ -1,48 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Data; |
|||
using Avalonia.Data.Core; |
|||
using Avalonia.Markup.Parsers; |
|||
using System; |
|||
using System.Reactive.Linq; |
|||
|
|||
namespace Avalonia.Markup.Xaml.Templates |
|||
{ |
|||
public class MemberSelector : IMemberSelector |
|||
{ |
|||
private string _memberName; |
|||
|
|||
public string MemberName |
|||
{ |
|||
get { return _memberName; } |
|||
set |
|||
{ |
|||
if (_memberName != value) |
|||
{ |
|||
_memberName = value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static MemberSelector Parse(string s) |
|||
{ |
|||
return new MemberSelector { MemberName = s }; |
|||
} |
|||
|
|||
public object Select(object o) |
|||
{ |
|||
if (string.IsNullOrEmpty(MemberName)) |
|||
{ |
|||
return o; |
|||
} |
|||
|
|||
var expression = ExpressionObserverBuilder.Build(o, MemberName); |
|||
object result = AvaloniaProperty.UnsetValue; |
|||
|
|||
expression.Subscribe(x => result = x); |
|||
return (result == AvaloniaProperty.UnsetValue || result is BindingNotification) ? null : result; |
|||
} |
|||
} |
|||
} |
|||
@ -1,55 +0,0 @@ |
|||
using Avalonia.Markup.Xaml.Templates; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.dotMemoryUnit; |
|||
using Xunit; |
|||
using Xunit.Abstractions; |
|||
|
|||
namespace Avalonia.LeakTests |
|||
{ |
|||
[DotMemoryUnit(FailIfRunWithoutSupport = false)] |
|||
public class MemberSelectorTests |
|||
{ |
|||
public MemberSelectorTests(ITestOutputHelper atr) |
|||
{ |
|||
DotMemoryUnitTestOutput.SetOutputMethod(atr.WriteLine); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Not_Hold_Reference_To_Object() |
|||
{ |
|||
WeakReference dataRef = null; |
|||
|
|||
var selector = new MemberSelector() { MemberName = "Child.StringValue" }; |
|||
|
|||
Action run = () => |
|||
{ |
|||
var data = new Item() |
|||
{ |
|||
Child = new Item() { StringValue = "Value1" } |
|||
}; |
|||
|
|||
Assert.Same("Value1", selector.Select(data)); |
|||
|
|||
dataRef = new WeakReference(data); |
|||
}; |
|||
|
|||
run(); |
|||
|
|||
GC.Collect(); |
|||
|
|||
Assert.False(dataRef.IsAlive); |
|||
} |
|||
|
|||
private class Item |
|||
{ |
|||
public Item Child { get; set; } |
|||
public int IntValue { get; set; } |
|||
|
|||
public string StringValue { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -1,159 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using Avalonia.Markup.Xaml.Templates; |
|||
using System; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Markup.Xaml.UnitTests.Templates |
|||
{ |
|||
public class MemberSelectorTests |
|||
{ |
|||
[Fact] |
|||
public void Should_Select_Child_Property_Value() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "Child.StringValue" }; |
|||
|
|||
var data = new Item() |
|||
{ |
|||
Child = new Item() { StringValue = "Value1" } |
|||
}; |
|||
|
|||
Assert.Same("Value1", selector.Select(data)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Select_Child_Property_Value_In_Multiple_Items() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "Child.StringValue" }; |
|||
|
|||
var data = new Item[] |
|||
{ |
|||
new Item() { Child = new Item() { StringValue = "Value1" } }, |
|||
new Item() { Child = new Item() { StringValue = "Value2" } }, |
|||
new Item() { Child = new Item() { StringValue = "Value3" } } |
|||
}; |
|||
|
|||
Assert.Same("Value1", selector.Select(data[0])); |
|||
Assert.Same("Value2", selector.Select(data[1])); |
|||
Assert.Same("Value3", selector.Select(data[2])); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Select_MoreComplex_Property_Value() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "Child.Child.Child.StringValue" }; |
|||
|
|||
var data = new Item() |
|||
{ |
|||
Child = new Item() |
|||
{ |
|||
Child = new Item() |
|||
{ |
|||
Child = new Item() { StringValue = "Value1" } |
|||
} |
|||
} |
|||
}; |
|||
|
|||
Assert.Same("Value1", selector.Select(data)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Select_Null_Value_On_Null_Object() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|||
|
|||
Assert.Null(selector.Select(null)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Select_Null_Value_On_Wrong_MemberName() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "WrongProperty" }; |
|||
|
|||
var data = new Item() { StringValue = "Value1" }; |
|||
|
|||
Assert.Null(selector.Select(data)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Select_Simple_Property_Value() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|||
|
|||
var data = new Item() { StringValue = "Value1" }; |
|||
|
|||
Assert.Same("Value1", selector.Select(data)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Select_Simple_Property_Value_In_Multiple_Items() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|||
|
|||
var data = new Item[] |
|||
{ |
|||
new Item() { StringValue = "Value1" }, |
|||
new Item() { StringValue = "Value2" }, |
|||
new Item() { StringValue = "Value3" } |
|||
}; |
|||
|
|||
Assert.Same("Value1", selector.Select(data[0])); |
|||
Assert.Same("Value2", selector.Select(data[1])); |
|||
Assert.Same("Value3", selector.Select(data[2])); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Select_Target_On_Empty_MemberName() |
|||
{ |
|||
var selector = new MemberSelector(); |
|||
|
|||
var data = new Item() { StringValue = "Value1" }; |
|||
|
|||
Assert.Same(data, selector.Select(data)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Support_Change_Of_MemberName() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|||
|
|||
var data = new Item() |
|||
{ |
|||
StringValue = "Value1", |
|||
IntValue = 1 |
|||
}; |
|||
|
|||
Assert.Same("Value1", selector.Select(data)); |
|||
|
|||
selector.MemberName = "IntValue"; |
|||
|
|||
Assert.Equal(1, selector.Select(data)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Support_Change_Of_Target_Value() |
|||
{ |
|||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|||
|
|||
var data = new Item() |
|||
{ |
|||
StringValue = "Value1" |
|||
}; |
|||
|
|||
Assert.Same("Value1", selector.Select(data)); |
|||
|
|||
data.StringValue = "Value2"; |
|||
|
|||
Assert.Same("Value2", selector.Select(data)); |
|||
} |
|||
|
|||
private class Item |
|||
{ |
|||
public Item Child { get; set; } |
|||
public int IntValue { get; set; } |
|||
|
|||
public string StringValue { get; set; } |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue