diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 1cddb9d295..8699508320 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -36,6 +36,7 @@
+
diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
index 0ca3567970..f90a0c4658 100644
--- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
@@ -37,10 +37,6 @@
-
-
+
+ TabStrip
+ A control which displays a selectable strip of tabs
+
+
+
+ Defined in XAML
+
+ Item 1
+ Item 2
+ Disabled
+
+
+
+
+ Dynamically generated
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/TabStripPage.xaml.cs b/samples/ControlCatalog/Pages/TabStripPage.xaml.cs
new file mode 100644
index 0000000000..f0630cf534
--- /dev/null
+++ b/samples/ControlCatalog/Pages/TabStripPage.xaml.cs
@@ -0,0 +1,45 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+
+namespace ControlCatalog.Pages
+{
+ public class TabStripPage : UserControl
+ {
+ public TabStripPage()
+ {
+ InitializeComponent();
+
+ DataContext = new[]
+ {
+ new TabStripItemViewModel
+ {
+ Header = "Item 1",
+ },
+ new TabStripItemViewModel
+ {
+ Header = "Item 2",
+ },
+ new TabStripItemViewModel
+ {
+ Header = "Disabled",
+ IsEnabled = false,
+ },
+ };
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private class TabStripItemViewModel
+ {
+ public string Header { get; set; }
+ public bool IsEnabled { get; set; } = true;
+ }
+ }
+}
diff --git a/samples/ControlCatalog/SideBar.xaml b/samples/ControlCatalog/SideBar.xaml
index 3047b1e519..3513e94107 100644
--- a/samples/ControlCatalog/SideBar.xaml
+++ b/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}">
+ ItemTemplate="{TemplateBinding ItemTemplate}">
-
\ No newline at end of file
+
diff --git a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
index 990a4b04f2..0ffd6a9539 100644
--- a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
@@ -31,7 +31,7 @@ namespace Avalonia.Data.Converters
{
if (value == null)
{
- return AvaloniaProperty.UnsetValue;
+ return targetType.IsValueType ? AvaloniaProperty.UnsetValue : null;
}
if (typeof(ICommand).IsAssignableFrom(targetType) && value is Delegate d && d.Method.GetParameters().Length <= 1)
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index 473c4fe21b..1e2fc9f9d0 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -345,7 +345,6 @@ namespace Avalonia.Controls
///
private IDisposable _collectionChangeSubscription;
- private IMemberSelector _valueMemberSelector;
private Func>> _asyncPopulator;
private CancellationTokenSource _populationCancellationTokenSource;
@@ -541,12 +540,6 @@ namespace Avalonia.Controls
o => o.Items,
(o, v) => o.Items = v);
- public static readonly DirectProperty ValueMemberSelectorProperty =
- AvaloniaProperty.RegisterDirect(
- nameof(ValueMemberSelector),
- o => o.ValueMemberSelector,
- (o, v) => o.ValueMemberSelector = v);
-
public static readonly DirectProperty>>> AsyncPopulatorProperty =
AvaloniaProperty.RegisterDirect>>>(
nameof(AsyncPopulator),
@@ -958,20 +951,6 @@ namespace Avalonia.Controls
}
}
- ///
- /// Gets or sets the MemberSelector that is used to get values for
- /// display in the text portion of the
- /// control.
- ///
- /// The MemberSelector that is used to get values for display in
- /// the text portion of the
- /// control.
- public IMemberSelector ValueMemberSelector
- {
- get { return _valueMemberSelector; }
- set { SetAndRaise(ValueMemberSelectorProperty, ref _valueMemberSelector, value); }
- }
-
///
/// Gets or sets the selected item in the drop-down.
///
@@ -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();
}
diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs
index 5d427df5a6..f32b8fabc6 100644
--- a/src/Avalonia.Controls/ComboBox.cs
+++ b/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;
}
}
diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs
index 92293a32d6..58b4324a3e 100644
--- a/src/Avalonia.Controls/ContextMenu.cs
+++ b/src/Avalonia.Controls/ContextMenu.cs
@@ -1,12 +1,12 @@
using System;
using System.ComponentModel;
using System.Linq;
-using System.Reactive.Linq;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
+using Avalonia.Interactivity;
using Avalonia.LogicalTree;
namespace Avalonia.Controls
@@ -90,9 +90,14 @@ namespace Avalonia.Controls
/// The control.
public void Open(Control control)
{
+ if (IsOpen)
+ {
+ return;
+ }
+
if (_popup == null)
{
- _popup = new Popup()
+ _popup = new Popup
{
PlacementMode = PlacementMode.Pointer,
PlacementTarget = control,
@@ -107,7 +112,14 @@ namespace Avalonia.Controls
((ISetLogicalParent)_popup).SetParent(control);
_popup.Child = this;
_popup.IsOpen = true;
+
IsOpen = true;
+
+ RaiseEvent(new RoutedEventArgs
+ {
+ RoutedEvent = MenuOpenedEvent,
+ Source = this,
+ });
}
///
@@ -115,13 +127,15 @@ namespace Avalonia.Controls
///
public override void Close()
{
+ if (!IsOpen)
+ {
+ return;
+ }
+
if (_popup != null && _popup.IsVisible)
{
_popup.IsOpen = false;
}
-
- SelectedIndex = -1;
- IsOpen = false;
}
protected override IItemContainerGenerator CreateItemContainerGenerator()
@@ -129,6 +143,18 @@ namespace Avalonia.Controls
return new MenuItemContainerGenerator(this);
}
+ private void CloseCore()
+ {
+ SelectedIndex = -1;
+ IsOpen = false;
+
+ RaiseEvent(new RoutedEventArgs
+ {
+ RoutedEvent = MenuClosedEvent,
+ Source = this,
+ });
+ }
+
private void PopupOpened(object sender, EventArgs e)
{
Focus();
@@ -145,8 +171,7 @@ namespace Avalonia.Controls
i.IsSubMenuOpen = false;
}
- contextMenu.IsOpen = false;
- contextMenu.SelectedIndex = -1;
+ contextMenu.CloseCore();
}
}
diff --git a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
index 653a4f5dcb..2d6757219d 100644
--- a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
+++ b/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.
///
/// The item.
- /// An optional member selector.
/// The created controls.
- ItemContainerInfo Materialize(
- int index,
- object item,
- IMemberSelector selector);
+ ItemContainerInfo Materialize(int index, object item);
///
/// Removes a set of created containers.
@@ -84,11 +80,7 @@ namespace Avalonia.Controls.Generators
/// The removed containers.
IEnumerable RemoveRange(int startingIndex, int count);
- bool TryRecycle(
- int oldIndex,
- int newIndex,
- object item,
- IMemberSelector selector);
+ bool TryRecycle(int oldIndex, int newIndex, object item);
///
/// Clears all created containers and returns the removed controls.
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
index f1a1f94a01..4fd6f4135c 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
@@ -54,13 +54,9 @@ namespace Avalonia.Controls.Generators
public virtual Type ContainerType => null;
///
- 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
}
///
- 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;
///
public virtual IEnumerable Clear()
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
index 320d6c8faf..d1d1c2b172 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
@@ -79,11 +79,7 @@ namespace Avalonia.Controls.Generators
}
///
- 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;
diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
index 43d1108fb9..c06a64443c 100644
--- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
@@ -117,10 +117,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;
class WrapperTreeDataTemplate : ITreeDataTemplate
{
diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs
index a292ff7d0a..902e55bde6 100644
--- a/src/Avalonia.Controls/ItemsControl.cs
+++ b/src/Avalonia.Controls/ItemsControl.cs
@@ -54,12 +54,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty ItemTemplateProperty =
AvaloniaProperty.Register(nameof(ItemTemplate));
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty MemberSelectorProperty =
- AvaloniaProperty.Register(nameof(MemberSelector));
-
private IEnumerable _items = new AvaloniaList
public static readonly RoutedEvent MenuOpenedEvent =
- RoutedEvent.Register
protected void SelectAll()
{
- if ((SelectionMode & (SelectionMode.Multiple | SelectionMode.Toggle)) == 0)
- {
- throw new NotSupportedException("Multiple selection is not enabled on this control.");
- }
-
UpdateSelectedItems(() =>
{
_selection.Clear();
@@ -523,7 +534,14 @@ namespace Avalonia.Controls.Primitives
var toggle = (toggleModifier || (mode & SelectionMode.Toggle) != 0);
var range = multi && rangeModifier;
- if (range)
+ if (rightButton)
+ {
+ if (!_selection.Contains(index))
+ {
+ UpdateSelectedItem(index);
+ }
+ }
+ else if (range)
{
UpdateSelectedItems(() =>
{
@@ -582,7 +600,7 @@ namespace Avalonia.Controls.Primitives
}
else
{
- UpdateSelectedItem(index, !(rightButton && _selection.Contains(index)));
+ UpdateSelectedItem(index);
}
if (Presenter?.Panel != null)
diff --git a/src/Avalonia.Controls/Primitives/TabStrip.cs b/src/Avalonia.Controls/Primitives/TabStrip.cs
index 0e15ae4d7b..a61757e628 100644
--- a/src/Avalonia.Controls/Primitives/TabStrip.cs
+++ b/src/Avalonia.Controls/Primitives/TabStrip.cs
@@ -12,11 +12,8 @@ namespace Avalonia.Controls.Primitives
private static readonly FuncTemplate DefaultPanel =
new FuncTemplate(() => new WrapPanel { Orientation = Orientation.Horizontal });
- private static IMemberSelector s_MemberSelector = new FuncMemberSelector
diff --git a/src/Avalonia.Visuals/Rendering/RenderLayers.cs b/src/Avalonia.Visuals/Rendering/RenderLayers.cs
index 0ff7862ab6..e82934fbad 100644
--- a/src/Avalonia.Visuals/Rendering/RenderLayers.cs
+++ b/src/Avalonia.Visuals/Rendering/RenderLayers.cs
@@ -8,8 +8,8 @@ namespace Avalonia.Rendering
{
public class RenderLayers : IEnumerable
{
- private List _inner = new List();
- private Dictionary _index = new Dictionary();
+ private readonly List _inner = new List();
+ private readonly Dictionary _index = new Dictionary();
public int Count => _inner.Count;
public RenderLayer this[IVisual layerRoot] => _index[layerRoot];
@@ -56,6 +56,7 @@ namespace Avalonia.Rendering
}
_index.Clear();
+ _inner.Clear();
}
public bool TryGetValue(IVisual layerRoot, out RenderLayer value)
diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index 6f3dabd568..06c5375520 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -12,7 +12,6 @@
-
@@ -33,7 +32,6 @@
-
diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs
deleted file mode 100644
index 8dc052fe63..0000000000
--- a/src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs
+++ /dev/null
@@ -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);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs
deleted file mode 100644
index fa91ab60ff..0000000000
--- a/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs
+++ /dev/null
@@ -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;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
index ea9eaee73a..63c8b1c074 100644
--- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
@@ -103,8 +103,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");
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs
index b12b2e3c31..428f878945 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reactive.Subjects;
using Avalonia.Data;
+using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Base.UnitTests
@@ -34,10 +35,10 @@ namespace Avalonia.Base.UnitTests
{
var target = new Class1();
- target.SetValue(Class1.ValidatedDirectProperty, new BindingNotification(6));
- target.SetValue(Class1.ValidatedDirectProperty, new BindingNotification(new Exception(), BindingErrorType.Error));
- target.SetValue(Class1.ValidatedDirectProperty, new BindingNotification(new Exception(), BindingErrorType.DataValidationError));
- target.SetValue(Class1.ValidatedDirectProperty, new BindingNotification(7));
+ target.SetValue(Class1.ValidatedDirectIntProperty, new BindingNotification(6));
+ target.SetValue(Class1.ValidatedDirectIntProperty, new BindingNotification(new Exception(), BindingErrorType.Error));
+ target.SetValue(Class1.ValidatedDirectIntProperty, new BindingNotification(new Exception(), BindingErrorType.DataValidationError));
+ target.SetValue(Class1.ValidatedDirectIntProperty, new BindingNotification(7));
Assert.Equal(
new[]
@@ -73,7 +74,7 @@ namespace Avalonia.Base.UnitTests
var source = new Subject();
var target = new Class1
{
- [!Class1.ValidatedDirectProperty] = source.ToBinding(),
+ [!Class1.ValidatedDirectIntProperty] = source.ToBinding(),
};
source.OnNext(new BindingNotification(6));
@@ -92,6 +93,30 @@ namespace Avalonia.Base.UnitTests
target.Notifications.AsEnumerable());
}
+ [Fact]
+ public void Bound_Validated_Direct_String_Property_Can_Be_Set_To_Null()
+ {
+ var source = new ViewModel
+ {
+ StringValue = "foo",
+ };
+
+ var target = new Class1
+ {
+ [!Class1.ValidatedDirectStringProperty] = new Binding
+ {
+ Path = nameof(ViewModel.StringValue),
+ Source = source,
+ },
+ };
+
+ Assert.Equal("foo", target.ValidatedDirectString);
+
+ source.StringValue = null;
+
+ Assert.Null(target.ValidatedDirectString);
+ }
+
private class Class1 : AvaloniaObject
{
public static readonly StyledProperty NonValidatedProperty =
@@ -104,15 +129,23 @@ namespace Avalonia.Base.UnitTests
o => o.NonValidatedDirect,
(o, v) => o.NonValidatedDirect = v);
- public static readonly DirectProperty ValidatedDirectProperty =
+ public static readonly DirectProperty ValidatedDirectIntProperty =
AvaloniaProperty.RegisterDirect(
- nameof(ValidatedDirect),
- o => o.ValidatedDirect,
- (o, v) => o.ValidatedDirect = v,
+ nameof(ValidatedDirectInt),
+ o => o.ValidatedDirectInt,
+ (o, v) => o.ValidatedDirectInt = v,
+ enableDataValidation: true);
+
+ public static readonly DirectProperty ValidatedDirectStringProperty =
+ AvaloniaProperty.RegisterDirect(
+ nameof(ValidatedDirectString),
+ o => o.ValidatedDirectString,
+ (o, v) => o.ValidatedDirectString = v,
enableDataValidation: true);
private int _nonValidatedDirect;
- private int _direct;
+ private int _directInt;
+ private string _directString;
public int NonValidated
{
@@ -122,14 +155,20 @@ namespace Avalonia.Base.UnitTests
public int NonValidatedDirect
{
- get { return _direct; }
+ get { return _directInt; }
set { SetAndRaise(NonValidatedDirectProperty, ref _nonValidatedDirect, value); }
}
- public int ValidatedDirect
+ public int ValidatedDirectInt
+ {
+ get { return _directInt; }
+ set { SetAndRaise(ValidatedDirectIntProperty, ref _directInt, value); }
+ }
+
+ public string ValidatedDirectString
{
- get { return _direct; }
- set { SetAndRaise(ValidatedDirectProperty, ref _direct, value); }
+ get { return _directString; }
+ set { SetAndRaise(ValidatedDirectStringProperty, ref _directString, value); }
}
public IList Notifications { get; } = new List();
@@ -139,5 +178,16 @@ namespace Avalonia.Base.UnitTests
Notifications.Add(notification);
}
}
+
+ public class ViewModel : NotifyingBase
+ {
+ private string _stringValue;
+
+ public string StringValue
+ {
+ get { return _stringValue; }
+ set { _stringValue = value; RaisePropertyChanged(); }
+ }
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
index 6482fcb4da..58d205deaa 100644
--- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
@@ -16,6 +16,60 @@ namespace Avalonia.Controls.UnitTests
private Mock popupImpl;
private MouseTestHelper _mouse = new MouseTestHelper();
+ [Fact]
+ public void Opening_Raises_Single_Opened_Event()
+ {
+ using (Application())
+ {
+ var sut = new ContextMenu();
+ var target = new Panel
+ {
+ ContextMenu = sut
+ };
+
+ new Window { Content = target };
+
+ int openedCount = 0;
+
+ sut.MenuOpened += (sender, args) =>
+ {
+ openedCount++;
+ };
+
+ sut.Open(null);
+
+ Assert.Equal(1, openedCount);
+ }
+ }
+
+ [Fact]
+ public void Closing_Raises_Single_Closed_Event()
+ {
+ using (Application())
+ {
+ var sut = new ContextMenu();
+ var target = new Panel
+ {
+ ContextMenu = sut
+ };
+
+ new Window { Content = target };
+
+ sut.Open(null);
+
+ int closedCount = 0;
+
+ sut.MenuClosed += (sender, args) =>
+ {
+ closedCount++;
+ };
+
+ sut.Close();
+
+ Assert.Equal(1, closedCount);
+ }
+ }
+
[Fact]
public void Clicking_On_Control_Toggles_ContextMenu()
{
diff --git a/tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs b/tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs
index 9b4be59647..70410dff0d 100644
--- a/tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs
+++ b/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(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);
}
diff --git a/tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTypedTests.cs b/tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTypedTests.cs
index f63c0efbf9..05954cbcd2 100644
--- a/tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTypedTests.cs
+++ b/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);
}
diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
index 2599d24354..b2839360ee 100644
--- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
+++ b/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- (x => x.Value),
- };
-
- target.ApplyTemplate();
- target.Presenter.ApplyTemplate();
-
- var text = target.Presenter.Panel.Children
- .Cast()
- .Select(x => x.Content)
- .ToList();
-
- Assert.Equal(new[] { "Foo", "Bar" }, text);
- }
-
[Fact]
public void Control_Item_Should_Not_Be_NameScope()
{
@@ -563,7 +542,6 @@ namespace Avalonia.Controls.UnitTests
Child = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
- MemberSelector = parent.MemberSelector,
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
}.RegisterInNameScope(scope)
};
diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
index 7ca11d9bed..274ca335d9 100644
--- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
+++ b/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
- (x => x.Value),
- };
-
- target.ApplyTemplate();
-
- var text = target.Panel.Children
- .Cast()
- .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
- (x => x.Value),
- };
-
- target.ApplyTemplate();
-
- var dataContexts = target.Panel.Children
- .Cast()
- .Do(x => x.UpdateChild())
- .Select(x => x.DataContext)
- .ToList();
-
- Assert.Equal(new[] { "Foo", "Bar" }, dataContexts);
- }
-
private class Item
{
public Item(string value)
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
index e266150901..2e22725125 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Linq;
using Moq;
using Avalonia.Controls.Presenters;
@@ -185,6 +186,53 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
}
+ [Fact]
+ public void Popup_Open_Should_Raise_Single_Opened_Event()
+ {
+ using (CreateServices())
+ {
+ var window = new Window();
+ var target = new Popup();
+
+ window.Content = target;
+
+ int openedCount = 0;
+
+ target.Opened += (sender, args) =>
+ {
+ openedCount++;
+ };
+
+ target.Open();
+
+ Assert.Equal(1, openedCount);
+ }
+ }
+
+ [Fact]
+ public void Popup_Close_Should_Raise_Single_Closed_Event()
+ {
+ using (CreateServices())
+ {
+ var window = new Window();
+ var target = new Popup();
+
+ window.Content = target;
+ target.Open();
+
+ int closedCount = 0;
+
+ target.Closed += (sender, args) =>
+ {
+ closedCount++;
+ };
+
+ target.Close();
+
+ Assert.Equal(1, closedCount);
+ }
+ }
+
[Fact]
public void PopupRoot_Should_Have_Template_Applied()
{
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
index 9d0cc368e0..4bcfeb6d03 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
@@ -53,7 +53,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
[Fact]
- public void Assigning_SelectedItems_Should_Set_SelectedIndex()
+ public void Assigning_Single_SelectedItems_Should_Set_SelectedIndex()
{
var target = new TestSelector
{
@@ -62,9 +62,51 @@ namespace Avalonia.Controls.UnitTests.Primitives
};
target.ApplyTemplate();
+ target.Presenter.ApplyTemplate();
target.SelectedItems = new AvaloniaList("bar");
Assert.Equal(1, target.SelectedIndex);
+ Assert.Equal(new[] { "bar" }, target.SelectedItems);
+ Assert.Equal(new[] { 1 }, SelectedContainers(target));
+ }
+
+ [Fact]
+ public void Assigning_Multiple_SelectedItems_Should_Set_SelectedIndex()
+ {
+ // Note that we don't need SelectionMode = Multiple here. Multiple selections can always
+ // be made in code.
+ var target = new TestSelector
+ {
+ Items = new[] { "foo", "bar", "baz" },
+ Template = Template(),
+ };
+
+ target.ApplyTemplate();
+ target.Presenter.ApplyTemplate();
+ target.SelectedItems = new AvaloniaList("foo", "bar", "baz");
+
+ Assert.Equal(0, target.SelectedIndex);
+ Assert.Equal(new[] { "foo", "bar", "baz" }, target.SelectedItems);
+ Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target));
+ }
+
+ [Fact]
+ public void Selected_Items_Should_Be_Marked_When_Panel_Created_After_SelectedItems_Is_Set()
+ {
+ // Issue #2565.
+ var target = new TestSelector
+ {
+ Items = new[] { "foo", "bar", "baz" },
+ Template = Template(),
+ };
+
+ target.ApplyTemplate();
+ target.SelectedItems = new AvaloniaList("foo", "bar", "baz");
+ target.Presenter.ApplyTemplate();
+
+ Assert.Equal(0, target.SelectedIndex);
+ Assert.Equal(new[] { "foo", "bar", "baz" }, target.SelectedItems);
+ Assert.Equal(new[] { 0, 1, 2 }, SelectedContainers(target));
}
[Fact]
@@ -1026,6 +1068,71 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.Equal(1, target.SelectedItems.Count);
}
+ [Fact]
+ public void Adding_Selected_ItemContainers_Should_Update_Selection()
+ {
+ var items = new AvaloniaList(new[]
+ {
+ new ItemContainer(),
+ new ItemContainer(),
+ });
+
+ var target = new TestSelector
+ {
+ Items = items,
+ Template = Template(),
+ };
+
+ target.ApplyTemplate();
+ target.Presenter.ApplyTemplate();
+ items.Add(new ItemContainer { IsSelected = true });
+ items.Add(new ItemContainer { IsSelected = true });
+
+ Assert.Equal(2, target.SelectedIndex);
+ Assert.Equal(items[2], target.SelectedItem);
+ Assert.Equal(new[] { items[2], items[3] }, target.SelectedItems);
+ }
+
+ [Fact]
+ public void Shift_Right_Click_Should_Not_Select_Multiple()
+ {
+ var target = new ListBox
+ {
+ Template = Template(),
+ Items = new[] { "Foo", "Bar", "Baz" },
+ ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }),
+ SelectionMode = SelectionMode.Multiple,
+ };
+
+ target.ApplyTemplate();
+ target.Presenter.ApplyTemplate();
+
+ _helper.Click((Interactive)target.Presenter.Panel.Children[0]);
+ _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: InputModifiers.Shift);
+
+ Assert.Equal(1, target.SelectedItems.Count);
+ }
+
+ [Fact]
+ public void Ctrl_Right_Click_Should_Not_Select_Multiple()
+ {
+ var target = new ListBox
+ {
+ Template = Template(),
+ Items = new[] { "Foo", "Bar", "Baz" },
+ ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }),
+ SelectionMode = SelectionMode.Multiple,
+ };
+
+ target.ApplyTemplate();
+ target.Presenter.ApplyTemplate();
+
+ _helper.Click((Interactive)target.Presenter.Panel.Children[0]);
+ _helper.Click((Interactive)target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: InputModifiers.Control);
+
+ Assert.Equal(1, target.SelectedItems.Count);
+ }
+
private IEnumerable SelectedContainers(SelectingItemsControl target)
{
return target.Presenter.Panel.Children
@@ -1078,5 +1185,11 @@ namespace Avalonia.Controls.UnitTests.Primitives
public List Items { get; }
public List SelectedItems { get; }
}
+
+ private class ItemContainer : Control, ISelectable
+ {
+ public string Value { get; set; }
+ public bool IsSelected { get; set; }
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs
index a7b90afa70..b4570ec229 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs
+++ b/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(x => x.Header == "foo"),
- Mock.Of(x => x.Header == "bar"),
-#pragma warning restore CS0252 // Possible unintended reference comparison; left hand side needs cast
- };
-
- var target = new TabStrip
- {
- Template = new FuncControlTemplate(CreateTabStripTemplate),
- Items = items,
- };
-
- target.ApplyTemplate();
- target.Presenter.ApplyTemplate();
-
- var result = target.GetLogicalChildren()
- .OfType()
- .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(CreateTabStripTemplate),
- Items = items,
- };
-
- target.ApplyTemplate();
- target.Presenter.ApplyTemplate();
-
- var result = target.GetLogicalChildren()
- .OfType()
- .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],
}.RegisterInNameScope(scope);
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
index f40571bc39..35f0b39210 100644
--- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
@@ -444,6 +444,22 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void Setting_Bound_Text_To_Null_Works()
+ {
+ using (UnitTestApplication.Start(Services))
+ {
+ var source = new Class1 { Bar = "bar" };
+ var target = new TextBox { DataContext = source };
+
+ target.Bind(TextBox.TextProperty, new Binding("Bar"));
+
+ Assert.Equal("bar", target.Text);
+ source.Bar = null;
+ Assert.Null(target.Text);
+ }
+ }
+
private static TestServices FocusServices => TestServices.MockThreadingInterface.With(
focusManager: new FocusManager(),
keyboardDevice: () => new KeyboardDevice(),
@@ -492,12 +508,19 @@ namespace Avalonia.Controls.UnitTests
private class Class1 : NotifyingBase
{
private int _foo;
+ private string _bar;
public int Foo
{
get { return _foo; }
set { _foo = value; RaisePropertyChanged(); }
}
+
+ public string Bar
+ {
+ get { return _bar; }
+ set { _bar = value; RaisePropertyChanged(); }
+ }
}
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
index 2868928455..5646e86f7a 100644
--- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
@@ -11,6 +11,7 @@ using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Input;
using Avalonia.Input.Platform;
+using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.UnitTests;
using Xunit;
@@ -719,6 +720,129 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void Right_Click_On_SelectedItem_Should_Not_Clear_Existing_Selection()
+ {
+ var tree = CreateTestTreeData();
+ var target = new TreeView
+ {
+ Template = CreateTreeViewTemplate(),
+ Items = tree,
+ SelectionMode = SelectionMode.Multiple,
+ };
+
+ var visualRoot = new TestRoot();
+ visualRoot.Child = target;
+
+ CreateNodeDataTemplate(target);
+ ApplyTemplates(target);
+ target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
+ target.SelectAll();
+
+ AssertChildrenSelected(target, tree[0]);
+ Assert.Equal(5, target.SelectedItems.Count);
+
+ _mouse.Click((Interactive)target.Presenter.Panel.Children[0], MouseButton.Right);
+
+ Assert.Equal(5, target.SelectedItems.Count);
+ }
+
+ [Fact]
+ public void Right_Click_On_UnselectedItem_Should_Clear_Existing_Selection()
+ {
+ var tree = CreateTestTreeData();
+ var target = new TreeView
+ {
+ Template = CreateTreeViewTemplate(),
+ Items = tree,
+ SelectionMode = SelectionMode.Multiple,
+ };
+
+ var visualRoot = new TestRoot();
+ visualRoot.Child = target;
+
+ CreateNodeDataTemplate(target);
+ ApplyTemplates(target);
+ target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
+
+ var rootNode = tree[0];
+ var to = rootNode.Children[0];
+ var then = rootNode.Children[1];
+
+ var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(rootNode);
+ var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
+ var thenContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(then);
+
+ ClickContainer(fromContainer, InputModifiers.None);
+ ClickContainer(toContainer, InputModifiers.Shift);
+
+ Assert.Equal(2, target.SelectedItems.Count);
+
+ _mouse.Click(thenContainer, MouseButton.Right);
+
+ Assert.Equal(1, target.SelectedItems.Count);
+ }
+
+ [Fact]
+ public void Shift_Right_Click_Should_Not_Select_Multiple()
+ {
+ var tree = CreateTestTreeData();
+ var target = new TreeView
+ {
+ Template = CreateTreeViewTemplate(),
+ Items = tree,
+ SelectionMode = SelectionMode.Multiple,
+ };
+
+ var visualRoot = new TestRoot();
+ visualRoot.Child = target;
+
+ CreateNodeDataTemplate(target);
+ ApplyTemplates(target);
+ target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
+
+ var rootNode = tree[0];
+ var from = rootNode.Children[0];
+ var to = rootNode.Children[1];
+ var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
+ var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
+
+ _mouse.Click(fromContainer);
+ _mouse.Click(toContainer, MouseButton.Right, modifiers: InputModifiers.Shift);
+
+ Assert.Equal(1, target.SelectedItems.Count);
+ }
+
+ [Fact]
+ public void Ctrl_Right_Click_Should_Not_Select_Multiple()
+ {
+ var tree = CreateTestTreeData();
+ var target = new TreeView
+ {
+ Template = CreateTreeViewTemplate(),
+ Items = tree,
+ SelectionMode = SelectionMode.Multiple,
+ };
+
+ var visualRoot = new TestRoot();
+ visualRoot.Child = target;
+
+ CreateNodeDataTemplate(target);
+ ApplyTemplates(target);
+ target.ExpandSubTree((TreeViewItem)target.Presenter.Panel.Children[0]);
+
+ var rootNode = tree[0];
+ var from = rootNode.Children[0];
+ var to = rootNode.Children[1];
+ var fromContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(from);
+ var toContainer = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(to);
+
+ _mouse.Click(fromContainer);
+ _mouse.Click(toContainer, MouseButton.Right, modifiers: InputModifiers.Control);
+
+ Assert.Equal(1, target.SelectedItems.Count);
+ }
+
private void ApplyTemplates(TreeView tree)
{
tree.ApplyTemplate();
@@ -853,7 +977,6 @@ namespace Avalonia.Controls.UnitTests
}
}
-
private class Node : NotifyingBase
{
private IAvaloniaList _children;
diff --git a/tests/Avalonia.LeakTests/MemberSelectorTests.cs b/tests/Avalonia.LeakTests/MemberSelectorTests.cs
deleted file mode 100644
index ffee18ae0a..0000000000
--- a/tests/Avalonia.LeakTests/MemberSelectorTests.cs
+++ /dev/null
@@ -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; }
- }
- }
-}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs
deleted file mode 100644
index aa1e56f2a5..0000000000
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs
+++ /dev/null
@@ -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; }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs
index 8769bf2b8b..d300877f0b 100644
--- a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs
+++ b/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs
@@ -106,7 +106,6 @@ namespace Avalonia.ReactiveUI.UnitTests
Child = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
- MemberSelector = parent.MemberSelector,
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
}.RegisterInNameScope(scope)
};