Browse Source

Removed MemberSelector.

pull/2690/head
Steven Kirk 7 years ago
parent
commit
2fa8247f01
  1. 4
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  2. 3
      samples/ControlCatalog/SideBar.xaml
  3. 5
      samples/RenderDemo/SideBar.xaml
  4. 26
      src/Avalonia.Controls/AutoCompleteBox.cs
  5. 3
      src/Avalonia.Controls/ComboBox.cs
  6. 12
      src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
  7. 17
      src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
  8. 14
      src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
  9. 5
      src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
  10. 15
      src/Avalonia.Controls/ItemsControl.cs
  11. 2
      src/Avalonia.Controls/Presenters/CarouselPresenter.cs
  12. 2
      src/Avalonia.Controls/Presenters/ItemContainerSync.cs
  13. 2
      src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs
  14. 9
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  15. 15
      src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
  16. 9
      src/Avalonia.Controls/Primitives/TabStrip.cs
  17. 35
      src/Avalonia.Controls/Templates/FuncMemberSelector.cs
  18. 18
      src/Avalonia.Controls/Templates/IMemberSelector.cs
  19. 1
      src/Avalonia.Themes.Default/AutoCompleteBox.xaml
  20. 3
      src/Avalonia.Themes.Default/Carousel.xaml
  21. 1
      src/Avalonia.Themes.Default/ComboBox.xaml
  22. 2
      src/Avalonia.Themes.Default/DataValidationErrors.xaml
  23. 5
      src/Avalonia.Themes.Default/ItemsControl.xaml
  24. 3
      src/Avalonia.Themes.Default/ListBox.xaml
  25. 6
      src/Avalonia.Themes.Default/MenuItem.xaml
  26. 3
      src/Avalonia.Themes.Default/TabControl.xaml
  27. 3
      src/Avalonia.Themes.Default/TabStrip.xaml
  28. 3
      src/Avalonia.Themes.Default/TreeView.xaml
  29. 3
      src/Avalonia.Themes.Default/TreeViewItem.xaml
  30. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  31. 24
      src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs
  32. 48
      src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs
  33. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  34. 6
      tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs
  35. 2
      tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTypedTests.cs
  36. 22
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
  37. 40
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
  38. 55
      tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs
  39. 55
      tests/Avalonia.LeakTests/MemberSelectorTests.cs
  40. 159
      tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs
  41. 3
      tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs

4
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@ -37,10 +37,6 @@
<StackPanel Orientation="Vertical">
<TextBlock Text="ValueMemeberSelector"/>
<AutoCompleteBox Width="200"
Margin="0,0,0,8"
ValueMemberSelector="Capital"/>
<TextBlock Text="ValueMemberBinding"/>
<AutoCompleteBox Width="200"
Margin="0,0,0,8"

3
samples/ControlCatalog/SideBar.xaml

@ -29,8 +29,7 @@
Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding MemberSelector}">
ItemTemplate="{TemplateBinding ItemTemplate}">
</ItemsPresenter>
</ScrollViewer>
<ContentPresenter

5
samples/RenderDemo/SideBar.xaml

@ -20,8 +20,7 @@
Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding MemberSelector}">
ItemTemplate="{TemplateBinding ItemTemplate}">
</ItemsPresenter>
</ScrollViewer>
<ContentPresenter
@ -63,4 +62,4 @@
<Style Selector="TabControl.sidebar > TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/>
</Style>
</Styles>
</Styles>

26
src/Avalonia.Controls/AutoCompleteBox.cs

@ -345,7 +345,6 @@ namespace Avalonia.Controls
/// </summary>
private IDisposable _collectionChangeSubscription;
private IMemberSelector _valueMemberSelector;
private Func<string, CancellationToken, Task<IEnumerable<object>>> _asyncPopulator;
private CancellationTokenSource _populationCancellationTokenSource;
@ -541,12 +540,6 @@ namespace Avalonia.Controls
o => o.Items,
(o, v) => o.Items = v);
public static readonly DirectProperty<AutoCompleteBox, IMemberSelector> ValueMemberSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, IMemberSelector>(
nameof(ValueMemberSelector),
o => o.ValueMemberSelector,
(o, v) => o.ValueMemberSelector = v);
public static readonly DirectProperty<AutoCompleteBox, Func<string, CancellationToken, Task<IEnumerable<object>>>> AsyncPopulatorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, Func<string, CancellationToken, Task<IEnumerable<object>>>>(
nameof(AsyncPopulator),
@ -958,20 +951,6 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Gets or sets the MemberSelector that is used to get values for
/// display in the text portion of the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.
/// </summary>
/// <value>The MemberSelector that is used to get values for display in
/// the text portion of the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control.</value>
public IMemberSelector ValueMemberSelector
{
get { return _valueMemberSelector; }
set { SetAndRaise(ValueMemberSelectorProperty, ref _valueMemberSelector, value); }
}
/// <summary>
/// Gets or sets the selected item in the drop-down.
/// </summary>
@ -1841,11 +1820,6 @@ namespace Avalonia.Controls
return _valueBindingEvaluator.GetDynamicValue(value) ?? String.Empty;
}
if (_valueMemberSelector != null)
{
value = _valueMemberSelector.Select(value);
}
return value == null ? String.Empty : value.ToString();
}

3
src/Avalonia.Controls/ComboBox.cs

@ -333,8 +333,7 @@ namespace Avalonia.Controls
}
else
{
var selector = MemberSelector;
SelectionBoxItem = selector != null ? selector.Select(item) : item;
SelectionBoxItem = item;
}
}

12
src/Avalonia.Controls/Generators/IItemContainerGenerator.cs

@ -49,12 +49,8 @@ namespace Avalonia.Controls.Generators
/// The index of the item of data in the control's items.
/// </param>
/// <param name="item">The item.</param>
/// <param name="selector">An optional member selector.</param>
/// <returns>The created controls.</returns>
ItemContainerInfo Materialize(
int index,
object item,
IMemberSelector selector);
ItemContainerInfo Materialize(int index, object item);
/// <summary>
/// Removes a set of created containers.
@ -84,11 +80,7 @@ namespace Avalonia.Controls.Generators
/// <returns>The removed containers.</returns>
IEnumerable<ItemContainerInfo> RemoveRange(int startingIndex, int count);
bool TryRecycle(
int oldIndex,
int newIndex,
object item,
IMemberSelector selector);
bool TryRecycle(int oldIndex, int newIndex, object item);
/// <summary>
/// Clears all created containers and returns the removed controls.

17
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@ -54,13 +54,9 @@ namespace Avalonia.Controls.Generators
public virtual Type ContainerType => null;
/// <inheritdoc/>
public ItemContainerInfo Materialize(
int index,
object item,
IMemberSelector selector)
public ItemContainerInfo Materialize(int index, object item)
{
var i = selector != null ? selector.Select(item) : item;
var container = new ItemContainerInfo(CreateContainer(i), item, index);
var container = new ItemContainerInfo(CreateContainer(item), item, index);
_containers.Add(container.Index, container);
Materialized?.Invoke(this, new ItemContainerEventArgs(container));
@ -138,14 +134,7 @@ namespace Avalonia.Controls.Generators
}
/// <inheritdoc/>
public virtual bool TryRecycle(
int oldIndex,
int newIndex,
object item,
IMemberSelector selector)
{
return false;
}
public virtual bool TryRecycle(int oldIndex, int newIndex, object item) => false;
/// <inheritdoc/>
public virtual IEnumerable<ItemContainerInfo> Clear()

14
src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

@ -79,11 +79,7 @@ namespace Avalonia.Controls.Generators
}
/// <inheritdoc/>
public override bool TryRecycle(
int oldIndex,
int newIndex,
object item,
IMemberSelector selector)
public override bool TryRecycle(int oldIndex, int newIndex, object item)
{
var container = ContainerFromIndex(oldIndex);
@ -92,16 +88,14 @@ namespace Avalonia.Controls.Generators
throw new IndexOutOfRangeException("Could not recycle container: not materialized.");
}
var i = selector != null ? selector.Select(item) : item;
container.SetValue(ContentProperty, i);
container.SetValue(ContentProperty, item);
if (!(item is IControl))
{
container.DataContext = i;
container.DataContext = item;
}
var info = MoveContainer(oldIndex, newIndex, i);
var info = MoveContainer(oldIndex, newIndex, item);
RaiseRecycled(new ItemContainerEventArgs(info));
return true;

5
src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs

@ -118,10 +118,7 @@ namespace Avalonia.Controls.Generators
return base.RemoveRange(startingIndex, count);
}
public override bool TryRecycle(int oldIndex, int newIndex, object item, IMemberSelector selector)
{
return false;
}
public override bool TryRecycle(int oldIndex, int newIndex, object item) => false;
private ITreeDataTemplate GetTreeDataTemplate(object item, IDataTemplate primary)
{

15
src/Avalonia.Controls/ItemsControl.cs

@ -54,12 +54,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IDataTemplate> ItemTemplateProperty =
AvaloniaProperty.Register<ItemsControl, IDataTemplate>(nameof(ItemTemplate));
/// <summary>
/// Defines the <see cref="MemberSelector"/> property.
/// </summary>
public static readonly StyledProperty<IMemberSelector> MemberSelectorProperty =
AvaloniaProperty.Register<ItemsControl, IMemberSelector>(nameof(MemberSelector));
private IEnumerable _items = new AvaloniaList<object>();
private int _itemCount;
private IItemContainerGenerator _itemContainerGenerator;
@ -144,15 +138,6 @@ namespace Avalonia.Controls
set { SetValue(ItemTemplateProperty, value); }
}
/// <summary>
/// Selects a member from <see cref="Items"/> to use as the list item.
/// </summary>
public IMemberSelector MemberSelector
{
get { return GetValue(MemberSelectorProperty); }
set { SetValue(MemberSelectorProperty, value); }
}
/// <summary>
/// Gets the items presenter control.
/// </summary>

2
src/Avalonia.Controls/Presenters/CarouselPresenter.cs

@ -213,7 +213,7 @@ namespace Avalonia.Controls.Presenters
if (container == null && IsVirtualized)
{
var item = Items.Cast<object>().ElementAt(index);
var materialized = ItemContainerGenerator.Materialize(index, item, MemberSelector);
var materialized = ItemContainerGenerator.Materialize(index, item);
Panel.Children.Add(materialized.ContainerControl);
container = materialized.ContainerControl;
}

2
src/Avalonia.Controls/Presenters/ItemContainerSync.cs

@ -88,7 +88,7 @@ namespace Avalonia.Controls.Presenters
foreach (var item in items)
{
var i = generator.Materialize(index++, item, owner.MemberSelector);
var i = generator.Materialize(index++, item);
if (i.ContainerControl != null)
{

2
src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs

@ -90,7 +90,7 @@ namespace Avalonia.Controls.Presenters
foreach (var item in items)
{
var i = generator.Materialize(index++, item, Owner.MemberSelector);
var i = generator.Materialize(index++, item);
if (i.ContainerControl != null)
{

9
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@ -314,7 +314,6 @@ namespace Avalonia.Controls.Presenters
if (!panel.IsFull && Items != null && panel.IsAttachedToVisualTree)
{
var memberSelector = Owner.MemberSelector;
var index = NextIndex;
var step = 1;
@ -337,7 +336,7 @@ namespace Avalonia.Controls.Presenters
}
}
var materialized = generator.Materialize(index, Items.ElementAt(index), memberSelector);
var materialized = generator.Materialize(index, Items.ElementAt(index));
if (step == 1)
{
@ -383,7 +382,6 @@ namespace Avalonia.Controls.Presenters
{
var panel = VirtualizingPanel;
var generator = Owner.ItemContainerGenerator;
var selector = Owner.MemberSelector;
var containers = generator.Containers.ToList();
var itemIndex = FirstIndex;
@ -393,7 +391,7 @@ namespace Avalonia.Controls.Presenters
if (!object.Equals(container.Item, item))
{
if (!generator.TryRecycle(itemIndex, itemIndex, item, selector))
if (!generator.TryRecycle(itemIndex, itemIndex, item))
{
throw new NotImplementedException();
}
@ -420,7 +418,6 @@ namespace Avalonia.Controls.Presenters
{
var panel = VirtualizingPanel;
var generator = Owner.ItemContainerGenerator;
var selector = Owner.MemberSelector;
//validate delta it should never overflow last index or generate index < 0
delta = MathUtilities.Clamp(delta, -FirstIndex, ItemCount - FirstIndex - panel.Children.Count);
@ -437,7 +434,7 @@ namespace Avalonia.Controls.Presenters
var item = Items.ElementAt(newItemIndex);
if (!generator.TryRecycle(oldItemIndex, newItemIndex, item, selector))
if (!generator.TryRecycle(oldItemIndex, newItemIndex, item))
{
throw new NotImplementedException();
}

15
src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs

@ -35,12 +35,6 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty<IDataTemplate> ItemTemplateProperty =
ItemsControl.ItemTemplateProperty.AddOwner<ItemsPresenterBase>();
/// <summary>
/// Defines the <see cref="MemberSelector"/> property.
/// </summary>
public static readonly StyledProperty<IMemberSelector> MemberSelectorProperty =
ItemsControl.MemberSelectorProperty.AddOwner<ItemsPresenterBase>();
private IEnumerable _items;
private IDisposable _itemsSubscription;
private bool _createdPanel;
@ -127,15 +121,6 @@ namespace Avalonia.Controls.Presenters
set { SetValue(ItemTemplateProperty, value); }
}
/// <summary>
/// Selects a member from <see cref="Items"/> to use as the list item.
/// </summary>
public IMemberSelector MemberSelector
{
get { return GetValue(MemberSelectorProperty); }
set { SetValue(MemberSelectorProperty, value); }
}
/// <summary>
/// Gets the panel used to display the items.
/// </summary>

9
src/Avalonia.Controls/Primitives/TabStrip.cs

@ -12,11 +12,8 @@ namespace Avalonia.Controls.Primitives
private static readonly FuncTemplate<IPanel> DefaultPanel =
new FuncTemplate<IPanel>(() => new WrapPanel { Orientation = Orientation.Horizontal });
private static IMemberSelector s_MemberSelector = new FuncMemberSelector<object, object>(SelectHeader);
static TabStrip()
{
MemberSelectorProperty.OverrideDefaultValue<TabStrip>(s_MemberSelector);
SelectionModeProperty.OverrideDefaultValue<TabStrip>(SelectionMode.AlwaysSelected);
FocusableProperty.OverrideDefaultValue(typeof(TabStrip), false);
ItemsPanelProperty.OverrideDefaultValue<TabStrip>(DefaultPanel);
@ -51,11 +48,5 @@ namespace Avalonia.Controls.Primitives
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
private static object SelectHeader(object o)
{
var headered = o as IHeadered;
return (headered != null) ? (headered.Header ?? string.Empty) : o;
}
}
}

35
src/Avalonia.Controls/Templates/FuncMemberSelector.cs

@ -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);
}
}
}

18
src/Avalonia.Controls/Templates/IMemberSelector.cs

@ -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
src/Avalonia.Themes.Default/AutoCompleteBox.xaml

@ -27,7 +27,6 @@
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding ValueMemberSelector}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</Border>

3
src/Avalonia.Themes.Default/Carousel.xaml

@ -8,10 +8,9 @@
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
Margin="{TemplateBinding Padding}"
MemberSelector="{TemplateBinding MemberSelector}"
SelectedIndex="{TemplateBinding SelectedIndex}"
PageTransition="{TemplateBinding PageTransition}"/>
</Border>
</ControlTemplate>
</Setter>
</Style>
</Style>

1
src/Avalonia.Themes.Default/ComboBox.xaml

@ -45,7 +45,6 @@
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding MemberSelector}"
VirtualizationMode="{TemplateBinding VirtualizationMode}"
/>
</ScrollViewer>

2
src/Avalonia.Themes.Default/DataValidationErrors.xaml

@ -29,7 +29,7 @@
</Style>
</Canvas.Styles>
<ToolTip.Tip>
<ItemsControl Items="{Binding}" MemberSelector="Message"/>
<ItemsControl Items="{Binding}"/>
</ToolTip.Tip>
<Path Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2" Stroke="{DynamicResource ErrorBrush}" StrokeThickness="2"/>
</Canvas>

5
src/Avalonia.Themes.Default/ItemsControl.xaml

@ -4,8 +4,7 @@
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding MemberSelector}"/>
ItemTemplate="{TemplateBinding ItemTemplate}"/>
</ControlTemplate>
</Setter>
</Style>
</Style>

3
src/Avalonia.Themes.Default/ListBox.xaml

@ -18,10 +18,9 @@
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="{TemplateBinding Padding}"
MemberSelector="{TemplateBinding MemberSelector}"
VirtualizationMode="{TemplateBinding VirtualizationMode}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter>
</Style>
</Style>

6
src/Avalonia.Themes.Default/MenuItem.xaml

@ -56,8 +56,7 @@
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="2"
MemberSelector="{TemplateBinding MemberSelector}"/>
Margin="2"/>
<Rectangle Name="iconSeparator"
Fill="{DynamicResource ThemeControlMidBrush}"
HorizontalAlignment="Left"
@ -114,8 +113,7 @@
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="2"
MemberSelector="{TemplateBinding MemberSelector}"/>
Margin="2"/>
<Rectangle Name="iconSeparator"
Fill="{DynamicResource ThemeControlMidBrush}"
HorizontalAlignment="Left"

3
src/Avalonia.Themes.Default/TabControl.xaml

@ -14,8 +14,7 @@
Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
MemberSelector="{TemplateBinding MemberSelector}" >
ItemTemplate="{TemplateBinding ItemTemplate}">
</ItemsPresenter>
<ContentPresenter
Name="PART_SelectedContentHost"

3
src/Avalonia.Themes.Default/TabStrip.xaml

@ -3,7 +3,6 @@
<Setter Property="Template">
<ControlTemplate>
<ItemsPresenter Name="PART_ItemsPresenter"
MemberSelector="{TemplateBinding MemberSelector}"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"/>
@ -18,4 +17,4 @@
<Style Selector="TabStrip > TabStripItem">
<Setter Property="Margin" Value="16"/>
</Style>
</Styles>
</Styles>

3
src/Avalonia.Themes.Default/TreeView.xaml

@ -15,8 +15,7 @@
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
Margin="{TemplateBinding Padding}"
MemberSelector="{TemplateBinding MemberSelector}"/>
Margin="{TemplateBinding Padding}"/>
</ScrollViewer>
</Border>
</ControlTemplate>

3
src/Avalonia.Themes.Default/TreeViewItem.xaml

@ -32,8 +32,7 @@
<ItemsPresenter Name="PART_ItemsPresenter"
IsVisible="{TemplateBinding IsExpanded}"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
MemberSelector="{TemplateBinding MemberSelector}"/>
ItemsPanel="{TemplateBinding ItemsPanel}"/>
</StackPanel>
</ControlTemplate>
</Setter>

2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -12,7 +12,6 @@
<Compile Include="AvaloniaXamlLoader.cs" />
<Compile Include="Converters\AvaloniaUriTypeConverter.cs" />
<Compile Include="Converters\FontFamilyTypeConverter.cs" />
<Compile Include="Converters\MemberSelectorTypeConverter.cs" />
<Compile Include="Converters\TimeSpanTypeConverter.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="MarkupExtension.cs" />
@ -33,7 +32,6 @@
<Compile Include="Templates\DataTemplate.cs" />
<Compile Include="Templates\FocusAdornerTemplate.cs" />
<Compile Include="Templates\ItemsPanelTemplate.cs" />
<Compile Include="Templates\MemberSelector.cs" />
<Compile Include="Templates\Template.cs" />
<Compile Include="Templates\TemplateContent.cs" />
<Compile Include="Templates\TreeDataTemplate.cs" />

24
src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs

@ -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);
}
}
}

48
src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs

@ -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;
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs

@ -81,8 +81,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
var ilist = typeSystem.GetType("System.Collections.Generic.IList`1");
AddType(ilist.MakeGenericType(typeSystem.GetType("Avalonia.Point")),
typeSystem.GetType("Avalonia.Markup.Xaml.Converters.PointsListTypeConverter"));
Add("Avalonia.Controls.Templates.IMemberSelector",
"Avalonia.Markup.Xaml.Converters.MemberSelectorTypeConverter");
Add("Avalonia.Controls.WindowIcon","Avalonia.Markup.Xaml.Converters.IconTypeConverter");
Add("System.Globalization.CultureInfo", "System.ComponentModel.CultureInfoConverter");
Add("System.Uri", "Avalonia.Markup.Xaml.Converters.AvaloniaUriTypeConverter");

6
tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs

@ -118,7 +118,7 @@ namespace Avalonia.Controls.UnitTests.Generators
{
var owner = new Decorator();
var target = new ItemContainerGenerator(owner);
var container = (ContentPresenter)target.Materialize(0, "foo", null).ContainerControl;
var container = (ContentPresenter)target.Materialize(0, "foo").ContainerControl;
Assert.Equal("foo", container.Content);
@ -135,7 +135,7 @@ namespace Avalonia.Controls.UnitTests.Generators
{
var owner = new Decorator();
var target = new ItemContainerGenerator<ListBoxItem>(owner, ListBoxItem.ContentProperty, null);
var container = (ListBoxItem)target.Materialize(0, "foo", null).ContainerControl;
var container = (ListBoxItem)target.Materialize(0, "foo").ContainerControl;
Assert.Equal("foo", container.Content);
@ -156,7 +156,7 @@ namespace Avalonia.Controls.UnitTests.Generators
foreach (var item in items)
{
var container = generator.Materialize(index++, item, null);
var container = generator.Materialize(index++, item);
result.Add(container);
}

2
tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTypedTests.cs

@ -35,7 +35,7 @@ namespace Avalonia.Controls.UnitTests.Generators
foreach (var item in items)
{
var container = generator.Materialize(index++, item, null);
var container = generator.Materialize(index++, item);
result.Add(container);
}

22
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@ -430,27 +430,6 @@ namespace Avalonia.Controls.UnitTests
dataContexts);
}
[Fact]
public void MemberSelector_Should_Select_Member()
{
var target = new ItemsControl
{
Template = GetTemplate(),
Items = new[] { new Item("Foo"), new Item("Bar") },
MemberSelector = new FuncMemberSelector<Item, string>(x => x.Value),
};
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
var text = target.Presenter.Panel.Children
.Cast<ContentPresenter>()
.Select(x => x.Content)
.ToList();
Assert.Equal(new[] { "Foo", "Bar" }, text);
}
[Fact]
public void Control_Item_Should_Not_Be_NameScope()
{
@ -586,7 +565,6 @@ namespace Avalonia.Controls.UnitTests
Child = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
MemberSelector = parent.MemberSelector,
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
}
};

40
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs

@ -310,46 +310,6 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.Equal(target.Panel, child);
}
[Fact]
public void MemberSelector_Should_Select_Member()
{
var target = new ItemsPresenter
{
Items = new[] { new Item("Foo"), new Item("Bar") },
MemberSelector = new FuncMemberSelector<Item, string>(x => x.Value),
};
target.ApplyTemplate();
var text = target.Panel.Children
.Cast<ContentPresenter>()
.Select(x => x.Content)
.ToList();
Assert.Equal(new[] { "Foo", "Bar" }, text);
}
[Fact]
public void MemberSelector_Should_Set_DataContext()
{
var items = new[] { new Item("Foo"), new Item("Bar") };
var target = new ItemsPresenter
{
Items = items,
MemberSelector = new FuncMemberSelector<Item, string>(x => x.Value),
};
target.ApplyTemplate();
var dataContexts = target.Panel.Children
.Cast<ContentPresenter>()
.Do(x => x.UpdateChild())
.Select(x => x.DataContext)
.ToList();
Assert.Equal(new[] { "Foo", "Bar" }, dataContexts);
}
private class Item
{
public Item(string value)

55
tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs

@ -14,60 +14,6 @@ namespace Avalonia.Controls.UnitTests.Primitives
{
public class TabStripTests
{
[Fact]
public void Header_Of_IHeadered_Items_Should_Be_Used()
{
var items = new[]
{
#pragma warning disable CS0252 // Possible unintended reference comparison; left hand side needs cast
Mock.Of<IHeadered>(x => x.Header == "foo"),
Mock.Of<IHeadered>(x => x.Header == "bar"),
#pragma warning restore CS0252 // Possible unintended reference comparison; left hand side needs cast
};
var target = new TabStrip
{
Template = new FuncControlTemplate<TabStrip>(CreateTabStripTemplate),
Items = items,
};
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
var result = target.GetLogicalChildren()
.OfType<TabStripItem>()
.Select(x => x.Content)
.ToList();
Assert.Equal(new[] { "foo", "bar" }, result);
}
[Fact]
public void Data_Of_Non_IHeadered_Items_Should_Be_Used()
{
var items = new[]
{
"foo",
"bar"
};
var target = new TabStrip
{
Template = new FuncControlTemplate<TabStrip>(CreateTabStripTemplate),
Items = items,
};
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
var result = target.GetLogicalChildren()
.OfType<TabStripItem>()
.Select(x => x.Content)
.ToList();
Assert.Equal(new[] { "foo", "bar" }, result);
}
[Fact]
public void First_Tab_Should_Be_Selected_By_Default()
{
@ -165,7 +111,6 @@ namespace Avalonia.Controls.UnitTests.Primitives
{
Name = "itemsPresenter",
[!ItemsPresenter.ItemsProperty] = parent[!ItemsControl.ItemsProperty],
[!ItemsPresenter.MemberSelectorProperty] = parent[!ItemsControl.MemberSelectorProperty],
};
}
}

55
tests/Avalonia.LeakTests/MemberSelectorTests.cs

@ -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; }
}
}
}

159
tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs

@ -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; }
}
}
}

3
tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs

@ -106,11 +106,10 @@ namespace Avalonia.ReactiveUI.UnitTests
Child = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
MemberSelector = parent.MemberSelector,
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
}
};
});
}
}
}
}

Loading…
Cancel
Save