From 67bd1b8d86744ac65f4427b0b85239856c6b71ef Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 25 Jun 2019 21:28:56 +0200 Subject: [PATCH 01/37] Added failing tests for #1701. --- .../AvaloniaObjectTests_DataValidation.cs | 78 +++++++++++++++---- .../TextBoxTests.cs | 23 ++++++ 2 files changed, 87 insertions(+), 14 deletions(-) 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/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 932aada64e..cef5fe61fc 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(); } + } } } } From ecabeba4d15540168507822472f917c58bd768ae Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 25 Jun 2019 22:49:02 +0200 Subject: [PATCH 02/37] Fix conversion of null in DefaultValueConverter. `null` is a valid value for a non-value type so don't convert it to `{unset}`. Fixes #1701. --- src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 11a3f0c0934204410f7e1eb2848a8cf627161564 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 27 Jun 2019 01:07:37 +0200 Subject: [PATCH 03/37] Added failing test for #2565. Along with a passing test I wrote looking for the solution, and some documentation about SelectionMode. --- src/Avalonia.Controls/ListBox.cs | 8 +++- .../Primitives/SelectingItemsControl.cs | 4 ++ .../SelectingItemsControlTests_Multiple.cs | 44 ++++++++++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs index 3150b6be91..f26cd47bcb 100644 --- a/src/Avalonia.Controls/ListBox.cs +++ b/src/Avalonia.Controls/ListBox.cs @@ -68,7 +68,13 @@ namespace Avalonia.Controls /// public new IList SelectedItems => base.SelectedItems; - /// + /// + /// Gets or sets the selection mode. + /// + /// + /// Note that the selection mode only applies to selections made via user interaction. + /// Multiple selections can be made programatically regardless of the value of this property. + /// public new SelectionMode SelectionMode { get { return base.SelectionMode; } diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index 91a9fa7e40..6f7bf4eb3f 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -222,6 +222,10 @@ namespace Avalonia.Controls.Primitives /// /// Gets or sets the selection mode. /// + /// + /// Note that the selection mode only applies to selections made via user interaction. + /// Multiple selections can be made programatically regardless of the value of this property. + /// protected SelectionMode SelectionMode { get { return GetValue(SelectionModeProperty); } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs index a33d97779e..a44e23096f 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] From fc9a8db010acd04949de0814461aed10a636ff27 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 27 Jun 2019 01:08:29 +0200 Subject: [PATCH 04/37] Correctly select materialized containers. And add another test. --- .../Primitives/SelectingItemsControl.cs | 34 +++++++++++++------ .../SelectingItemsControlTests_Multiple.cs | 31 +++++++++++++++++ 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index 6f7bf4eb3f..4f01f5467b 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -342,24 +342,36 @@ namespace Avalonia.Controls.Primitives { base.OnContainersMaterialized(e); - var selectedIndex = SelectedIndex; - var selectedContainer = e.Containers - .FirstOrDefault(x => (x.ContainerControl as ISelectable)?.IsSelected == true); + var resetSelectedItems = false; - if (selectedContainer != null) + foreach (var container in e.Containers) { - SelectedIndex = selectedContainer.Index; - } - else if (selectedIndex >= e.StartingIndex && - selectedIndex < e.StartingIndex + e.Containers.Count) - { - var container = e.Containers[selectedIndex - e.StartingIndex]; + if ((container.ContainerControl as ISelectable)?.IsSelected == true) + { + if (SelectedIndex == -1) + { + SelectedIndex = container.Index; + } + else + { + if (_selection.Add(container.Index)) + { + resetSelectedItems = true; + } + } - if (container.ContainerControl != null) + MarkContainerSelected(container.ContainerControl, true); + } + else if (_selection.Contains(container.Index)) { MarkContainerSelected(container.ContainerControl, true); } } + + if (resetSelectedItems) + { + ResetSelectedItems(); + } } /// diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs index a44e23096f..2faced358b 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs @@ -1068,6 +1068,31 @@ 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); + } + private IEnumerable SelectedContainers(SelectingItemsControl target) { return target.Presenter.Panel.Children @@ -1120,5 +1145,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; } + } } } From 2fa8247f014af936577b1dbaf6372d281fbb168c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 27 Jun 2019 10:55:27 +0200 Subject: [PATCH 05/37] Removed MemberSelector. --- .../Pages/AutoCompleteBoxPage.xaml | 4 - samples/ControlCatalog/SideBar.xaml | 3 +- samples/RenderDemo/SideBar.xaml | 5 +- src/Avalonia.Controls/AutoCompleteBox.cs | 26 --- src/Avalonia.Controls/ComboBox.cs | 3 +- .../Generators/IItemContainerGenerator.cs | 12 +- .../Generators/ItemContainerGenerator.cs | 17 +- .../Generators/ItemContainerGenerator`1.cs | 14 +- .../Generators/TreeItemContainerGenerator.cs | 5 +- src/Avalonia.Controls/ItemsControl.cs | 15 -- .../Presenters/CarouselPresenter.cs | 2 +- .../Presenters/ItemContainerSync.cs | 2 +- .../Presenters/ItemVirtualizerNone.cs | 2 +- .../Presenters/ItemVirtualizerSimple.cs | 9 +- .../Presenters/ItemsPresenterBase.cs | 15 -- src/Avalonia.Controls/Primitives/TabStrip.cs | 9 - .../Templates/FuncMemberSelector.cs | 35 ---- .../Templates/IMemberSelector.cs | 18 -- .../AutoCompleteBox.xaml | 1 - src/Avalonia.Themes.Default/Carousel.xaml | 3 +- src/Avalonia.Themes.Default/ComboBox.xaml | 1 - .../DataValidationErrors.xaml | 2 +- src/Avalonia.Themes.Default/ItemsControl.xaml | 5 +- src/Avalonia.Themes.Default/ListBox.xaml | 3 +- src/Avalonia.Themes.Default/MenuItem.xaml | 6 +- src/Avalonia.Themes.Default/TabControl.xaml | 3 +- src/Avalonia.Themes.Default/TabStrip.xaml | 3 +- src/Avalonia.Themes.Default/TreeView.xaml | 3 +- src/Avalonia.Themes.Default/TreeViewItem.xaml | 3 +- .../Avalonia.Markup.Xaml.csproj | 2 - .../Converters/MemberSelectorTypeConverter.cs | 24 --- .../Templates/MemberSelector.cs | 48 ------ .../AvaloniaXamlIlLanguage.cs | 2 - .../Generators/ItemContainerGeneratorTests.cs | 6 +- .../ItemContainerGeneratorTypedTests.cs | 2 +- .../ItemsControlTests.cs | 22 --- .../Presenters/ItemsPresenterTests.cs | 40 ----- .../Primitives/TabStripTests.cs | 55 ------ .../Avalonia.LeakTests/MemberSelectorTests.cs | 55 ------ .../Templates/MemberSelectorTests.cs | 159 ------------------ .../AutoDataTemplateBindingHookTest.cs | 3 +- 41 files changed, 36 insertions(+), 611 deletions(-) delete mode 100644 src/Avalonia.Controls/Templates/FuncMemberSelector.cs delete mode 100644 src/Avalonia.Controls/Templates/IMemberSelector.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs delete mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs delete mode 100644 tests/Avalonia.LeakTests/MemberSelectorTests.cs delete mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Templates/MemberSelectorTests.cs 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 @@ - - + ItemTemplate="{TemplateBinding ItemTemplate}"> + ItemTemplate="{TemplateBinding ItemTemplate}"> - \ No newline at end of file + diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs index b87e10d284..787abc1891 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/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 304c86dbf7..fce7579ec0 100644 --- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs +++ b/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) { 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(); private int _itemCount; private IItemContainerGenerator _itemContainerGenerator; @@ -144,15 +138,6 @@ namespace Avalonia.Controls set { SetValue(ItemTemplateProperty, value); } } - /// - /// Selects a member from to use as the list item. - /// - public IMemberSelector MemberSelector - { - get { return GetValue(MemberSelectorProperty); } - set { SetValue(MemberSelectorProperty, value); } - } - /// /// Gets the items presenter control. /// diff --git a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs index a3123cf8c6..dedab3e43e 100644 --- a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs +++ b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs @@ -213,7 +213,7 @@ namespace Avalonia.Controls.Presenters if (container == null && IsVirtualized) { var item = Items.Cast().ElementAt(index); - var materialized = ItemContainerGenerator.Materialize(index, item, MemberSelector); + var materialized = ItemContainerGenerator.Materialize(index, item); Panel.Children.Add(materialized.ContainerControl); container = materialized.ContainerControl; } diff --git a/src/Avalonia.Controls/Presenters/ItemContainerSync.cs b/src/Avalonia.Controls/Presenters/ItemContainerSync.cs index 035d404dec..6e72908e6b 100644 --- a/src/Avalonia.Controls/Presenters/ItemContainerSync.cs +++ b/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) { diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs index 413855bcc6..56f64779f6 100644 --- a/src/Avalonia.Controls/Presenters/ItemVirtualizerNone.cs +++ b/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) { diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs index d11ce9a7ea..b8b8094582 100644 --- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs +++ b/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(); } diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs index b4b792139d..ea56a0c6fc 100644 --- a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs +++ b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs @@ -35,12 +35,6 @@ namespace Avalonia.Controls.Presenters public static readonly StyledProperty ItemTemplateProperty = ItemsControl.ItemTemplateProperty.AddOwner(); - /// - /// Defines the property. - /// - public static readonly StyledProperty MemberSelectorProperty = - ItemsControl.MemberSelectorProperty.AddOwner(); - private IEnumerable _items; private IDisposable _itemsSubscription; private bool _createdPanel; @@ -127,15 +121,6 @@ namespace Avalonia.Controls.Presenters set { SetValue(ItemTemplateProperty, value); } } - /// - /// Selects a member from to use as the list item. - /// - public IMemberSelector MemberSelector - { - get { return GetValue(MemberSelectorProperty); } - set { SetValue(MemberSelectorProperty, value); } - } - /// /// Gets the panel used to display the items. /// 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(SelectHeader); - static TabStrip() { - MemberSelectorProperty.OverrideDefaultValue(s_MemberSelector); SelectionModeProperty.OverrideDefaultValue(SelectionMode.AlwaysSelected); FocusableProperty.OverrideDefaultValue(typeof(TabStrip), false); ItemsPanelProperty.OverrideDefaultValue(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; - } } } diff --git a/src/Avalonia.Controls/Templates/FuncMemberSelector.cs b/src/Avalonia.Controls/Templates/FuncMemberSelector.cs deleted file mode 100644 index 5ab186261e..0000000000 --- a/src/Avalonia.Controls/Templates/FuncMemberSelector.cs +++ /dev/null @@ -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 -{ - /// - /// Selects a member of an object using a . - /// - public class FuncMemberSelector : IMemberSelector - { - private readonly Func _selector; - - /// - /// Initializes a new instance of the - /// class. - /// - /// The selector. - public FuncMemberSelector(Func selector) - { - this._selector = selector; - } - - /// - /// Selects a member of an object. - /// - /// The object. - /// The selected member. - public object Select(object o) - { - return (o is TObject) ? _selector((TObject)o) : default(TMember); - } - } -} diff --git a/src/Avalonia.Controls/Templates/IMemberSelector.cs b/src/Avalonia.Controls/Templates/IMemberSelector.cs deleted file mode 100644 index e1ec42a849..0000000000 --- a/src/Avalonia.Controls/Templates/IMemberSelector.cs +++ /dev/null @@ -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 -{ - /// - /// Selects a member of an object. - /// - public interface IMemberSelector - { - /// - /// Selects a member of an object. - /// - /// The object. - /// The selected member. - object Select(object o); - } -} diff --git a/src/Avalonia.Themes.Default/AutoCompleteBox.xaml b/src/Avalonia.Themes.Default/AutoCompleteBox.xaml index 11d8a344d9..788b60892b 100644 --- a/src/Avalonia.Themes.Default/AutoCompleteBox.xaml +++ b/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" /> diff --git a/src/Avalonia.Themes.Default/Carousel.xaml b/src/Avalonia.Themes.Default/Carousel.xaml index efe12c4333..955a49a974 100644 --- a/src/Avalonia.Themes.Default/Carousel.xaml +++ b/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}"/> - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/ComboBox.xaml b/src/Avalonia.Themes.Default/ComboBox.xaml index ca6c2e372e..6227962a48 100644 --- a/src/Avalonia.Themes.Default/ComboBox.xaml +++ b/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}" /> diff --git a/src/Avalonia.Themes.Default/DataValidationErrors.xaml b/src/Avalonia.Themes.Default/DataValidationErrors.xaml index 0c40a7eb25..f4145a51f5 100644 --- a/src/Avalonia.Themes.Default/DataValidationErrors.xaml +++ b/src/Avalonia.Themes.Default/DataValidationErrors.xaml @@ -29,7 +29,7 @@ - + diff --git a/src/Avalonia.Themes.Default/ItemsControl.xaml b/src/Avalonia.Themes.Default/ItemsControl.xaml index 7b6671b42c..f3def542fc 100644 --- a/src/Avalonia.Themes.Default/ItemsControl.xaml +++ b/src/Avalonia.Themes.Default/ItemsControl.xaml @@ -4,8 +4,7 @@ + ItemTemplate="{TemplateBinding ItemTemplate}"/> - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/ListBox.xaml b/src/Avalonia.Themes.Default/ListBox.xaml index 57b0c541b8..59c596bcaa 100644 --- a/src/Avalonia.Themes.Default/ListBox.xaml +++ b/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}"/> - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml index be86e8b14c..a794d15577 100644 --- a/src/Avalonia.Themes.Default/MenuItem.xaml +++ b/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"/> + Margin="2"/> + ItemTemplate="{TemplateBinding ItemTemplate}"> @@ -18,4 +17,4 @@ - \ No newline at end of file + diff --git a/src/Avalonia.Themes.Default/TreeView.xaml b/src/Avalonia.Themes.Default/TreeView.xaml index 4e38c6db3a..6ed2fd17b8 100644 --- a/src/Avalonia.Themes.Default/TreeView.xaml +++ b/src/Avalonia.Themes.Default/TreeView.xaml @@ -15,8 +15,7 @@ + Margin="{TemplateBinding Padding}"/> diff --git a/src/Avalonia.Themes.Default/TreeViewItem.xaml b/src/Avalonia.Themes.Default/TreeViewItem.xaml index b5e0e7a005..5dd082cf7a 100644 --- a/src/Avalonia.Themes.Default/TreeViewItem.xaml +++ b/src/Avalonia.Themes.Default/TreeViewItem.xaml @@ -32,8 +32,7 @@ + ItemsPanel="{TemplateBinding ItemsPanel}"/> 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 c25e1186d0..830e354274 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/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"); 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 3cf886ade4..ca945c66bf 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() { @@ -586,7 +565,6 @@ namespace Avalonia.Controls.UnitTests Child = new ItemsPresenter { Name = "PART_ItemsPresenter", - MemberSelector = parent.MemberSelector, [~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty], } }; diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs index 3d13e4c32f..0c9d36ba3a 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/TabStripTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs index 55b3d6f756..622169f8f6 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], }; } } 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 667462eb91..b8fd7d166d 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs +++ b/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], } }; }); } } -} \ No newline at end of file +} From 139475de1c26323c62ddef0f2031c4a7094a7c95 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 27 Jun 2019 11:23:11 +0200 Subject: [PATCH 06/37] Added TabStripPage to ControlCatalog. To make sure that everything still works with TabStrip. --- samples/ControlCatalog/MainView.xaml | 1 + .../ControlCatalog/Pages/TabStripPage.xaml | 33 ++++++++++++++ .../ControlCatalog/Pages/TabStripPage.xaml.cs | 45 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 samples/ControlCatalog/Pages/TabStripPage.xaml create mode 100644 samples/ControlCatalog/Pages/TabStripPage.xaml.cs 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/TabStripPage.xaml b/samples/ControlCatalog/Pages/TabStripPage.xaml new file mode 100644 index 0000000000..a824336f75 --- /dev/null +++ b/samples/ControlCatalog/Pages/TabStripPage.xaml @@ -0,0 +1,33 @@ + + + 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; + } + } +} From fa55755b71015567d25c4e183a29ec9f3c53354c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 3 Jul 2019 23:29:19 +0300 Subject: [PATCH 07/37] Manually handle name scope registrations --- src/Avalonia.Controls/AutoCompleteBox.cs | 2 +- .../Embedding/EmbeddableControlRoot.cs | 21 +---- .../Embedding/Offscreen/OffscreenTopLevel.cs | 19 ----- .../Generators/TreeItemContainerGenerator.cs | 14 +++- .../Presenters/ContentPresenter.cs | 6 -- .../Primitives/TemplatedControl.cs | 30 ++----- .../Templates/FuncControlTemplate.cs | 4 +- .../Templates/FuncControlTemplate`2.cs | 6 +- .../Templates/FuncDataTemplate.cs | 8 +- .../Templates/FuncDataTemplate`1.cs | 26 +++++- .../FuncTemplateNameScopeExtensions.cs | 24 ++++++ .../Templates/FuncTemplate`2.cs | 13 ++- .../Templates/FuncTreeDataTemplate.cs | 4 +- .../Templates/FuncTreeDataTemplate`1.cs | 15 +++- src/Avalonia.Controls/UserControl.cs | 34 +------- src/Avalonia.Controls/Window.cs | 34 +------- .../AutoDataTemplateBindingHook.cs | 4 +- src/Avalonia.Styling/Controls/NameScope.cs | 15 ++++ .../Controls/NameScopeExtensions.cs | 41 ++++++++++ src/Avalonia.Styling/StyledElement.cs | 21 ----- src/Avalonia.Styling/Styling/Setter.cs | 1 - .../AvaloniaXamlIlLanguage.cs | 1 + .../Transformers/AddNameScopeRegistration.cs | 69 ++++++++-------- .../AvaloniaXamlIlWellKnownTypes.cs | 12 +++ .../XamlIl/Runtime/XamlIlRuntimeHelpers.cs | 1 + .../Avalonia.Markup.Xaml/XamlIl/xamlil.github | 2 +- src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs | 8 ++ .../AutoCompleteBoxTests.cs | 10 +-- .../CarouselTests.cs | 4 +- .../ComboBoxTests.cs | 10 +-- .../ContentControlTests.cs | 12 +-- .../DatePickerTests.cs | 12 +-- .../GridSplitterTests.cs | 21 +++-- .../HeaderedItemsControlTests .cs | 6 +- .../ItemsControlTests.cs | 10 +-- .../ListBoxTests.cs | 30 +++---- .../ListBoxTests_Single.cs | 13 +-- .../Mixins/ContentControlMixinTests.cs | 17 ++-- .../ContentPresenterTests_InTemplate.cs | 18 ++-- .../ContentPresenterTests_Standalone.cs | 16 ++-- .../ContentPresenterTests_Unrooted.cs | 4 +- .../Presenters/ItemsPresenterTests.cs | 2 +- .../ItemsPresenterTests_Virtualization.cs | 2 +- ...emsPresenterTests_Virtualization_Simple.cs | 8 +- .../Primitives/PopupRootTests.cs | 6 +- .../Primitives/PopupTests.cs | 8 +- .../Primitives/RangeBaseTests.cs | 6 +- .../Primitives/ScrollBarTests.cs | 10 +-- .../Primitives/SelectingItemsControlTests.cs | 4 +- .../SelectingItemsControlTests_AutoSelect.cs | 4 +- .../SelectingItemsControlTests_Multiple.cs | 10 +-- .../Primitives/TabStripTests.cs | 4 +- .../Primitives/TemplatedControlTests.cs | 58 ++++++------- .../ScrollViewerTests.cs | 12 +-- .../TabControlTests.cs | 18 ++-- .../TextBoxTests.cs | 4 +- .../TextBoxTests_DataValidation.cs | 4 +- .../TopLevelTests.cs | 4 +- .../TreeViewTests.cs | 18 ++-- .../UserControlTests.cs | 6 +- .../Utils/HotKeyManagerTests.cs | 4 +- .../WindowBaseTests.cs | 4 +- .../Data/BindingTests_ElementName.cs | 10 ++- .../Data/MultiBindingTests_Converters.cs | 5 +- .../Data/TemplateBindingTests.cs | 6 +- .../MarkupExtensions/BindingExtensionTests.cs | 4 +- .../DynamicResourceExtensionTests.cs | 4 +- .../StaticResourceExtensionTests.cs | 4 +- .../AutoDataTemplateBindingHookTest.cs | 8 +- .../TransitioningContentControlTest.cs | 8 +- .../ControlLocatorTests.cs | 82 +++++++++++++++++-- .../SelectorTests_Multiple.cs | 12 +-- .../Avalonia.Styling.UnitTests/SetterTests.cs | 13 --- .../StyledElementTests.cs | 15 ---- .../StyledElementTests_NameScope.cs | 69 ---------------- .../StyledElementTests_Resources.cs | 4 +- tests/Avalonia.UnitTests/TestRoot.cs | 48 +++++------ tests/Avalonia.UnitTests/TestTemplatedRoot.cs | 33 +------- 78 files changed, 537 insertions(+), 602 deletions(-) create mode 100644 src/Avalonia.Controls/Templates/FuncTemplateNameScopeExtensions.cs delete mode 100644 tests/Avalonia.Styling.UnitTests/StyledElementTests_NameScope.cs diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs index b87e10d284..473c4fe21b 100644 --- a/src/Avalonia.Controls/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox.cs @@ -795,7 +795,7 @@ namespace Avalonia.Controls var template = new FuncDataTemplate( typeof(object), - o => + (o, _) => { var control = new ContentControl(); control.Bind(ContentControl.ContentProperty, value); diff --git a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs index 83d1c4aae3..2d48a7d33b 100644 --- a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs +++ b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs @@ -8,7 +8,7 @@ using JetBrains.Annotations; namespace Avalonia.Controls.Embedding { - public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, INameScope, IDisposable + public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, IDisposable { public EmbeddableControlRoot(IEmbeddableWindowImpl impl) : base(impl) { @@ -51,25 +51,6 @@ namespace Avalonia.Controls.Embedding return rv; } - private readonly NameScope _nameScope = new NameScope(); - public event EventHandler Registered - { - add { _nameScope.Registered += value; } - remove { _nameScope.Registered -= value; } - } - - public event EventHandler Unregistered - { - add { _nameScope.Unregistered += value; } - remove { _nameScope.Unregistered -= value; } - } - - public void Register(string name, object element) => _nameScope.Register(name, element); - - public object Find(string name) => _nameScope.Find(name); - - public void Unregister(string name) => _nameScope.Unregister(name); - Type IStyleable.StyleKey => typeof(EmbeddableControlRoot); public void Dispose() => PlatformImpl?.Dispose(); } diff --git a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs index c4f83ffd54..d326ab5734 100644 --- a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs +++ b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs @@ -30,25 +30,6 @@ namespace Avalonia.Controls.Embedding.Offscreen init.EndInit(); } } - - private readonly NameScope _nameScope = new NameScope(); - public event EventHandler Registered - { - add { _nameScope.Registered += value; } - remove { _nameScope.Registered -= value; } - } - - public event EventHandler Unregistered - { - add { _nameScope.Unregistered += value; } - remove { _nameScope.Unregistered -= value; } - } - - public void Register(string name, object element) => _nameScope.Register(name, element); - - public object Find(string name) => _nameScope.Find(name); - - public void Unregister(string name) => _nameScope.Unregister(name); Type IStyleable.StyleKey => typeof(EmbeddableControlRoot); public void Dispose() diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs index 304c86dbf7..43d1108fb9 100644 --- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs +++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs @@ -92,7 +92,6 @@ namespace Avalonia.Controls.Generators result.DataContext = item; } - NameScope.SetNameScope((Control)(object)result, new NameScope()); Index.Add(item, result); return result; @@ -123,11 +122,20 @@ namespace Avalonia.Controls.Generators return false; } + class WrapperTreeDataTemplate : ITreeDataTemplate + { + private readonly IDataTemplate _inner; + public WrapperTreeDataTemplate(IDataTemplate inner) => _inner = inner; + public IControl Build(object param) => _inner.Build(param); + public bool SupportsRecycling => _inner.SupportsRecycling; + public bool Match(object data) => _inner.Match(data); + public InstancedBinding ItemsSelector(object item) => null; + } + private ITreeDataTemplate GetTreeDataTemplate(object item, IDataTemplate primary) { var template = Owner.FindDataTemplate(item, primary) ?? FuncDataTemplate.Default; - var treeTemplate = template as ITreeDataTemplate ?? - new FuncTreeDataTemplate(typeof(object), template.Build, x => null); + var treeTemplate = template as ITreeDataTemplate ?? new WrapperTreeDataTemplate(template); return treeTemplate; } } diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index 49f268c128..c2690d503d 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -325,12 +325,6 @@ namespace Avalonia.Controls.Presenters { _dataTemplate = dataTemplate; newChild = _dataTemplate.Build(content); - - // Give the new control its own name scope. - if (newChild is Control controlResult) - { - NameScope.SetNameScope(controlResult, new NameScope()); - } } } else diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs index 32e220b789..2927a3c7b3 100644 --- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs +++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs @@ -258,13 +258,16 @@ namespace Avalonia.Controls.Primitives Logger.Verbose(LogArea.Control, this, "Creating control template"); var child = template.Build(this); - var nameScope = new NameScope(); - NameScope.SetNameScope((Control)child, nameScope); ApplyTemplatedParent(child); - RegisterNames(child, nameScope); ((ISetLogicalParent)child).SetParent(this); VisualChildren.Add(child); + var nameScope = (child is StyledElement styledChild) ? NameScope.GetNameScope(styledChild) : null; + + // Existing code kinda expect to see a NameScope even if it's empty + if (nameScope == null) + nameScope = new NameScope(); + OnTemplateApplied(new TemplateAppliedEventArgs(nameScope)); } @@ -342,26 +345,5 @@ namespace Avalonia.Controls.Primitives } } } - - /// - /// Registers each control with its name scope. - /// - /// The control. - /// The name scope. - private void RegisterNames(IControl control, INameScope nameScope) - { - if (control.Name != null) - { - nameScope.Register(control.Name, control); - } - - if (control.TemplatedParent == this) - { - foreach (IControl child in control.GetLogicalChildren()) - { - RegisterNames(child, nameScope); - } - } - } } } diff --git a/src/Avalonia.Controls/Templates/FuncControlTemplate.cs b/src/Avalonia.Controls/Templates/FuncControlTemplate.cs index 4c3c92309e..8a588b4089 100644 --- a/src/Avalonia.Controls/Templates/FuncControlTemplate.cs +++ b/src/Avalonia.Controls/Templates/FuncControlTemplate.cs @@ -16,9 +16,9 @@ namespace Avalonia.Controls.Templates /// Initializes a new instance of the class. /// /// The build function. - public FuncControlTemplate(Func build) + public FuncControlTemplate(Func build) : base(build) { } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs b/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs index 8e49b51cb8..eec7a6030f 100644 --- a/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs +++ b/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs @@ -17,9 +17,9 @@ namespace Avalonia.Controls.Templates /// Initializes a new instance of the class. /// /// The build function. - public FuncControlTemplate(Func build) - : base(x => build((T)x)) + public FuncControlTemplate(Func build) + : base((x, s) => build((T)x, s)) { } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs index 1d90fcd01e..204540e431 100644 --- a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs +++ b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs @@ -17,7 +17,7 @@ namespace Avalonia.Controls.Templates /// public static readonly FuncDataTemplate Default = new FuncDataTemplate( - data => + (data, s) => { if (data != null) { @@ -49,7 +49,7 @@ namespace Avalonia.Controls.Templates /// Whether the control can be recycled. public FuncDataTemplate( Type type, - Func build, + Func build, bool supportsRecycling = false) : this(o => IsInstance(o, type), build, supportsRecycling) { @@ -67,7 +67,7 @@ namespace Avalonia.Controls.Templates /// Whether the control can be recycled. public FuncDataTemplate( Func match, - Func build, + Func build, bool supportsRecycling = false) : base(build) { @@ -105,4 +105,4 @@ namespace Avalonia.Controls.Templates return (o != null) && t.GetTypeInfo().IsAssignableFrom(o.GetType().GetTypeInfo()); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs index 9339aa6924..68b737928d 100644 --- a/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs +++ b/src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs @@ -18,7 +18,7 @@ namespace Avalonia.Controls.Templates /// A function which when passed an object of returns a control. /// /// Whether the control can be recycled. - public FuncDataTemplate(Func build, bool supportsRecycling = false) + public FuncDataTemplate(Func build, bool supportsRecycling = false) : base(typeof(T), CastBuild(build), supportsRecycling) { } @@ -35,12 +35,30 @@ namespace Avalonia.Controls.Templates /// Whether the control can be recycled. public FuncDataTemplate( Func match, - Func build, + Func build, bool supportsRecycling = false) : base(CastMatch(match), CastBuild(build), supportsRecycling) { } + /// + /// Initializes a new instance of the class. + /// + /// + /// A function which determines whether the data template matches the specified data. + /// + /// + /// A function which when passed an object of returns a control. + /// + /// Whether the control can be recycled. + public FuncDataTemplate( + Func match, + Func build, + bool supportsRecycling = false) + : this(match, (a, _) => build(a), supportsRecycling) + { + } + /// /// Casts a strongly typed match function to a weakly typed one. /// @@ -57,9 +75,9 @@ namespace Avalonia.Controls.Templates /// The strong data type. /// The strongly typed function. /// The weakly typed function. - private static Func CastBuild(Func f) + private static Func CastBuild(Func f) { - return o => f((T)o); + return (o, s) => f((T)o, s); } } } diff --git a/src/Avalonia.Controls/Templates/FuncTemplateNameScopeExtensions.cs b/src/Avalonia.Controls/Templates/FuncTemplateNameScopeExtensions.cs new file mode 100644 index 0000000000..c9c083f9c7 --- /dev/null +++ b/src/Avalonia.Controls/Templates/FuncTemplateNameScopeExtensions.cs @@ -0,0 +1,24 @@ +using System; + +namespace Avalonia.Controls.Templates +{ + public static class FuncTemplateNameScopeExtensions + { + public static T RegisterInNameScope(this T control, INameScope scope) + where T : StyledElement + { + scope.Register(control.Name, control); + return control; + } + + public static T WithNameScope(this T control, INameScope scope) + where T : StyledElement + { + var existingScope = NameScope.GetNameScope(control); + if (existingScope != null && existingScope != scope) + throw new InvalidOperationException("Control already has a name scope"); + NameScope.SetNameScope(control, scope); + return control; + } + } +} diff --git a/src/Avalonia.Controls/Templates/FuncTemplate`2.cs b/src/Avalonia.Controls/Templates/FuncTemplate`2.cs index b1ce63fdf1..a779f796e7 100644 --- a/src/Avalonia.Controls/Templates/FuncTemplate`2.cs +++ b/src/Avalonia.Controls/Templates/FuncTemplate`2.cs @@ -13,13 +13,13 @@ namespace Avalonia.Controls.Templates public class FuncTemplate : ITemplate where TControl : IControl { - private readonly Func _func; + private readonly Func _func; /// /// Initializes a new instance of the class. /// /// The function used to create the control. - public FuncTemplate(Func func) + public FuncTemplate(Func func) { Contract.Requires(func != null); @@ -35,7 +35,12 @@ namespace Avalonia.Controls.Templates /// public TControl Build(TParam param) { - return _func(param); + var scope = new NameScope(); + var rv = _func(param, scope); + // TODO: May be return the name scope alongside with the control instead? + if (rv is StyledElement sl) + NameScope.SetNameScope(sl, scope); + return rv; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs index e7c9cf8608..998ef0e9f2 100644 --- a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs +++ b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs @@ -28,7 +28,7 @@ namespace Avalonia.Controls.Templates /// public FuncTreeDataTemplate( Type type, - Func build, + Func build, Func itemsSelector) : this(o => IsInstance(o, type), build, itemsSelector) { @@ -48,7 +48,7 @@ namespace Avalonia.Controls.Templates /// public FuncTreeDataTemplate( Func match, - Func build, + Func build, Func itemsSelector) : base(match, build) { diff --git a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs index 4ca96f60bd..41f870ab42 100644 --- a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs +++ b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs @@ -23,7 +23,7 @@ namespace Avalonia.Controls.Templates /// items. /// public FuncTreeDataTemplate( - Func build, + Func build, Func itemsSelector) : base( typeof(T), @@ -46,7 +46,7 @@ namespace Avalonia.Controls.Templates /// public FuncTreeDataTemplate( Func match, - Func build, + Func build, Func itemsSelector) : base( CastMatch(match), @@ -65,6 +65,17 @@ namespace Avalonia.Controls.Templates return o => (o is T) && f((T)o); } + /// + /// Casts a function with a typed parameter to an untyped function. + /// + /// The result. + /// The typed function. + /// The untyped function. + private static Func Cast(Func f) + { + return (o, s) => f((T)o, s); + } + /// /// Casts a function with a typed parameter to an untyped function. /// diff --git a/src/Avalonia.Controls/UserControl.cs b/src/Avalonia.Controls/UserControl.cs index e42ca5e0e6..4f15839821 100644 --- a/src/Avalonia.Controls/UserControl.cs +++ b/src/Avalonia.Controls/UserControl.cs @@ -9,40 +9,8 @@ namespace Avalonia.Controls /// /// Provides the base class for defining a new control that encapsulates related existing controls and provides its own logic. /// - public class UserControl : ContentControl, IStyleable, INameScope + public class UserControl : ContentControl, IStyleable { - private readonly NameScope _nameScope = new NameScope(); - /// - event EventHandler INameScope.Registered - { - add { _nameScope.Registered += value; } - remove { _nameScope.Registered -= value; } - } - - /// - event EventHandler INameScope.Unregistered - { - add { _nameScope.Unregistered += value; } - remove { _nameScope.Unregistered -= value; } - } - - /// - void INameScope.Register(string name, object element) - { - _nameScope.Register(name, element); - } - - /// - object INameScope.Find(string name) - { - return _nameScope.Find(name); - } - - /// - void INameScope.Unregister(string name) - { - _nameScope.Unregister(name); - } } } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 5c117f508b..d2793fe0dd 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -48,7 +48,7 @@ namespace Avalonia.Controls /// /// A top-level window. /// - public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot, INameScope + public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot { /// /// Defines the property. @@ -157,20 +157,6 @@ namespace Avalonia.Controls _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size); } - /// - event EventHandler INameScope.Registered - { - add { _nameScope.Registered += value; } - remove { _nameScope.Registered -= value; } - } - - /// - event EventHandler INameScope.Unregistered - { - add { _nameScope.Unregistered += value; } - remove { _nameScope.Unregistered -= value; } - } - /// /// Gets the platform-specific window implementation. /// @@ -494,24 +480,6 @@ namespace Avalonia.Controls } } - /// - void INameScope.Register(string name, object element) - { - _nameScope.Register(name, element); - } - - /// - object INameScope.Find(string name) - { - return _nameScope.Find(name); - } - - /// - void INameScope.Unregister(string name) - { - _nameScope.Unregister(name); - } - /// protected override Size MeasureOverride(Size availableSize) { diff --git a/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs b/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs index 3f41f54363..4881c77034 100644 --- a/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs +++ b/src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs @@ -16,7 +16,7 @@ namespace Avalonia.ReactiveUI /// public class AutoDataTemplateBindingHook : IPropertyBindingHook { - private static FuncDataTemplate DefaultItemTemplate = new FuncDataTemplate(x => + private static FuncDataTemplate DefaultItemTemplate = new FuncDataTemplate((x, _) => { var control = new ViewModelViewHost(); var context = control.GetObservable(Control.DataContextProperty); @@ -52,4 +52,4 @@ namespace Avalonia.ReactiveUI return true; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Styling/Controls/NameScope.cs b/src/Avalonia.Styling/Controls/NameScope.cs index e3a29af541..aeafa0bb0c 100644 --- a/src/Avalonia.Styling/Controls/NameScope.cs +++ b/src/Avalonia.Styling/Controls/NameScope.cs @@ -106,6 +106,21 @@ namespace Avalonia.Controls } } + /// + /// Registers an element in the name scope associated with the scopeElement. + /// Creates the scope if one isn't associated with the element yet + /// + /// + /// + /// + public static void Register(StyledElement scopeElement, string name, object element) + { + var scope = scopeElement as INameScope ?? GetNameScope(scopeElement); + if(scope == null) + SetNameScope(scopeElement, scope = new NameScope()); + scope.Register(name, element); + } + /// /// Finds a named element in the name scope. /// diff --git a/src/Avalonia.Styling/Controls/NameScopeExtensions.cs b/src/Avalonia.Styling/Controls/NameScopeExtensions.cs index 991a97a614..5921acd3b6 100644 --- a/src/Avalonia.Styling/Controls/NameScopeExtensions.cs +++ b/src/Avalonia.Styling/Controls/NameScopeExtensions.cs @@ -37,6 +37,25 @@ namespace Avalonia.Controls return (T)result; } + /// + /// Finds a named element in an . + /// + /// The element type. + /// The control to take the name scope from. + /// The name. + /// The named element or null if not found. + public static T Find(this ILogical anchor, string name) + where T : class + { + Contract.Requires(anchor != null); + Contract.Requires(name != null); + var styledAnchor = anchor as StyledElement; + if (styledAnchor == null) + return null; + var nameScope = (anchor as INameScope) ?? NameScope.GetNameScope(styledAnchor); + return nameScope?.Find(name); + } + /// /// Gets a named element from an or throws if no element of the /// requested name was found. @@ -67,6 +86,28 @@ namespace Avalonia.Controls return (T)result; } + /// + /// Gets a named element from an or throws if no element of the + /// requested name was found. + /// + /// The element type. + /// The control to take the name scope from. + /// The name. + /// The named element. + public static T Get(this ILogical anchor, string name) + where T : class + { + Contract.Requires(anchor != null); + Contract.Requires(name != null); + + var nameScope = (anchor as INameScope) ?? NameScope.GetNameScope((StyledElement)anchor); + if (nameScope == null) + throw new InvalidOperationException( + "The control doesn't have an associated name scope, probably no registrations has been done yet"); + + return nameScope.Get(name); + } + public static INameScope FindNameScope(this ILogical control) { Contract.Requires(control != null); diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index 146a4c75e7..b4aa89d5bf 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -61,7 +61,6 @@ namespace Avalonia private readonly Classes _classes = new Classes(); private bool _isAttachedToLogicalTree; private IAvaloniaList _logicalChildren; - private INameScope _nameScope; private IResourceDictionary _resources; private Styles _styles; private bool _styled; @@ -82,7 +81,6 @@ namespace Avalonia /// public StyledElement() { - _nameScope = this as INameScope; _isAttachedToLogicalTree = this is IStyleRoot; } @@ -381,7 +379,6 @@ namespace Avalonia { if (_initCount == 0 && (!_styled || force)) { - RegisterWithNameScope(); ApplyStyling(); _styled = true; } @@ -675,19 +672,6 @@ namespace Avalonia AvaloniaLocator.Current.GetService()?.ApplyStyles(this); } - private void RegisterWithNameScope() - { - if (_nameScope == null) - { - _nameScope = NameScope.GetNameScope(this) ?? ((StyledElement)Parent)?._nameScope; - } - - if (Name != null) - { - _nameScope?.Register(Name, this); - } - } - private static void ValidateLogicalChild(ILogical c) { if (c == null) @@ -724,11 +708,6 @@ namespace Avalonia { if (_isAttachedToLogicalTree) { - if (Name != null) - { - _nameScope?.Unregister(Name); - } - _isAttachedToLogicalTree = false; _styleDetach.OnNext(this); OnDetachedFromLogicalTree(e); diff --git a/src/Avalonia.Styling/Styling/Setter.cs b/src/Avalonia.Styling/Styling/Setter.cs index 3702259f35..9312d38c51 100644 --- a/src/Avalonia.Styling/Styling/Setter.cs +++ b/src/Avalonia.Styling/Styling/Setter.cs @@ -99,7 +99,6 @@ namespace Avalonia.Styling if (template != null && !isPropertyOfTypeITemplate) { var materialized = template.Build(); - NameScope.SetNameScope((StyledElement)materialized, new NameScope()); value = materialized; } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs index c25e1186d0..b4d090e278 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -35,6 +35,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions }, ProvideValueTarget = typeSystem.GetType("Avalonia.Markup.Xaml.IProvideValueTarget"), RootObjectProvider = typeSystem.GetType("Avalonia.Markup.Xaml.IRootObjectProvider"), + RootObjectProviderIntermediateRootPropertyName = "IntermediateRootObject", UriContextProvider = typeSystem.GetType("Avalonia.Markup.Xaml.IUriContext"), ParentStackProvider = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.IAvaloniaXamlIlParentStackProvider"), diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs index 33056fa3e8..05548808af 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs @@ -15,7 +15,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers && pa.Property.DeclaringType.FullName == "Avalonia.StyledElement") { if (context.ParentNodes().FirstOrDefault() is XamlIlManipulationGroupNode mg - && mg.Children.OfType().Any()) + && mg.Children.OfType().Any()) return node; IXamlIlAstValueNode value = null; @@ -41,7 +41,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Children = { pa, - new ScopeRegistrationNode(value) + new AvaloniaNameScopeRegistrationXamlIlNode(value, context.GetAvaloniaTypes()) } }; } @@ -49,46 +49,41 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers return node; } - class ScopeRegistrationNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode + + } + + class AvaloniaNameScopeRegistrationXamlIlNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode + { + private readonly AvaloniaXamlIlWellKnownTypes _types; + public IXamlIlAstValueNode Name { get; set; } + + public AvaloniaNameScopeRegistrationXamlIlNode(IXamlIlAstValueNode name, AvaloniaXamlIlWellKnownTypes types) : base(name) { - public IXamlIlAstValueNode Value { get; set; } - public ScopeRegistrationNode(IXamlIlAstValueNode value) : base(value) - { - Value = value; - } + _types = types; + Name = name; + } - public override void VisitChildren(IXamlIlAstVisitor visitor) - => Value = (IXamlIlAstValueNode)Value.Visit(visitor); + public override void VisitChildren(IXamlIlAstVisitor visitor) + => Name = (IXamlIlAstValueNode)Name.Visit(visitor); - public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) + { + using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) { - var exts = context.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScopeExtensions"); - var findNameScope = exts.FindMethod(m => m.Name == "FindNameScope"); - var registerMethod = findNameScope.ReturnType.FindMethod(m => m.Name == "Register"); - using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object)) - using (var nameScopeLoc = context.GetLocal(findNameScope.ReturnType)) - { - var exit = codeGen.DefineLabel(); - codeGen - // var target = {pop} - .Stloc(targetLoc.Local) - // var scope = target.FindNameScope() - .Ldloc(targetLoc.Local) - .Castclass(findNameScope.Parameters[0]) - .EmitCall(findNameScope) - .Stloc(nameScopeLoc.Local) - // if({scope} != null) goto call; - .Ldloc(nameScopeLoc.Local) - .Brfalse(exit) - .Ldloc(nameScopeLoc.Local); - context.Emit(Value, codeGen, Value.Type.GetClrType()); - codeGen - .Ldloc(targetLoc.Local) - .EmitCall(registerMethod) - .MarkLabel(exit); - } - return XamlIlNodeEmitResult.Void(1); + codeGen + // var target = {pop} + .Stloc(targetLoc.Local) + // NameScope.Register(context.IntermediateRoot, Name, target) + .Ldloc(context.ContextLocal) + .Ldfld(context.RuntimeContext.IntermediateRootObjectField) + .Castclass(_types.StyledElement); + context.Emit(Name, codeGen, Name.Type.GetClrType()); + codeGen + .Ldloc(targetLoc.Local) + .EmitCall(_types.NameScopeStaticRegister, true); } + + return XamlIlNodeEmitResult.Void(1); } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index c054e57380..81bbc80851 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -19,6 +19,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlIlType Transitions { get; } public IXamlIlType AssignBindingAttribute { get; } public IXamlIlType UnsetValueType { get; } + public IXamlIlType StyledElement { get; } + public IXamlIlType NameScope { get; } + public IXamlIlMethod NameScopeStaticRegister { get; } public AvaloniaXamlIlWellKnownTypes(XamlIlAstTransformationContext ctx) { @@ -37,6 +40,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers AvaloniaProperty, IBinding, ctx.Configuration.WellKnownTypes.Object); UnsetValueType = ctx.Configuration.TypeSystem.GetType("Avalonia.UnsetValueType"); + StyledElement = ctx.Configuration.TypeSystem.GetType("Avalonia.StyledElement"); + NameScope = ctx.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScope"); + NameScopeStaticRegister = NameScope.FindMethod( + new FindMethodMethodSignature("Register", XamlIlTypes.Void, + StyledElement, XamlIlTypes.String, XamlIlTypes.Object) + { + IsStatic = true, DeclaringOnly = true, IsExactMatch = true + }); + AvaloniaObjectSetValueMethod = AvaloniaObject.FindMethod("SetValue", XamlIlTypes.Void, false, AvaloniaProperty, XamlIlTypes.Object, BindingPriority); } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs index 2d8ea643ac..c6d2ecee72 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs @@ -56,6 +56,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime } public object RootObject { get; } + public object IntermediateRootObject => RootObject; } diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github index 894b2c0282..fc52295ea6 160000 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github @@ -1 +1 @@ -Subproject commit 894b2c02827fd5eb16a338de5d5b6c9fbc60fef5 +Subproject commit fc52295ea6c45f709bf63975026a4a18ce230be9 diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs index 06cc85101a..5ef3dc9753 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs @@ -10,7 +10,15 @@ namespace Avalonia.Markup.Xaml public interface IRootObjectProvider { + /// + /// The root object of the xaml file + /// object RootObject { get; } + /// + /// The "current" root object, contains either the root of the xaml file + /// or the root object of the control/data template + /// + object IntermediateRootObject { get; } } public interface IUriContext diff --git a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs index b10929cbdc..b302237285 100644 --- a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs @@ -1012,25 +1012,25 @@ namespace Avalonia.Controls.UnitTests } private IControlTemplate CreateTemplate() { - return new FuncControlTemplate(control => + return new FuncControlTemplate((control, scope) => { var textBox = new TextBox { Name = "PART_TextBox" - }; + }.RegisterInNameScope(scope); var listbox = new ListBox { Name = "PART_SelectingItemsControl" - }; + }.RegisterInNameScope(scope); var popup = new Popup { Name = "PART_Popup" - }; + }.RegisterInNameScope(scope); - var panel = new Panel(); + var panel = new Panel().WithNameScope(scope); panel.Children.Add(textBox); panel.Children.Add(popup); panel.Children.Add(listbox); diff --git a/tests/Avalonia.Controls.UnitTests/CarouselTests.cs b/tests/Avalonia.Controls.UnitTests/CarouselTests.cs index 515e18434d..f70a61f43a 100644 --- a/tests/Avalonia.Controls.UnitTests/CarouselTests.cs +++ b/tests/Avalonia.Controls.UnitTests/CarouselTests.cs @@ -302,7 +302,7 @@ namespace Avalonia.Controls.UnitTests Assert.Equal("FooBar", target.SelectedItem); } - private Control CreateTemplate(Carousel control) + private Control CreateTemplate(Carousel control, INameScope scope) { return new CarouselPresenter { @@ -312,7 +312,7 @@ namespace Avalonia.Controls.UnitTests [~CarouselPresenter.ItemsPanelProperty] = control[~Carousel.ItemsPanelProperty], [~CarouselPresenter.SelectedIndexProperty] = control[~Carousel.SelectedIndexProperty], [~CarouselPresenter.PageTransitionProperty] = control[~Carousel.PageTransitionProperty], - }; + }.RegisterInNameScope(scope).WithNameScope(scope); } } } diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs index 70ec6c1408..879f32087d 100644 --- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs @@ -80,7 +80,7 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate GetTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => { return new Panel { @@ -94,7 +94,7 @@ namespace Avalonia.Controls.UnitTests new ToggleButton { Name = "toggle", - }, + }.RegisterInNameScope(scope), new Popup { Name = "PART_Popup", @@ -102,10 +102,10 @@ namespace Avalonia.Controls.UnitTests { Name = "PART_ItemsPresenter", [!ItemsPresenter.ItemsProperty] = parent[!ComboBox.ItemsProperty], - } - } + }.RegisterInNameScope(scope) + }.RegisterInNameScope(scope) } - }; + }.WithNameScope(scope); }); } } diff --git a/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs b/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs index c17893604c..abddbe16ab 100644 --- a/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContentControlTests.cs @@ -126,7 +126,7 @@ namespace Avalonia.Controls.UnitTests var target = new ContentControl { Template = GetTemplate(), - ContentTemplate = new FuncDataTemplate(_ => new Canvas()), + ContentTemplate = new FuncDataTemplate((_, __) => new Canvas()), }; target.Content = "Foo"; @@ -302,8 +302,8 @@ namespace Avalonia.Controls.UnitTests var target = new ContentControl { - Template = new FuncControlTemplate(_ => presenter), - ContentTemplate = new FuncDataTemplate(x => new Canvas()), + Template = new FuncControlTemplate((_, __) => presenter), + ContentTemplate = new FuncDataTemplate((_, __) => new Canvas()), Content = "foo", }; @@ -333,7 +333,7 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate GetTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => { return new Border { @@ -343,8 +343,8 @@ namespace Avalonia.Controls.UnitTests Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty], [~ContentPresenter.ContentTemplateProperty] = parent[~ContentControl.ContentTemplateProperty], - } - }; + }.RegisterInNameScope(scope) + }.WithNameScope(scope); }); } } diff --git a/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs b/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs index 936d700ad0..ac30daf505 100644 --- a/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs @@ -93,30 +93,30 @@ namespace Avalonia.Controls.UnitTests private IControlTemplate CreateTemplate() { - return new FuncControlTemplate(control => + return new FuncControlTemplate((control, scope) => { var textBox = new TextBox { Name = "PART_TextBox" - }; + }.RegisterInNameScope(scope); var button = new Button { Name = "PART_Button" - }; + }.RegisterInNameScope(scope); var calendar = new Calendar { Name = "PART_Calendar" - }; + }.RegisterInNameScope(scope); var popup = new Popup { Name = "PART_Popup" - }; + }.RegisterInNameScope(scope); - var panel = new Panel(); + var panel = new Panel().WithNameScope(scope); panel.Children.Add(textBox); panel.Children.Add(button); panel.Children.Add(popup); diff --git a/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs b/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs index a1ba608ec6..a790d2fca1 100644 --- a/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs +++ b/tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs @@ -20,6 +20,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Detects_Horizontal_Orientation() { + GridSplitter splitter; var grid = new Grid() { RowDefinitions = new RowDefinitions("*,Auto,*"), @@ -27,7 +28,7 @@ namespace Avalonia.Controls.UnitTests Children = { new Border { [Grid.RowProperty] = 0 }, - new GridSplitter { [Grid.RowProperty] = 1, Name = "splitter" }, + (splitter = new GridSplitter { [Grid.RowProperty] = 1 }), new Border { [Grid.RowProperty] = 2 } } }; @@ -35,12 +36,13 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot { Child = grid }; root.Measure(new Size(100, 300)); root.Arrange(new Rect(0, 0, 100, 300)); - Assert.Contains(grid.FindControl("splitter").Classes, ":horizontal".Equals); + Assert.Contains(splitter.Classes, ":horizontal".Equals); } [Fact] public void Detects_Vertical_Orientation() { + GridSplitter splitter; var grid = new Grid() { ColumnDefinitions = new ColumnDefinitions("*,Auto,*"), @@ -48,7 +50,7 @@ namespace Avalonia.Controls.UnitTests Children = { new Border { [Grid.ColumnProperty] = 0 }, - new GridSplitter { [Grid.ColumnProperty] = 1, Name = "splitter" }, + (splitter = new GridSplitter { [Grid.ColumnProperty] = 1}), new Border { [Grid.ColumnProperty] = 2 }, } }; @@ -56,12 +58,13 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot { Child = grid }; root.Measure(new Size(100, 300)); root.Arrange(new Rect(0, 0, 100, 300)); - Assert.Contains(grid.FindControl("splitter").Classes, ":vertical".Equals); + Assert.Contains(splitter.Classes, ":vertical".Equals); } [Fact] public void Detects_With_Both_Auto() { + GridSplitter splitter; var grid = new Grid() { ColumnDefinitions = new ColumnDefinitions("Auto,Auto,Auto"), @@ -69,7 +72,7 @@ namespace Avalonia.Controls.UnitTests Children = { new Border { [Grid.ColumnProperty] = 0 }, - new GridSplitter { [Grid.ColumnProperty] = 1, Name = "splitter" }, + (splitter = new GridSplitter { [Grid.ColumnProperty] = 1}), new Border { [Grid.ColumnProperty] = 2 }, } }; @@ -77,7 +80,7 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot { Child = grid }; root.Measure(new Size(100, 300)); root.Arrange(new Rect(0, 0, 100, 300)); - Assert.Contains(grid.FindControl("splitter").Classes, ":vertical".Equals); + Assert.Contains(splitter.Classes, ":vertical".Equals); } [Fact] @@ -129,13 +132,14 @@ namespace Avalonia.Controls.UnitTests [Fact] public void In_First_Position_Doesnt_Throw_Exception() { + GridSplitter splitter; var grid = new Grid() { ColumnDefinitions = new ColumnDefinitions("Auto,*,*"), RowDefinitions = new RowDefinitions("*,*"), Children = { - new GridSplitter { [Grid.ColumnProperty] = 0, Name = "splitter" }, + (splitter = new GridSplitter { [Grid.ColumnProperty] = 0} ), new Border { [Grid.ColumnProperty] = 1 }, new Border { [Grid.ColumnProperty] = 2 }, } @@ -144,7 +148,6 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot { Child = grid }; root.Measure(new Size(100, 300)); root.Arrange(new Rect(0, 0, 100, 300)); - var splitter = grid.FindControl("splitter"); splitter.RaiseEvent(new VectorEventArgs { RoutedEvent = Thumb.DragDeltaEvent, @@ -199,4 +202,4 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(columnDefinitions[2].Width, new GridLength(80, GridUnitType.Star)); } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Controls.UnitTests/HeaderedItemsControlTests .cs b/tests/Avalonia.Controls.UnitTests/HeaderedItemsControlTests .cs index 66789ef874..832a19c02d 100644 --- a/tests/Avalonia.Controls.UnitTests/HeaderedItemsControlTests .cs +++ b/tests/Avalonia.Controls.UnitTests/HeaderedItemsControlTests .cs @@ -63,7 +63,7 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate GetTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => { return new Border { @@ -71,8 +71,8 @@ namespace Avalonia.Controls.UnitTests { Name = "PART_HeaderPresenter", [~ContentPresenter.ContentProperty] = parent[~HeaderedItemsControl.HeaderProperty], - } - }; + }.RegisterInNameScope(scope) + }.WithNameScope(scope); }); } } diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs index 3cf886ade4..6680766ffa 100644 --- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs @@ -23,7 +23,7 @@ namespace Avalonia.Controls.UnitTests var target = new ItemsControl { Template = GetTemplate(), - ItemTemplate = new FuncDataTemplate(_ => new Canvas()), + ItemTemplate = new FuncDataTemplate((_, __) => new Canvas()), }; target.Items = new[] { "Foo" }; @@ -411,7 +411,7 @@ namespace Avalonia.Controls.UnitTests DataContext = "Base", DataTemplates = { - new FuncDataTemplate(x => new Button { Content = x }) + new FuncDataTemplate((x, __) => new Button { Content = x }) }, Items = items, }; @@ -578,7 +578,7 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate GetTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => { return new Border { @@ -588,8 +588,8 @@ namespace Avalonia.Controls.UnitTests Name = "PART_ItemsPresenter", MemberSelector = parent.MemberSelector, [~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty], - } - }; + }.RegisterInNameScope(scope) + }.WithNameScope(scope); }); } diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index 238e214a5d..ef61d34ee1 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs @@ -25,7 +25,7 @@ namespace Avalonia.Controls.UnitTests { Template = ListBoxTemplate(), Items = new[] { "Foo" }, - ItemTemplate = new FuncDataTemplate(_ => new Canvas()), + ItemTemplate = new FuncDataTemplate((_, __) => new Canvas()), }; Prepare(target); @@ -113,7 +113,7 @@ namespace Avalonia.Controls.UnitTests DataContext = "Base", DataTemplates = { - new FuncDataTemplate(x => new Button { Content = x }) + new FuncDataTemplate((x, _) => new Button { Content = x }) }, Items = items, }; @@ -138,7 +138,7 @@ namespace Avalonia.Controls.UnitTests { Template = ListBoxTemplate(), Items = Enumerable.Range(0, 20).Select(x => $"Item {x}").ToList(), - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Height = 10 }), SelectedIndex = 0, }; @@ -162,7 +162,7 @@ namespace Avalonia.Controls.UnitTests { Template = ListBoxTemplate(), Items = Enumerable.Range(0, 20).Select(x => $"Item {x}").ToList(), - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Width = 20, Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), SelectedIndex = 0, }; @@ -181,7 +181,7 @@ namespace Avalonia.Controls.UnitTests { Template = ListBoxTemplate(), Items = items, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Width = 20, Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), SelectedIndex = 0, }; @@ -205,7 +205,7 @@ namespace Avalonia.Controls.UnitTests Template = ListBoxTemplate(), Items = items, SelectionMode = SelectionMode.Toggle, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Height = 10 }) + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Height = 10 }) }; Prepare(target); @@ -239,7 +239,7 @@ namespace Avalonia.Controls.UnitTests { Template = ListBoxTemplate(), Items = items, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Height = 11 }) + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Height = 11 }) }; Prepare(target); @@ -287,7 +287,7 @@ namespace Avalonia.Controls.UnitTests target.DataContext = items; target.VirtualizationMode = virtualizationMode; - target.ItemTemplate = new FuncDataTemplate(c => + target.ItemTemplate = new FuncDataTemplate((c, _) => { var tb = new TextBlock() { Height = 10, Width = 30 }; tb.Bind(TextBlock.TextProperty, new Data.Binding()); @@ -334,7 +334,7 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate ListBoxTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => new ScrollViewer { Name = "PART_ScrollViewer", @@ -345,24 +345,24 @@ namespace Avalonia.Controls.UnitTests [~ItemsPresenter.ItemsProperty] = parent.GetObservable(ItemsControl.ItemsProperty).ToBinding(), [~ItemsPresenter.ItemsPanelProperty] = parent.GetObservable(ItemsControl.ItemsPanelProperty).ToBinding(), [~ItemsPresenter.VirtualizationModeProperty] = parent.GetObservable(ListBox.VirtualizationModeProperty).ToBinding(), - } - }); + }.RegisterInNameScope(scope) + }.RegisterInNameScope(scope).WithNameScope(scope)); } private FuncControlTemplate ListBoxItemTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => new ContentPresenter { Name = "PART_ContentPresenter", [!ContentPresenter.ContentProperty] = parent[!ListBoxItem.ContentProperty], [!ContentPresenter.ContentTemplateProperty] = parent[!ListBoxItem.ContentTemplateProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private FuncControlTemplate ScrollViewerTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => new ScrollContentPresenter { Name = "PART_ContentPresenter", @@ -370,7 +370,7 @@ namespace Avalonia.Controls.UnitTests [~~ScrollContentPresenter.ExtentProperty] = parent[~~ScrollViewer.ExtentProperty], [~~ScrollContentPresenter.OffsetProperty] = parent[~~ScrollViewer.OffsetProperty], [~~ScrollContentPresenter.ViewportProperty] = parent[~~ScrollViewer.ViewportProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private void Prepare(ListBox target) diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs index de34558ad1..ece9e27fb3 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs @@ -245,7 +245,7 @@ namespace Avalonia.Controls.UnitTests } } - private Control CreateListBoxTemplate(ITemplatedControl parent) + private Control CreateListBoxTemplate(ITemplatedControl parent, INameScope scope) { return new ScrollViewer { @@ -254,17 +254,18 @@ namespace Avalonia.Controls.UnitTests { Name = "PART_ItemsPresenter", [~ItemsPresenter.ItemsProperty] = parent.GetObservable(ItemsControl.ItemsProperty).ToBinding(), - } - }; + }.RegisterInNameScope(scope) + }.WithNameScope(scope); } - private Control CreateScrollViewerTemplate(ITemplatedControl parent) + private Control CreateScrollViewerTemplate(ITemplatedControl parent, INameScope scope) { return new ScrollContentPresenter { Name = "PART_ContentPresenter", - [~ContentPresenter.ContentProperty] = parent.GetObservable(ContentControl.ContentProperty).ToBinding(), - }; + [~ContentPresenter.ContentProperty] = + parent.GetObservable(ContentControl.ContentProperty).ToBinding(), + }.RegisterInNameScope(scope).WithNameScope(scope); } private void ApplyTemplate(ListBox target) diff --git a/tests/Avalonia.Controls.UnitTests/Mixins/ContentControlMixinTests.cs b/tests/Avalonia.Controls.UnitTests/Mixins/ContentControlMixinTests.cs index f06553411c..06679b2399 100644 --- a/tests/Avalonia.Controls.UnitTests/Mixins/ContentControlMixinTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Mixins/ContentControlMixinTests.cs @@ -21,15 +21,16 @@ namespace Avalonia.Controls.UnitTests.Mixins { var target = new TestControl() { - Template = new FuncControlTemplate(_ => new Panel + Template = new FuncControlTemplate((_, scope) => new Panel { Children = { - new ContentPresenter { Name = "Content_1_Presenter" }, - new ContentPresenter { Name = "Content_2_Presenter" } + new ContentPresenter {Name = "Content_1_Presenter"}.RegisterInNameScope(scope), + new ContentPresenter {Name = "Content_2_Presenter"}.RegisterInNameScope(scope) } - }) + }.WithNameScope(scope)) }; + var ex = Record.Exception(() => target.ApplyTemplate()); @@ -43,14 +44,14 @@ namespace Avalonia.Controls.UnitTests.Mixins var p2 = new ContentPresenter { Name = "Content_2_Presenter" }; var target = new TestControl { - Template = new FuncControlTemplate(_ => new Panel + Template = new FuncControlTemplate((_, scope) => new Panel { Children = { - p1, - p2 + p1.RegisterInNameScope(scope), + p2.RegisterInNameScope(scope) } - }) + }.WithNameScope(scope)) }; target.ApplyTemplate(); diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs index 708e934214..b8b329099a 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs @@ -170,7 +170,7 @@ namespace Avalonia.Controls.UnitTests.Presenters { var (target, _) = CreateTarget(); - target.ContentTemplate = new FuncDataTemplate(_ => new Canvas()); + target.ContentTemplate = new FuncDataTemplate((_, __) => new Canvas()); target.Content = "Foo"; Assert.IsType(target.Child); @@ -184,7 +184,7 @@ namespace Avalonia.Controls.UnitTests.Presenters target.Content = "Foo"; Assert.IsType(target.Child); - target.ContentTemplate = new FuncDataTemplate(_ => new Canvas()); + target.ContentTemplate = new FuncDataTemplate((_, __) => new Canvas()); Assert.IsType(target.Child); target.ContentTemplate = null; @@ -209,7 +209,7 @@ namespace Avalonia.Controls.UnitTests.Presenters public void Recycles_DataTemplate() { var (target, _) = CreateTarget(); - target.DataTemplates.Add(new FuncDataTemplate(_ => new Border(), true)); + target.DataTemplates.Add(new FuncDataTemplate((_, __) => new Border(), true)); target.Content = "foo"; @@ -239,7 +239,7 @@ namespace Avalonia.Controls.UnitTests.Presenters public void Detects_DataTemplate_Doesnt_Support_Recycling() { var (target, _) = CreateTarget(); - target.DataTemplates.Add(new FuncDataTemplate(_ => new Border(), false)); + target.DataTemplates.Add(new FuncDataTemplate((_, __) => new Border(), false)); target.Content = "foo"; @@ -256,7 +256,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var (target, _) = CreateTarget(); target.DataTemplates.Add(new FuncDataTemplate(x => x == "bar", _ => new Canvas(), true)); - target.DataTemplates.Add(new FuncDataTemplate(_ => new Border(), true)); + target.DataTemplates.Add(new FuncDataTemplate((_, __) => new Border(), true)); target.Content = "foo"; @@ -278,8 +278,8 @@ namespace Avalonia.Controls.UnitTests.Presenters }; var (target, host) = CreateTarget(); - host.DataTemplates.Add(new FuncDataTemplate(x => textBlock)); - host.DataTemplates.Add(new FuncDataTemplate(x => new Canvas())); + host.DataTemplates.Add(new FuncDataTemplate((_, __) => textBlock)); + host.DataTemplates.Add(new FuncDataTemplate((_, __) => new Canvas())); target.Content = "foo"; Assert.Same(textBlock, target.Child); @@ -296,11 +296,11 @@ namespace Avalonia.Controls.UnitTests.Presenters { var templatedParent = new ContentControl { - Template = new FuncControlTemplate(x => + Template = new FuncControlTemplate((_, s) => new ContentPresenter { Name = "PART_ContentPresenter", - }), + }.RegisterInNameScope(s).WithNameScope(s)), }; var root = new TestRoot { Child = templatedParent }; diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs index 2facee16b7..5dd4deabf6 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs @@ -54,7 +54,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var target = new ContentPresenter { ContentTemplate = - new FuncDataTemplate(t => new ContentControl() { Content = t }, false) + new FuncDataTemplate((t, _) => new ContentControl() { Content = t }, false) }; var parentMock = new Mock(); @@ -93,14 +93,14 @@ namespace Avalonia.Controls.UnitTests.Presenters { var contentControl = new ContentControl { - Template = new FuncControlTemplate(c => new ContentPresenter() + Template = new FuncControlTemplate((c, scope) => new ContentPresenter() { Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = c[~ContentControl.ContentProperty], [~ContentPresenter.ContentTemplateProperty] = c[~ContentControl.ContentTemplateProperty] - }), + }.RegisterInNameScope(scope).WithNameScope(scope)), ContentTemplate = - new FuncDataTemplate(t => new ContentControl() { Content = t }, false) + new FuncDataTemplate((t, _) => new ContentControl() { Content = t }, false) }; var parentMock = new Mock(); @@ -144,7 +144,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var target = new ContentPresenter { ContentTemplate = - new FuncDataTemplate(t => new ContentControl() { Content = t }, false) + new FuncDataTemplate((t, _) => new ContentControl() { Content = t }, false) }; var parentMock = new Mock(); @@ -179,7 +179,7 @@ namespace Avalonia.Controls.UnitTests.Presenters var target = new ContentPresenter { ContentTemplate = - new FuncDataTemplate(t => new ContentControl() { Content = t }, false) + new FuncDataTemplate((t, _) => new ContentControl() { Content = t }, false) }; target.Content = "foo"; @@ -235,8 +235,8 @@ namespace Avalonia.Controls.UnitTests.Presenters { DataTemplates = { - new FuncDataTemplate(x => textBlock), - new FuncDataTemplate(x => new Canvas()), + new FuncDataTemplate((x, _) => textBlock), + new FuncDataTemplate((x, _) => new Canvas()), }, }; diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs index 5268c9ac0d..09970926fa 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs @@ -90,7 +90,7 @@ namespace Avalonia.Controls.UnitTests.Presenters { DataTemplates = { - new FuncDataTemplate(x => new Decorator()), + new FuncDataTemplate((x, _) => new Decorator()), }, }; @@ -99,4 +99,4 @@ namespace Avalonia.Controls.UnitTests.Presenters Assert.IsType(target.Child); } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs index 3d13e4c32f..7ca11d9bed 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs @@ -220,7 +220,7 @@ namespace Avalonia.Controls.UnitTests.Presenters { VirtualizationMode = ItemVirtualizationMode.None, Items = items, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Height = 10 }), }; target.ApplyTemplate(); diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs index 3ea32ed719..269da884ba 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs @@ -309,7 +309,7 @@ namespace Avalonia.Controls.UnitTests.Presenters private static IDataTemplate ItemTemplate() { - return new FuncDataTemplate(x => new Canvas + return new FuncDataTemplate((x, _) => new Canvas { Width = 10, Height = 10, diff --git a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs index 97d57e9eb6..dcbe8b4e0a 100644 --- a/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs +++ b/tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs @@ -470,7 +470,7 @@ namespace Avalonia.Controls.UnitTests.Presenters { VirtualizationMode = ItemVirtualizationMode.None, Items = items, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Height = 10 }), }; target.ApplyTemplate(); @@ -1046,7 +1046,7 @@ namespace Avalonia.Controls.UnitTests.Presenters private static IDataTemplate StringDataTemplate() { - return new FuncDataTemplate(x => new Canvas + return new FuncDataTemplate((x, _) => new Canvas { Width = 10, Height = 10, @@ -1095,12 +1095,12 @@ namespace Avalonia.Controls.UnitTests.Presenters { public TestContainer() { - Template = new FuncControlTemplate(parent => new ContentPresenter + Template = new FuncControlTemplate((parent, scope) => new ContentPresenter { Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty], [~ContentPresenter.ContentTemplateProperty] = parent[~ContentControl.ContentTemplateProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } } } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs index d4b5d01a6b..25dcea32ab 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs @@ -134,12 +134,12 @@ namespace Avalonia.Controls.UnitTests.Primitives { var result = new PopupRoot { - Template = new FuncControlTemplate(parent => + Template = new FuncControlTemplate((parent, scope) => new ContentPresenter { Name = "PART_ContentPresenter", [!ContentPresenter.ContentProperty] = parent[!PopupRoot.ContentProperty], - }), + }.RegisterInNameScope(scope).WithNameScope(scope)), }; result.ApplyTemplate(); @@ -154,7 +154,7 @@ namespace Avalonia.Controls.UnitTests.Primitives public TemplatedControlWithPopup() { - Template = new FuncControlTemplate(parent => + Template = new FuncControlTemplate((parent, _) => new Popup { [!Popup.ChildProperty] = parent[!TemplatedControlWithPopup.PopupContentProperty], diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index bd11cf2e3c..4db542c4e1 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -315,16 +315,16 @@ namespace Avalonia.Controls.UnitTests.Primitives return result; } - private static IControl PopupRootTemplate(PopupRoot control) + private static IControl PopupRootTemplate(PopupRoot control, INameScope scope) { return new ContentPresenter { Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = control[~ContentControl.ContentProperty], - }; + }.RegisterInNameScope(scope).WithNameScope(scope); } - private static IControl PopupContentControlTemplate(PopupContentControl control) + private static IControl PopupContentControlTemplate(PopupContentControl control, INameScope scope) { return new Popup { @@ -333,7 +333,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { [~ContentPresenter.ContentProperty] = control[~ContentControl.ContentProperty], } - }; + }.RegisterInNameScope(scope).WithNameScope(scope); } private class PopupContentControl : ContentControl diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs index d913e3e54f..5fe7e270d9 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs @@ -111,7 +111,7 @@ namespace Avalonia.Controls.UnitTests.Primitives var target = new TestRange() { - Template = new FuncControlTemplate(c => + Template = new FuncControlTemplate((c, scope) => { track = new Track() { @@ -122,7 +122,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Name = "PART_Track", Thumb = new Thumb() - }; + }.RegisterInNameScope(scope); if (useXamlBinding) { @@ -138,7 +138,7 @@ namespace Avalonia.Controls.UnitTests.Primitives track[~~Track.ValueProperty] = c[~~RangeBase.ValueProperty]; } - return track; + return track.WithNameScope(scope); }), Minimum = 0, Maximum = 100, diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs index 672b5c608b..cdb6aebb25 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs @@ -169,7 +169,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.False(target.IsVisible); } - private static Control Template(ScrollBar control) + private static Control Template(ScrollBar control, INameScope scope) { return new Border { @@ -185,11 +185,11 @@ namespace Avalonia.Controls.UnitTests.Primitives { Template = new FuncControlTemplate(ThumbTemplate), }, - }, - }; + }.RegisterInNameScope(scope), + }.WithNameScope(scope); } - private static Control ThumbTemplate(Thumb control) + private static Control ThumbTemplate(Thumb control, INameScope scope) { return new Border { @@ -197,4 +197,4 @@ namespace Avalonia.Controls.UnitTests.Primitives }; } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index 75cababf54..1036730575 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -896,13 +896,13 @@ namespace Avalonia.Controls.UnitTests.Primitives private FuncControlTemplate Template() { - return new FuncControlTemplate(control => + return new FuncControlTemplate((control, scope) => new ItemsPresenter { Name = "itemsPresenter", [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty], [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private class Item : Control, ISelectable diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs index 88cb726469..e2d306dd67 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs @@ -84,13 +84,13 @@ namespace Avalonia.Controls.UnitTests.Primitives private FuncControlTemplate Template() { - return new FuncControlTemplate(control => + return new FuncControlTemplate((control, scope) => new ItemsPresenter { Name = "itemsPresenter", [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty], [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private class TestSelector : SelectingItemsControl diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs index a33d97779e..68884a6a4c 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs @@ -964,7 +964,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { Template = Template(), Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Width = 20, Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), SelectionMode = SelectionMode.Multiple, }; @@ -988,7 +988,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { Template = Template(), Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Width = 20, Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), SelectionMode = SelectionMode.Multiple, }; @@ -1010,7 +1010,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { Template = Template(), Items = new[] { "Foo", "Bar", "Baz" }, - ItemTemplate = new FuncDataTemplate(x => new TextBlock { Width = 20, Height = 10 }), + ItemTemplate = new FuncDataTemplate((x, _) => new TextBlock { Width = 20, Height = 10 }), SelectionMode = SelectionMode.Multiple, }; @@ -1035,13 +1035,13 @@ namespace Avalonia.Controls.UnitTests.Primitives private FuncControlTemplate Template() { - return new FuncControlTemplate(control => + return new FuncControlTemplate((control, scope) => new ItemsPresenter { Name = "PART_ItemsPresenter", [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty], [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private class TestSelector : SelectingItemsControl diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs index 55b3d6f756..d7e78fdd0d 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs @@ -159,14 +159,14 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.Same("3rd", ((TabItem)target.SelectedItem).Name); } - private Control CreateTabStripTemplate(TabStrip parent) + private Control CreateTabStripTemplate(TabStrip parent, INameScope scope) { return new ItemsPresenter { Name = "itemsPresenter", [!ItemsPresenter.ItemsProperty] = parent[!ItemsControl.ItemsProperty], [!ItemsPresenter.MemberSelectorProperty] = parent[!ItemsControl.MemberSelectorProperty], - }; + }.RegisterInNameScope(scope).WithNameScope(scope); } } } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs index 166586ace1..db0f2b6fb3 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs @@ -23,7 +23,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { bool executed = false; - var template = new FuncControlTemplate(_ => + var template = new FuncControlTemplate((_, __) => { executed = true; return new Control(); @@ -42,7 +42,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { bool executed = false; - var template = new FuncControlTemplate(_ => + var template = new FuncControlTemplate((_, __) => { executed = true; return new Control(); @@ -63,7 +63,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator + Template = new FuncControlTemplate((_, __) => new Decorator { Child = new Panel { @@ -97,7 +97,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator + Template = new FuncControlTemplate((_, __) => new Decorator { Child = new Panel { @@ -120,7 +120,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator + Template = new FuncControlTemplate((_, __) => new Decorator { Child = new Panel { @@ -149,7 +149,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator()) + Template = new FuncControlTemplate((_, __) => new Decorator()) }; target.ApplyTemplate(); @@ -165,14 +165,14 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator()) + Template = new FuncControlTemplate((_, __) => new Decorator()) }; target.ApplyTemplate(); var child = (Decorator)target.GetVisualChildren().Single(); - target.Template = new FuncControlTemplate(_ => new Canvas()); + target.Template = new FuncControlTemplate((_, __) => new Canvas()); target.ApplyTemplate(); Assert.Null(child.Parent); @@ -183,7 +183,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TemplatedControl { - Template = new FuncControlTemplate(_ => new ScrollViewer()) + Template = new FuncControlTemplate((_, __) => new ScrollViewer()) }; target.ApplyTemplate(); @@ -203,7 +203,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { Child = target = new TestTemplatedControl { - Template = new FuncControlTemplate(_ => + Template = new FuncControlTemplate((_, __) => { return new StackPanel { @@ -232,11 +232,11 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TestTemplatedControl { - Template = new FuncControlTemplate(_ => + Template = new FuncControlTemplate((_, __) => { return new ContentControl { - Template = new FuncControlTemplate(parent => + Template = new FuncControlTemplate((parent, ___) => { return new Border { @@ -311,7 +311,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TestTemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator()) + Template = new FuncControlTemplate((_, __) => new Decorator()) }; var raised = false; @@ -334,7 +334,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { var target = new TestTemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator + Template = new FuncControlTemplate((_, __) => new Decorator { Child = new Border(), }) @@ -348,7 +348,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.Equal(target, decorator.TemplatedParent); Assert.Equal(target, border.TemplatedParent); - target.Template = new FuncControlTemplate(_ => new Canvas()); + target.Template = new FuncControlTemplate((_, __) => new Canvas()); // Templated children should not be removed here: the control may be re-added // somewhere with the same template, so they could still be of use. @@ -370,7 +370,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { Child = new TestTemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator + Template = new FuncControlTemplate((_, __) => new Decorator { Child = templateChild, }) @@ -392,7 +392,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { Child = new TestTemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator + Template = new FuncControlTemplate((_, __) => new Decorator { Child = templateChild, }) @@ -425,7 +425,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { new Setter( TemplatedControl.TemplateProperty, - new FuncControlTemplate(_ => new Decorator + new FuncControlTemplate((_, __) => new Decorator { Child = new Border(), })) @@ -461,7 +461,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { new Setter( TemplatedControl.TemplateProperty, - new FuncControlTemplate(_ => new Decorator + new FuncControlTemplate((_, __) => new Decorator { Child = new Border(), })) @@ -500,7 +500,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { new Setter( TemplatedControl.TemplateProperty, - new FuncControlTemplate(_ => new Decorator + new FuncControlTemplate((_, __) => new Decorator { Child = new Border(), })) @@ -520,7 +520,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { new Setter( TemplatedControl.TemplateProperty, - new FuncControlTemplate(_ => new Decorator + new FuncControlTemplate((_, __) => new Decorator { Child = new Border(), })) @@ -555,7 +555,7 @@ namespace Avalonia.Controls.UnitTests.Primitives { Child = target = new TestTemplatedControl { - Template = new FuncControlTemplate(_ => new Decorator()), + Template = new FuncControlTemplate((_, __) => new Decorator()), } }; @@ -573,7 +573,7 @@ namespace Avalonia.Controls.UnitTests.Primitives } } - private static IControl ScrollingContentControlTemplate(ContentControl control) + private static IControl ScrollingContentControlTemplate(ContentControl control, INameScope scope) { return new Border { @@ -585,20 +585,20 @@ namespace Avalonia.Controls.UnitTests.Primitives { Name = "PART_ContentPresenter", [!ContentPresenter.ContentProperty] = control[!ContentControl.ContentProperty], - } - } - }; + }.RegisterInNameScope(scope) + }.RegisterInNameScope(scope) + }.WithNameScope(scope); } - private static Control ScrollViewerTemplate(ScrollViewer control) + private static Control ScrollViewerTemplate(ScrollViewer control, INameScope scope) { var result = new ScrollContentPresenter { Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = control[~ContentControl.ContentProperty], - }; + }.RegisterInNameScope(scope).WithNameScope(scope); return result; } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Controls.UnitTests/ScrollViewerTests.cs b/tests/Avalonia.Controls.UnitTests/ScrollViewerTests.cs index d1385176c5..9076d8019c 100644 --- a/tests/Avalonia.Controls.UnitTests/ScrollViewerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ScrollViewerTests.cs @@ -64,7 +64,7 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(new Vector(10, 10), target.Offset); } - private Control CreateTemplate(ScrollViewer control) + private Control CreateTemplate(ScrollViewer control, INameScope scope) { return new Grid { @@ -88,7 +88,7 @@ namespace Avalonia.Controls.UnitTests [~~ScrollContentPresenter.OffsetProperty] = control[~~ScrollViewer.OffsetProperty], [~~ScrollContentPresenter.ViewportProperty] = control[~~ScrollViewer.ViewportProperty], [~ScrollContentPresenter.CanHorizontallyScrollProperty] = control[~ScrollViewer.CanHorizontallyScrollProperty], - }, + }.RegisterInNameScope(scope), new ScrollBar { Name = "horizontalScrollBar", @@ -98,7 +98,7 @@ namespace Avalonia.Controls.UnitTests [~ScrollBar.ViewportSizeProperty] = control[~ScrollViewer.HorizontalScrollBarViewportSizeProperty], [~ScrollBar.VisibilityProperty] = control[~ScrollViewer.HorizontalScrollBarVisibilityProperty], [Grid.RowProperty] = 1, - }, + }.RegisterInNameScope(scope), new ScrollBar { Name = "verticalScrollBar", @@ -108,9 +108,9 @@ namespace Avalonia.Controls.UnitTests [~ScrollBar.ViewportSizeProperty] = control[~ScrollViewer.VerticalScrollBarViewportSizeProperty], [~ScrollBar.VisibilityProperty] = control[~ScrollViewer.VerticalScrollBarVisibilityProperty], [Grid.ColumnProperty] = 1, - }, + }.RegisterInNameScope(scope), }, - }; + }.WithNameScope(scope); } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs index e00084eba4..35e1ed9e1c 100644 --- a/tests/Avalonia.Controls.UnitTests/TabControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TabControlTests.cs @@ -129,7 +129,7 @@ namespace Avalonia.Controls.UnitTests }, }; - var template = new FuncControlTemplate(x => new Decorator()); + var template = new FuncControlTemplate((x, __) => new Decorator()); using (UnitTestApplication.Start(TestServices.RealStyler)) { @@ -176,7 +176,7 @@ namespace Avalonia.Controls.UnitTests DataContext = "Base", DataTemplates = { - new FuncDataTemplate(x => new Button { Content = x }) + new FuncDataTemplate((x, __) => new Button { Content = x }) }, Items = items, }; @@ -273,7 +273,7 @@ namespace Avalonia.Controls.UnitTests TabControl target = new TabControl { Template = TabControlTemplate(), - ContentTemplate = new FuncDataTemplate(x => + ContentTemplate = new FuncDataTemplate((x, _) => new TextBlock { Tag = "bar", Text = x }), Items = new[] { "Foo" }, }; @@ -289,7 +289,7 @@ namespace Avalonia.Controls.UnitTests private IControlTemplate TabControlTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => new StackPanel { Children = @@ -299,26 +299,26 @@ namespace Avalonia.Controls.UnitTests Name = "PART_ItemsPresenter", [!TabStrip.ItemsProperty] = parent[!TabControl.ItemsProperty], [!TabStrip.ItemTemplateProperty] = parent[!TabControl.ItemTemplateProperty], - }, + }.RegisterInNameScope(scope), new ContentPresenter { Name = "PART_SelectedContentHost", [!ContentPresenter.ContentProperty] = parent[!TabControl.SelectedContentProperty], [!ContentPresenter.ContentTemplateProperty] = parent[!TabControl.SelectedContentTemplateProperty], - } + }.RegisterInNameScope(scope) } - }); + }.WithNameScope(scope)); } private IControlTemplate TabItemTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => new ContentPresenter { Name = "PART_ContentPresenter", [!ContentPresenter.ContentProperty] = parent[!TabItem.HeaderProperty], [!ContentPresenter.ContentTemplateProperty] = parent[!TabItem.HeaderTemplateProperty] - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private void ApplyTemplate(TabControl target) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 932aada64e..7b08b4811f 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -456,7 +456,7 @@ namespace Avalonia.Controls.UnitTests private IControlTemplate CreateTemplate() { - return new FuncControlTemplate(control => + return new FuncControlTemplate((control, scope) => new TextPresenter { Name = "PART_TextPresenter", @@ -467,7 +467,7 @@ namespace Avalonia.Controls.UnitTests Priority = BindingPriority.TemplatedParent, RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), }, - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private void RaiseKeyEvent(TextBox textBox, Key key, InputModifiers inputModifiers) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs index 4d79dd557e..d9e60ffbcf 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs @@ -93,7 +93,7 @@ namespace Avalonia.Controls.UnitTests private IControlTemplate CreateTemplate() { - return new FuncControlTemplate(control => + return new FuncControlTemplate((control, scope) => new TextPresenter { Name = "PART_TextPresenter", @@ -104,7 +104,7 @@ namespace Avalonia.Controls.UnitTests Priority = BindingPriority.TemplatedParent, RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), }, - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private class ExceptionTest diff --git a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs index f112289460..99d55c4c5c 100644 --- a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs @@ -226,12 +226,12 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate CreateTemplate() { - return new FuncControlTemplate(x => + return new FuncControlTemplate((x, scope) => new ContentPresenter { Name = "PART_ContentPresenter", [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private class TestTopLevel : TopLevel diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs index b66d6ed11c..21a7f4e6db 100644 --- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs @@ -50,7 +50,7 @@ namespace Avalonia.Controls.UnitTests Template = CreateTreeViewTemplate(), Items = CreateTestTreeData(), ItemTemplate = new FuncTreeDataTemplate( - _ => new Canvas(), + (_, __) => new Canvas(), x => x.Children), } }; @@ -475,7 +475,7 @@ namespace Avalonia.Controls.UnitTests DataContext = "Base", DataTemplates = { - new FuncDataTemplate(x => new Button { Content = x }) + new FuncDataTemplate((x, _) => new Button { Content = x }) }, Items = items, }; @@ -513,7 +513,7 @@ namespace Avalonia.Controls.UnitTests Assert.Null(NameScope.GetNameScope((TreeViewItem)item)); } - [Fact] + [Fact(Skip = "Is this behavior needed anymore?")] public void DataTemplate_Created_Item_Should_Be_NameScope() { var items = new object[] @@ -799,16 +799,16 @@ namespace Avalonia.Controls.UnitTests private IControlTemplate CreateTreeViewTemplate() { - return new FuncControlTemplate(parent => new ItemsPresenter + return new FuncControlTemplate((parent, scope) => new ItemsPresenter { Name = "PART_ItemsPresenter", [~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private IControlTemplate CreateTreeViewItemTemplate() { - return new FuncControlTemplate(parent => new Panel + return new FuncControlTemplate((parent, scope) => new Panel { Children = { @@ -816,14 +816,14 @@ namespace Avalonia.Controls.UnitTests { Name = "PART_HeaderPresenter", [~ContentPresenter.ContentProperty] = parent[~TreeViewItem.HeaderProperty], - }, + }.RegisterInNameScope(scope), new ItemsPresenter { Name = "PART_ItemsPresenter", [~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty], - } + }.RegisterInNameScope(scope) } - }); + }.WithNameScope(scope)); } private List ExtractItemHeader(TreeView tree, int level) diff --git a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs index 6da771217c..7bcf8fe4f2 100644 --- a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs @@ -40,7 +40,7 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate GetTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => { return new Border { @@ -49,8 +49,8 @@ namespace Avalonia.Controls.UnitTests { Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty], - } - }; + }.RegisterInNameScope(scope) + }.WithNameScope(scope); }); } } diff --git a/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs b/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs index 641979638a..427c91d989 100644 --- a/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs @@ -59,13 +59,13 @@ namespace Avalonia.Controls.UnitTests.Utils private FuncControlTemplate CreateWindowTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate((parent, scope) => { return new ContentPresenter { Name = "PART_ContentPresenter", [~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty], - }; + }.RegisterInNameScope(scope).WithNameScope(scope); }); } } diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs index 12d29f2e5b..f4b3149e31 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs @@ -253,12 +253,12 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate CreateTemplate() { - return new FuncControlTemplate(x => + return new FuncControlTemplate((x, scope) => new ContentPresenter { Name = "PART_ContentPresenter", [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty], - }); + }.RegisterInNameScope(scope).WithNameScope(scope)); } private class TestWindowBase : WindowBase diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_ElementName.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_ElementName.cs index 61df0bffdf..e2a5824102 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_ElementName.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_ElementName.cs @@ -34,6 +34,8 @@ namespace Avalonia.Markup.UnitTests.Data } }; + root.RegisterChildrenNames(); + var binding = new Binding { ElementName = "source", @@ -69,6 +71,7 @@ namespace Avalonia.Markup.UnitTests.Data } } }; + root.RegisterChildrenNames(); var binding = new Binding { @@ -99,7 +102,8 @@ namespace Avalonia.Markup.UnitTests.Data } } }; - + root.RegisterChildrenNames(); + var binding = new Binding { ElementName = "source", @@ -113,7 +117,7 @@ namespace Avalonia.Markup.UnitTests.Data Name = "source", Text = "foo", }); - + root.RegisterChildrenNames(); Assert.Equal("foo", target.Text); } @@ -136,6 +140,7 @@ namespace Avalonia.Markup.UnitTests.Data } } }; + root.RegisterChildrenNames(); var binding = new Binding { @@ -151,6 +156,7 @@ namespace Avalonia.Markup.UnitTests.Data }; stackPanel.Children.Add(source); + root.RegisterChildrenNames(); Assert.Same(source, target.Content); } diff --git a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs index d3e3ce5507..ee95463f1f 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs @@ -23,9 +23,10 @@ namespace Avalonia.Markup.UnitTests.Data DataContext = new Class1(), }; + var format = "{0:0.0} + {1:00}"; var target = new MultiBinding { - StringFormat = "{0:0.0} + {1:00}", + StringFormat = format, Bindings = { new Binding(nameof(Class1.Foo)), @@ -35,7 +36,7 @@ namespace Avalonia.Markup.UnitTests.Data textBlock.Bind(TextBlock.TextProperty, target); - Assert.Equal("1.0 + 02", textBlock.Text); + Assert.Equal(string.Format(format, 1, 2), textBlock.Text); } [Fact] diff --git a/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs index ef3864abd7..51cb75a867 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs @@ -18,7 +18,7 @@ namespace Avalonia.Markup.UnitTests.Data { var source = new Button { - Template = new FuncControlTemplate