Browse Source

Manually handle name scope registrations

pull/2705/head
Nikita Tsukanov 7 years ago
parent
commit
fa55755b71
  1. 2
      src/Avalonia.Controls/AutoCompleteBox.cs
  2. 21
      src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
  3. 19
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
  4. 14
      src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
  5. 6
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  6. 30
      src/Avalonia.Controls/Primitives/TemplatedControl.cs
  7. 4
      src/Avalonia.Controls/Templates/FuncControlTemplate.cs
  8. 6
      src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs
  9. 8
      src/Avalonia.Controls/Templates/FuncDataTemplate.cs
  10. 26
      src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs
  11. 24
      src/Avalonia.Controls/Templates/FuncTemplateNameScopeExtensions.cs
  12. 13
      src/Avalonia.Controls/Templates/FuncTemplate`2.cs
  13. 4
      src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs
  14. 15
      src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs
  15. 34
      src/Avalonia.Controls/UserControl.cs
  16. 34
      src/Avalonia.Controls/Window.cs
  17. 4
      src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs
  18. 15
      src/Avalonia.Styling/Controls/NameScope.cs
  19. 41
      src/Avalonia.Styling/Controls/NameScopeExtensions.cs
  20. 21
      src/Avalonia.Styling/StyledElement.cs
  21. 1
      src/Avalonia.Styling/Styling/Setter.cs
  22. 1
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  23. 69
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
  24. 12
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  25. 1
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  26. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
  27. 8
      src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs
  28. 10
      tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
  29. 4
      tests/Avalonia.Controls.UnitTests/CarouselTests.cs
  30. 10
      tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
  31. 12
      tests/Avalonia.Controls.UnitTests/ContentControlTests.cs
  32. 12
      tests/Avalonia.Controls.UnitTests/DatePickerTests.cs
  33. 21
      tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs
  34. 6
      tests/Avalonia.Controls.UnitTests/HeaderedItemsControlTests .cs
  35. 10
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
  36. 30
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
  37. 13
      tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs
  38. 17
      tests/Avalonia.Controls.UnitTests/Mixins/ContentControlMixinTests.cs
  39. 18
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs
  40. 16
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs
  41. 4
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs
  42. 2
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs
  43. 2
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs
  44. 8
      tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization_Simple.cs
  45. 6
      tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs
  46. 8
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  47. 6
      tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs
  48. 10
      tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs
  49. 4
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  50. 4
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs
  51. 10
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs
  52. 4
      tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs
  53. 58
      tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs
  54. 12
      tests/Avalonia.Controls.UnitTests/ScrollViewerTests.cs
  55. 18
      tests/Avalonia.Controls.UnitTests/TabControlTests.cs
  56. 4
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
  57. 4
      tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs
  58. 4
      tests/Avalonia.Controls.UnitTests/TopLevelTests.cs
  59. 18
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  60. 6
      tests/Avalonia.Controls.UnitTests/UserControlTests.cs
  61. 4
      tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs
  62. 4
      tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
  63. 10
      tests/Avalonia.Markup.UnitTests/Data/BindingTests_ElementName.cs
  64. 5
      tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs
  65. 6
      tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs
  66. 4
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs
  67. 4
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs
  68. 4
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs
  69. 8
      tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs
  70. 8
      tests/Avalonia.ReactiveUI.UnitTests/TransitioningContentControlTest.cs
  71. 82
      tests/Avalonia.Styling.UnitTests/ControlLocatorTests.cs
  72. 12
      tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs
  73. 13
      tests/Avalonia.Styling.UnitTests/SetterTests.cs
  74. 15
      tests/Avalonia.Styling.UnitTests/StyledElementTests.cs
  75. 69
      tests/Avalonia.Styling.UnitTests/StyledElementTests_NameScope.cs
  76. 4
      tests/Avalonia.Styling.UnitTests/StyledElementTests_Resources.cs
  77. 48
      tests/Avalonia.UnitTests/TestRoot.cs
  78. 33
      tests/Avalonia.UnitTests/TestTemplatedRoot.cs

2
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);

21
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<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> 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();
}

19
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<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> 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()

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

6
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

30
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
}
}
}
/// <summary>
/// Registers each control with its name scope.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="nameScope">The name scope.</param>
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);
}
}
}
}
}

4
src/Avalonia.Controls/Templates/FuncControlTemplate.cs

@ -16,9 +16,9 @@ namespace Avalonia.Controls.Templates
/// Initializes a new instance of the <see cref="FuncControlTemplate"/> class.
/// </summary>
/// <param name="build">The build function.</param>
public FuncControlTemplate(Func<ITemplatedControl, IControl> build)
public FuncControlTemplate(Func<ITemplatedControl, INameScope, IControl> build)
: base(build)
{
}
}
}
}

6
src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs

@ -17,9 +17,9 @@ namespace Avalonia.Controls.Templates
/// Initializes a new instance of the <see cref="FuncControlTemplate{T}"/> class.
/// </summary>
/// <param name="build">The build function.</param>
public FuncControlTemplate(Func<T, IControl> build)
: base(x => build((T)x))
public FuncControlTemplate(Func<T, INameScope, IControl> build)
: base((x, s) => build((T)x, s))
{
}
}
}
}

8
src/Avalonia.Controls/Templates/FuncDataTemplate.cs

@ -17,7 +17,7 @@ namespace Avalonia.Controls.Templates
/// </summary>
public static readonly FuncDataTemplate Default =
new FuncDataTemplate<object>(
data =>
(data, s) =>
{
if (data != null)
{
@ -49,7 +49,7 @@ namespace Avalonia.Controls.Templates
/// <param name="supportsRecycling">Whether the control can be recycled.</param>
public FuncDataTemplate(
Type type,
Func<object, IControl> build,
Func<object, INameScope, IControl> build,
bool supportsRecycling = false)
: this(o => IsInstance(o, type), build, supportsRecycling)
{
@ -67,7 +67,7 @@ namespace Avalonia.Controls.Templates
/// <param name="supportsRecycling">Whether the control can be recycled.</param>
public FuncDataTemplate(
Func<object, bool> match,
Func<object, IControl> build,
Func<object, INameScope, IControl> build,
bool supportsRecycling = false)
: base(build)
{
@ -105,4 +105,4 @@ namespace Avalonia.Controls.Templates
return (o != null) && t.GetTypeInfo().IsAssignableFrom(o.GetType().GetTypeInfo());
}
}
}
}

26
src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs

@ -18,7 +18,7 @@ namespace Avalonia.Controls.Templates
/// A function which when passed an object of <typeparamref name="T"/> returns a control.
/// </param>
/// <param name="supportsRecycling">Whether the control can be recycled.</param>
public FuncDataTemplate(Func<T, IControl> build, bool supportsRecycling = false)
public FuncDataTemplate(Func<T, INameScope, IControl> build, bool supportsRecycling = false)
: base(typeof(T), CastBuild(build), supportsRecycling)
{
}
@ -35,12 +35,30 @@ namespace Avalonia.Controls.Templates
/// <param name="supportsRecycling">Whether the control can be recycled.</param>
public FuncDataTemplate(
Func<T, bool> match,
Func<T, IControl> build,
Func<T, INameScope, IControl> build,
bool supportsRecycling = false)
: base(CastMatch(match), CastBuild(build), supportsRecycling)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="FuncDataTemplate{T}"/> class.
/// </summary>
/// <param name="match">
/// A function which determines whether the data template matches the specified data.
/// </param>
/// <param name="build">
/// A function which when passed an object of <typeparamref name="T"/> returns a control.
/// </param>
/// <param name="supportsRecycling">Whether the control can be recycled.</param>
public FuncDataTemplate(
Func<T, bool> match,
Func<T, IControl> build,
bool supportsRecycling = false)
: this(match, (a, _) => build(a), supportsRecycling)
{
}
/// <summary>
/// Casts a strongly typed match function to a weakly typed one.
/// </summary>
@ -57,9 +75,9 @@ namespace Avalonia.Controls.Templates
/// <typeparam name="TResult">The strong data type.</typeparam>
/// <param name="f">The strongly typed function.</param>
/// <returns>The weakly typed function.</returns>
private static Func<object, TResult> CastBuild<TResult>(Func<T, TResult> f)
private static Func<object, INameScope, TResult> CastBuild<TResult>(Func<T, INameScope, TResult> f)
{
return o => f((T)o);
return (o, s) => f((T)o, s);
}
}
}

24
src/Avalonia.Controls/Templates/FuncTemplateNameScopeExtensions.cs

@ -0,0 +1,24 @@
using System;
namespace Avalonia.Controls.Templates
{
public static class FuncTemplateNameScopeExtensions
{
public static T RegisterInNameScope<T>(this T control, INameScope scope)
where T : StyledElement
{
scope.Register(control.Name, control);
return control;
}
public static T WithNameScope<T>(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;
}
}
}

13
src/Avalonia.Controls/Templates/FuncTemplate`2.cs

@ -13,13 +13,13 @@ namespace Avalonia.Controls.Templates
public class FuncTemplate<TParam, TControl> : ITemplate<TParam, TControl>
where TControl : IControl
{
private readonly Func<TParam, TControl> _func;
private readonly Func<TParam, INameScope, TControl> _func;
/// <summary>
/// Initializes a new instance of the <see cref="FuncTemplate{TControl, TParam}"/> class.
/// </summary>
/// <param name="func">The function used to create the control.</param>
public FuncTemplate(Func<TParam, TControl> func)
public FuncTemplate(Func<TParam, INameScope, TControl> func)
{
Contract.Requires<ArgumentNullException>(func != null);
@ -35,7 +35,12 @@ namespace Avalonia.Controls.Templates
/// </returns>
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;
}
}
}
}

4
src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs

@ -28,7 +28,7 @@ namespace Avalonia.Controls.Templates
/// </param>
public FuncTreeDataTemplate(
Type type,
Func<object, IControl> build,
Func<object, INameScope, IControl> build,
Func<object, IEnumerable> itemsSelector)
: this(o => IsInstance(o, type), build, itemsSelector)
{
@ -48,7 +48,7 @@ namespace Avalonia.Controls.Templates
/// </param>
public FuncTreeDataTemplate(
Func<object, bool> match,
Func<object, IControl> build,
Func<object, INameScope, IControl> build,
Func<object, IEnumerable> itemsSelector)
: base(match, build)
{

15
src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs

@ -23,7 +23,7 @@ namespace Avalonia.Controls.Templates
/// items.
/// </param>
public FuncTreeDataTemplate(
Func<T, Control> build,
Func<T, INameScope, Control> build,
Func<T, IEnumerable> itemsSelector)
: base(
typeof(T),
@ -46,7 +46,7 @@ namespace Avalonia.Controls.Templates
/// </param>
public FuncTreeDataTemplate(
Func<T, bool> match,
Func<T, Control> build,
Func<T, INameScope, Control> build,
Func<T, IEnumerable> itemsSelector)
: base(
CastMatch(match),
@ -65,6 +65,17 @@ namespace Avalonia.Controls.Templates
return o => (o is T) && f((T)o);
}
/// <summary>
/// Casts a function with a typed parameter to an untyped function.
/// </summary>
/// <typeparam name="TResult">The result.</typeparam>
/// <param name="f">The typed function.</param>
/// <returns>The untyped function.</returns>
private static Func<object, INameScope, TResult> Cast<TResult>(Func<T, INameScope, TResult> f)
{
return (o, s) => f((T)o, s);
}
/// <summary>
/// Casts a function with a typed parameter to an untyped function.
/// </summary>

34
src/Avalonia.Controls/UserControl.cs

@ -9,40 +9,8 @@ namespace Avalonia.Controls
/// <summary>
/// Provides the base class for defining a new control that encapsulates related existing controls and provides its own logic.
/// </summary>
public class UserControl : ContentControl, IStyleable, INameScope
public class UserControl : ContentControl, IStyleable
{
private readonly NameScope _nameScope = new NameScope();
/// <inheritdoc/>
event EventHandler<NameScopeEventArgs> INameScope.Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
/// <inheritdoc/>
event EventHandler<NameScopeEventArgs> INameScope.Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}
/// <inheritdoc/>
void INameScope.Register(string name, object element)
{
_nameScope.Register(name, element);
}
/// <inheritdoc/>
object INameScope.Find(string name)
{
return _nameScope.Find(name);
}
/// <inheritdoc/>
void INameScope.Unregister(string name)
{
_nameScope.Unregister(name);
}
}
}

34
src/Avalonia.Controls/Window.cs

@ -48,7 +48,7 @@ namespace Avalonia.Controls
/// <summary>
/// A top-level window.
/// </summary>
public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot, INameScope
public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot
{
/// <summary>
/// Defines the <see cref="SizeToContent"/> property.
@ -157,20 +157,6 @@ namespace Avalonia.Controls
_maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
}
/// <inheritdoc/>
event EventHandler<NameScopeEventArgs> INameScope.Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
/// <inheritdoc/>
event EventHandler<NameScopeEventArgs> INameScope.Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}
/// <summary>
/// Gets the platform-specific window implementation.
/// </summary>
@ -494,24 +480,6 @@ namespace Avalonia.Controls
}
}
/// <inheritdoc/>
void INameScope.Register(string name, object element)
{
_nameScope.Register(name, element);
}
/// <inheritdoc/>
object INameScope.Find(string name)
{
return _nameScope.Find(name);
}
/// <inheritdoc/>
void INameScope.Unregister(string name)
{
_nameScope.Unregister(name);
}
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{

4
src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs

@ -16,7 +16,7 @@ namespace Avalonia.ReactiveUI
/// </summary>
public class AutoDataTemplateBindingHook : IPropertyBindingHook
{
private static FuncDataTemplate DefaultItemTemplate = new FuncDataTemplate<object>(x =>
private static FuncDataTemplate DefaultItemTemplate = new FuncDataTemplate<object>((x, _) =>
{
var control = new ViewModelViewHost();
var context = control.GetObservable(Control.DataContextProperty);
@ -52,4 +52,4 @@ namespace Avalonia.ReactiveUI
return true;
}
}
}
}

15
src/Avalonia.Styling/Controls/NameScope.cs

@ -106,6 +106,21 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Registers an element in the name scope associated with the scopeElement.
/// Creates the scope if one isn't associated with the element yet
/// </summary>
/// <param name="scopeElement"></param>
/// <param name="name"></param>
/// <param name="element"></param>
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);
}
/// <summary>
/// Finds a named element in the name scope.
/// </summary>

41
src/Avalonia.Styling/Controls/NameScopeExtensions.cs

@ -37,6 +37,25 @@ namespace Avalonia.Controls
return (T)result;
}
/// <summary>
/// Finds a named element in an <see cref="INameScope"/>.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="anchor">The control to take the name scope from.</param>
/// <param name="name">The name.</param>
/// <returns>The named element or null if not found.</returns>
public static T Find<T>(this ILogical anchor, string name)
where T : class
{
Contract.Requires<ArgumentNullException>(anchor != null);
Contract.Requires<ArgumentNullException>(name != null);
var styledAnchor = anchor as StyledElement;
if (styledAnchor == null)
return null;
var nameScope = (anchor as INameScope) ?? NameScope.GetNameScope(styledAnchor);
return nameScope?.Find<T>(name);
}
/// <summary>
/// Gets a named element from an <see cref="INameScope"/> or throws if no element of the
/// requested name was found.
@ -67,6 +86,28 @@ namespace Avalonia.Controls
return (T)result;
}
/// <summary>
/// Gets a named element from an <see cref="INameScope"/> or throws if no element of the
/// requested name was found.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="anchor">The control to take the name scope from.</param>
/// <param name="name">The name.</param>
/// <returns>The named element.</returns>
public static T Get<T>(this ILogical anchor, string name)
where T : class
{
Contract.Requires<ArgumentNullException>(anchor != null);
Contract.Requires<ArgumentNullException>(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<T>(name);
}
public static INameScope FindNameScope(this ILogical control)
{
Contract.Requires<ArgumentNullException>(control != null);

21
src/Avalonia.Styling/StyledElement.cs

@ -61,7 +61,6 @@ namespace Avalonia
private readonly Classes _classes = new Classes();
private bool _isAttachedToLogicalTree;
private IAvaloniaList<ILogical> _logicalChildren;
private INameScope _nameScope;
private IResourceDictionary _resources;
private Styles _styles;
private bool _styled;
@ -82,7 +81,6 @@ namespace Avalonia
/// </summary>
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<IStyler>()?.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);

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

1
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"),

69
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<ScopeRegistrationNode>().Any())
&& mg.Children.OfType<AvaloniaNameScopeRegistrationXamlIlNode>().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);
}
}
}

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

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

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@ -1 +1 @@
Subproject commit 894b2c02827fd5eb16a338de5d5b6c9fbc60fef5
Subproject commit fc52295ea6c45f709bf63975026a4a18ce230be9

8
src/Markup/Avalonia.Markup.Xaml/XamlTypes.cs

@ -10,7 +10,15 @@ namespace Avalonia.Markup.Xaml
public interface IRootObjectProvider
{
/// <summary>
/// The root object of the xaml file
/// </summary>
object RootObject { get; }
/// <summary>
/// The "current" root object, contains either the root of the xaml file
/// or the root object of the control/data template
/// </summary>
object IntermediateRootObject { get; }
}
public interface IUriContext

10
tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs

@ -1012,25 +1012,25 @@ namespace Avalonia.Controls.UnitTests
}
private IControlTemplate CreateTemplate()
{
return new FuncControlTemplate<AutoCompleteBox>(control =>
return new FuncControlTemplate<AutoCompleteBox>((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);

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

10
tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs

@ -80,7 +80,7 @@ namespace Avalonia.Controls.UnitTests
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<ComboBox>(parent =>
return new FuncControlTemplate<ComboBox>((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);
});
}
}

12
tests/Avalonia.Controls.UnitTests/ContentControlTests.cs

@ -126,7 +126,7 @@ namespace Avalonia.Controls.UnitTests
var target = new ContentControl
{
Template = GetTemplate(),
ContentTemplate = new FuncDataTemplate<string>(_ => new Canvas()),
ContentTemplate = new FuncDataTemplate<string>((_, __) => new Canvas()),
};
target.Content = "Foo";
@ -302,8 +302,8 @@ namespace Avalonia.Controls.UnitTests
var target = new ContentControl
{
Template = new FuncControlTemplate<ContentControl>(_ => presenter),
ContentTemplate = new FuncDataTemplate<string>(x => new Canvas()),
Template = new FuncControlTemplate<ContentControl>((_, __) => presenter),
ContentTemplate = new FuncDataTemplate<string>((_, __) => new Canvas()),
Content = "foo",
};
@ -333,7 +333,7 @@ namespace Avalonia.Controls.UnitTests
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<ContentControl>(parent =>
return new FuncControlTemplate<ContentControl>((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);
});
}
}

12
tests/Avalonia.Controls.UnitTests/DatePickerTests.cs

@ -93,30 +93,30 @@ namespace Avalonia.Controls.UnitTests
private IControlTemplate CreateTemplate()
{
return new FuncControlTemplate<DatePicker>(control =>
return new FuncControlTemplate<DatePicker>((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);

21
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<GridSplitter>("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<GridSplitter>("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<GridSplitter>("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<GridSplitter>("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));
}
}
}
}

6
tests/Avalonia.Controls.UnitTests/HeaderedItemsControlTests .cs

@ -63,7 +63,7 @@ namespace Avalonia.Controls.UnitTests
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<HeaderedItemsControl>(parent =>
return new FuncControlTemplate<HeaderedItemsControl>((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);
});
}
}

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

@ -23,7 +23,7 @@ namespace Avalonia.Controls.UnitTests
var target = new ItemsControl
{
Template = GetTemplate(),
ItemTemplate = new FuncDataTemplate<string>(_ => new Canvas()),
ItemTemplate = new FuncDataTemplate<string>((_, __) => new Canvas()),
};
target.Items = new[] { "Foo" };
@ -411,7 +411,7 @@ namespace Avalonia.Controls.UnitTests
DataContext = "Base",
DataTemplates =
{
new FuncDataTemplate<Item>(x => new Button { Content = x })
new FuncDataTemplate<Item>((x, __) => new Button { Content = x })
},
Items = items,
};
@ -578,7 +578,7 @@ namespace Avalonia.Controls.UnitTests
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<ItemsControl>(parent =>
return new FuncControlTemplate<ItemsControl>((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);
});
}

30
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@ -25,7 +25,7 @@ namespace Avalonia.Controls.UnitTests
{
Template = ListBoxTemplate(),
Items = new[] { "Foo" },
ItemTemplate = new FuncDataTemplate<string>(_ => new Canvas()),
ItemTemplate = new FuncDataTemplate<string>((_, __) => new Canvas()),
};
Prepare(target);
@ -113,7 +113,7 @@ namespace Avalonia.Controls.UnitTests
DataContext = "Base",
DataTemplates =
{
new FuncDataTemplate<Item>(x => new Button { Content = x })
new FuncDataTemplate<Item>((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<string>(x => new TextBlock { Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((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<string>(x => new TextBlock { Width = 20, Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Width = 20, Height = 10 }),
SelectedIndex = 0,
};
@ -181,7 +181,7 @@ namespace Avalonia.Controls.UnitTests
{
Template = ListBoxTemplate(),
Items = items,
ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Width = 20, Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((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<string>(x => new TextBlock { Height = 10 })
ItemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Height = 10 })
};
Prepare(target);
@ -239,7 +239,7 @@ namespace Avalonia.Controls.UnitTests
{
Template = ListBoxTemplate(),
Items = items,
ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Height = 11 })
ItemTemplate = new FuncDataTemplate<string>((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<object>(c =>
target.ItemTemplate = new FuncDataTemplate<object>((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<ListBox>(parent =>
return new FuncControlTemplate<ListBox>((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<ListBoxItem>(parent =>
return new FuncControlTemplate<ListBoxItem>((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<ScrollViewer>(parent =>
return new FuncControlTemplate<ScrollViewer>((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)

13
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)

17
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();

18
tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_InTemplate.cs

@ -170,7 +170,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
var (target, _) = CreateTarget();
target.ContentTemplate = new FuncDataTemplate<string>(_ => new Canvas());
target.ContentTemplate = new FuncDataTemplate<string>((_, __) => new Canvas());
target.Content = "Foo";
Assert.IsType<Canvas>(target.Child);
@ -184,7 +184,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
target.Content = "Foo";
Assert.IsType<TextBlock>(target.Child);
target.ContentTemplate = new FuncDataTemplate<string>(_ => new Canvas());
target.ContentTemplate = new FuncDataTemplate<string>((_, __) => new Canvas());
Assert.IsType<Canvas>(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<string>(_ => new Border(), true));
target.DataTemplates.Add(new FuncDataTemplate<string>((_, __) => 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<string>(_ => new Border(), false));
target.DataTemplates.Add(new FuncDataTemplate<string>((_, __) => new Border(), false));
target.Content = "foo";
@ -256,7 +256,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
var (target, _) = CreateTarget();
target.DataTemplates.Add(new FuncDataTemplate<string>(x => x == "bar", _ => new Canvas(), true));
target.DataTemplates.Add(new FuncDataTemplate<string>(_ => new Border(), true));
target.DataTemplates.Add(new FuncDataTemplate<string>((_, __) => new Border(), true));
target.Content = "foo";
@ -278,8 +278,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
};
var (target, host) = CreateTarget();
host.DataTemplates.Add(new FuncDataTemplate<string>(x => textBlock));
host.DataTemplates.Add(new FuncDataTemplate<int>(x => new Canvas()));
host.DataTemplates.Add(new FuncDataTemplate<string>((_, __) => textBlock));
host.DataTemplates.Add(new FuncDataTemplate<int>((_, __) => 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<ContentControl>(x =>
Template = new FuncControlTemplate<ContentControl>((_, s) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
}),
}.RegisterInNameScope(s).WithNameScope(s)),
};
var root = new TestRoot { Child = templatedParent };

16
tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs

@ -54,7 +54,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
var target = new ContentPresenter
{
ContentTemplate =
new FuncDataTemplate<string>(t => new ContentControl() { Content = t }, false)
new FuncDataTemplate<string>((t, _) => new ContentControl() { Content = t }, false)
};
var parentMock = new Mock<Control>();
@ -93,14 +93,14 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
var contentControl = new ContentControl
{
Template = new FuncControlTemplate<ContentControl>(c => new ContentPresenter()
Template = new FuncControlTemplate<ContentControl>((c, scope) => new ContentPresenter()
{
Name = "PART_ContentPresenter",
[~ContentPresenter.ContentProperty] = c[~ContentControl.ContentProperty],
[~ContentPresenter.ContentTemplateProperty] = c[~ContentControl.ContentTemplateProperty]
}),
}.RegisterInNameScope(scope).WithNameScope(scope)),
ContentTemplate =
new FuncDataTemplate<string>(t => new ContentControl() { Content = t }, false)
new FuncDataTemplate<string>((t, _) => new ContentControl() { Content = t }, false)
};
var parentMock = new Mock<Control>();
@ -144,7 +144,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
var target = new ContentPresenter
{
ContentTemplate =
new FuncDataTemplate<string>(t => new ContentControl() { Content = t }, false)
new FuncDataTemplate<string>((t, _) => new ContentControl() { Content = t }, false)
};
var parentMock = new Mock<Control>();
@ -179,7 +179,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
var target = new ContentPresenter
{
ContentTemplate =
new FuncDataTemplate<string>(t => new ContentControl() { Content = t }, false)
new FuncDataTemplate<string>((t, _) => new ContentControl() { Content = t }, false)
};
target.Content = "foo";
@ -235,8 +235,8 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
DataTemplates =
{
new FuncDataTemplate<string>(x => textBlock),
new FuncDataTemplate<int>(x => new Canvas()),
new FuncDataTemplate<string>((x, _) => textBlock),
new FuncDataTemplate<int>((x, _) => new Canvas()),
},
};

4
tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs

@ -90,7 +90,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
DataTemplates =
{
new FuncDataTemplate<string>(x => new Decorator()),
new FuncDataTemplate<string>((x, _) => new Decorator()),
},
};
@ -99,4 +99,4 @@ namespace Avalonia.Controls.UnitTests.Presenters
Assert.IsType<Decorator>(target.Child);
}
}
}
}

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

@ -220,7 +220,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
VirtualizationMode = ItemVirtualizationMode.None,
Items = items,
ItemTemplate = new FuncDataTemplate<string>(x => new TextBlock { Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Height = 10 }),
};
target.ApplyTemplate();

2
tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests_Virtualization.cs

@ -309,7 +309,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
private static IDataTemplate ItemTemplate()
{
return new FuncDataTemplate<string>(x => new Canvas
return new FuncDataTemplate<string>((x, _) => new Canvas
{
Width = 10,
Height = 10,

8
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<string>(x => new TextBlock { Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Height = 10 }),
};
target.ApplyTemplate();
@ -1046,7 +1046,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
private static IDataTemplate StringDataTemplate()
{
return new FuncDataTemplate<string>(x => new Canvas
return new FuncDataTemplate<string>((x, _) => new Canvas
{
Width = 10,
Height = 10,
@ -1095,12 +1095,12 @@ namespace Avalonia.Controls.UnitTests.Presenters
{
public TestContainer()
{
Template = new FuncControlTemplate<TestContainer>(parent => new ContentPresenter
Template = new FuncControlTemplate<TestContainer>((parent, scope) => new ContentPresenter
{
Name = "PART_ContentPresenter",
[~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty],
[~ContentPresenter.ContentTemplateProperty] = parent[~ContentControl.ContentTemplateProperty],
});
}.RegisterInNameScope(scope).WithNameScope(scope));
}
}
}

6
tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs

@ -134,12 +134,12 @@ namespace Avalonia.Controls.UnitTests.Primitives
{
var result = new PopupRoot
{
Template = new FuncControlTemplate<PopupRoot>(parent =>
Template = new FuncControlTemplate<PopupRoot>((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<TemplatedControlWithPopup>(parent =>
Template = new FuncControlTemplate<TemplatedControlWithPopup>((parent, _) =>
new Popup
{
[!Popup.ChildProperty] = parent[!TemplatedControlWithPopup.PopupContentProperty],

8
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

6
tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs

@ -111,7 +111,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
var target = new TestRange()
{
Template = new FuncControlTemplate<RangeBase>(c =>
Template = new FuncControlTemplate<RangeBase>((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,

10
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<Thumb>(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
};
}
}
}
}

4
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@ -896,13 +896,13 @@ namespace Avalonia.Controls.UnitTests.Primitives
private FuncControlTemplate Template()
{
return new FuncControlTemplate<SelectingItemsControl>(control =>
return new FuncControlTemplate<SelectingItemsControl>((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

4
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs

@ -84,13 +84,13 @@ namespace Avalonia.Controls.UnitTests.Primitives
private FuncControlTemplate Template()
{
return new FuncControlTemplate<SelectingItemsControl>(control =>
return new FuncControlTemplate<SelectingItemsControl>((control, scope) =>
new ItemsPresenter
{
Name = "itemsPresenter",
[~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty],
[~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty],
});
}.RegisterInNameScope(scope).WithNameScope(scope));
}
private class TestSelector : SelectingItemsControl

10
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<string>(x => new TextBlock { Width = 20, Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((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<string>(x => new TextBlock { Width = 20, Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((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<string>(x => new TextBlock { Width = 20, Height = 10 }),
ItemTemplate = new FuncDataTemplate<string>((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<SelectingItemsControl>(control =>
return new FuncControlTemplate<SelectingItemsControl>((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

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

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

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

18
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@ -129,7 +129,7 @@ namespace Avalonia.Controls.UnitTests
},
};
var template = new FuncControlTemplate<TabItem>(x => new Decorator());
var template = new FuncControlTemplate<TabItem>((x, __) => new Decorator());
using (UnitTestApplication.Start(TestServices.RealStyler))
{
@ -176,7 +176,7 @@ namespace Avalonia.Controls.UnitTests
DataContext = "Base",
DataTemplates =
{
new FuncDataTemplate<Item>(x => new Button { Content = x })
new FuncDataTemplate<Item>((x, __) => new Button { Content = x })
},
Items = items,
};
@ -273,7 +273,7 @@ namespace Avalonia.Controls.UnitTests
TabControl target = new TabControl
{
Template = TabControlTemplate(),
ContentTemplate = new FuncDataTemplate<string>(x =>
ContentTemplate = new FuncDataTemplate<string>((x, _) =>
new TextBlock { Tag = "bar", Text = x }),
Items = new[] { "Foo" },
};
@ -289,7 +289,7 @@ namespace Avalonia.Controls.UnitTests
private IControlTemplate TabControlTemplate()
{
return new FuncControlTemplate<TabControl>(parent =>
return new FuncControlTemplate<TabControl>((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<TabItem>(parent =>
return new FuncControlTemplate<TabItem>((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)

4
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@ -456,7 +456,7 @@ namespace Avalonia.Controls.UnitTests
private IControlTemplate CreateTemplate()
{
return new FuncControlTemplate<TextBox>(control =>
return new FuncControlTemplate<TextBox>((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)

4
tests/Avalonia.Controls.UnitTests/TextBoxTests_DataValidation.cs

@ -93,7 +93,7 @@ namespace Avalonia.Controls.UnitTests
private IControlTemplate CreateTemplate()
{
return new FuncControlTemplate<TextBox>(control =>
return new FuncControlTemplate<TextBox>((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

4
tests/Avalonia.Controls.UnitTests/TopLevelTests.cs

@ -226,12 +226,12 @@ namespace Avalonia.Controls.UnitTests
private FuncControlTemplate<TestTopLevel> CreateTemplate()
{
return new FuncControlTemplate<TestTopLevel>(x =>
return new FuncControlTemplate<TestTopLevel>((x, scope) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
});
}.RegisterInNameScope(scope).WithNameScope(scope));
}
private class TestTopLevel : TopLevel

18
tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

@ -50,7 +50,7 @@ namespace Avalonia.Controls.UnitTests
Template = CreateTreeViewTemplate(),
Items = CreateTestTreeData(),
ItemTemplate = new FuncTreeDataTemplate<Node>(
_ => new Canvas(),
(_, __) => new Canvas(),
x => x.Children),
}
};
@ -475,7 +475,7 @@ namespace Avalonia.Controls.UnitTests
DataContext = "Base",
DataTemplates =
{
new FuncDataTemplate<Node>(x => new Button { Content = x })
new FuncDataTemplate<Node>((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<TreeView>(parent => new ItemsPresenter
return new FuncControlTemplate<TreeView>((parent, scope) => new ItemsPresenter
{
Name = "PART_ItemsPresenter",
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
});
}.RegisterInNameScope(scope).WithNameScope(scope));
}
private IControlTemplate CreateTreeViewItemTemplate()
{
return new FuncControlTemplate<TreeViewItem>(parent => new Panel
return new FuncControlTemplate<TreeViewItem>((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<string> ExtractItemHeader(TreeView tree, int level)

6
tests/Avalonia.Controls.UnitTests/UserControlTests.cs

@ -40,7 +40,7 @@ namespace Avalonia.Controls.UnitTests
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<UserControl>(parent =>
return new FuncControlTemplate<UserControl>((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);
});
}
}

4
tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs

@ -59,13 +59,13 @@ namespace Avalonia.Controls.UnitTests.Utils
private FuncControlTemplate CreateWindowTemplate()
{
return new FuncControlTemplate<Window>(parent =>
return new FuncControlTemplate<Window>((parent, scope) =>
{
return new ContentPresenter
{
Name = "PART_ContentPresenter",
[~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty],
};
}.RegisterInNameScope(scope).WithNameScope(scope);
});
}
}

4
tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs

@ -253,12 +253,12 @@ namespace Avalonia.Controls.UnitTests
private FuncControlTemplate<TestWindowBase> CreateTemplate()
{
return new FuncControlTemplate<TestWindowBase>(x =>
return new FuncControlTemplate<TestWindowBase>((x, scope) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
});
}.RegisterInNameScope(scope).WithNameScope(scope));
}
private class TestWindowBase : WindowBase

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

5
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]

6
tests/Avalonia.Markup.UnitTests/Data/TemplateBindingTests.cs

@ -18,7 +18,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
var source = new Button
{
Template = new FuncControlTemplate<Button>(parent =>
Template = new FuncControlTemplate<Button>((parent, _) =>
new ContentPresenter
{
[~ContentPresenter.ContentProperty] = new TemplateBinding(ContentControl.ContentProperty)
@ -41,7 +41,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
var source = new Button
{
Template = new FuncControlTemplate<Button>(parent =>
Template = new FuncControlTemplate<Button>((parent, _) =>
new ContentPresenter
{
[~ContentPresenter.ContentProperty] = new TemplateBinding(ContentControl.ContentProperty)
@ -67,7 +67,7 @@ namespace Avalonia.Markup.UnitTests.Data
{
var source = new Button
{
Template = new FuncControlTemplate<Button>(parent =>
Template = new FuncControlTemplate<Button>((parent, _) =>
new ContentPresenter
{
[~ContentPresenter.ContentProperty] = new TemplateBinding(ContentControl.ContentProperty)

4
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs

@ -58,12 +58,12 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
new Setter(
Window.TemplateProperty,
new FuncControlTemplate<Window>(x =>
new FuncControlTemplate<Window>((x, scope) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!Window.ContentProperty],
}))
}.RegisterInNameScope(scope).WithNameScope(scope)))
}
};
}

4
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceExtensionTests.cs

@ -647,12 +647,12 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
new Setter(
Window.TemplateProperty,
new FuncControlTemplate<Window>(x =>
new FuncControlTemplate<Window>((x, scope) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!Window.ContentProperty],
}))
}.RegisterInNameScope(scope).WithNameScope(scope)))
}
};
}

4
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs

@ -534,12 +534,12 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
new Setter(
Window.TemplateProperty,
new FuncControlTemplate<Window>(x =>
new FuncControlTemplate<Window>((x, scope) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!Window.ContentProperty],
}))
}.RegisterInNameScope(scope).WithNameScope(scope)))
}
};
}

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

@ -98,7 +98,7 @@ namespace Avalonia.ReactiveUI.UnitTests
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<ItemsControl>(parent =>
return new FuncControlTemplate<ItemsControl>((parent, scope) =>
{
return new Border
{
@ -108,9 +108,9 @@ namespace Avalonia.ReactiveUI.UnitTests
Name = "PART_ItemsPresenter",
MemberSelector = parent.MemberSelector,
[~ItemsPresenter.ItemsProperty] = parent[~ItemsControl.ItemsProperty],
}
};
}.RegisterInNameScope(scope)
}.WithNameScope(scope);
});
}
}
}
}

8
tests/Avalonia.ReactiveUI.UnitTests/TransitioningContentControlTest.cs

@ -45,7 +45,7 @@ namespace Avalonia.ReactiveUI.UnitTests
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<ContentControl>(parent =>
return new FuncControlTemplate<ContentControl>((parent, scope) =>
{
return new Border
{
@ -55,9 +55,9 @@ namespace Avalonia.ReactiveUI.UnitTests
Name = "PART_ContentPresenter",
[~ContentPresenter.ContentProperty] = parent[~ContentControl.ContentProperty],
[~ContentPresenter.ContentTemplateProperty] = parent[~ContentControl.ContentTemplateProperty],
}
};
}.RegisterInNameScope(scope)
}.WithNameScope(scope);
});
}
}
}
}

82
tests/Avalonia.Styling.UnitTests/ControlLocatorTests.cs

@ -31,15 +31,19 @@ namespace Avalonia.Styling.UnitTests
}
}
};
var scope = Register(root, relativeTo);
Register(root, target);
var locator = ControlLocator.Track(relativeTo, "target");
var result = await locator.Take(1);
Assert.Same(target, result);
Assert.Equal(0, root.NameScopeRegisteredSubscribers);
Assert.Equal(0, root.NameScopeUnregisteredSubscribers);
Assert.Equal(0, scope.RegisteredSubscribers);
Assert.Equal(0, scope.UnregisteredSubscribers);
}
[Fact]
public void Track_By_Name_Should_Find_Control_Added_Later()
{
@ -59,6 +63,7 @@ namespace Avalonia.Styling.UnitTests
}
})
};
var scope = Register(root, relativeTo);
var locator = ControlLocator.Track(relativeTo, "target");
var target = new TextBlock { Name = "target" };
@ -67,11 +72,12 @@ namespace Avalonia.Styling.UnitTests
using (locator.Subscribe(x => result.Add(x)))
{
panel.Children.Add(target);
Register(root, target);
}
Assert.Equal(new[] { null, target }, result);
Assert.Equal(0, root.NameScopeRegisteredSubscribers);
Assert.Equal(0, root.NameScopeUnregisteredSubscribers);
Assert.Equal(0, scope.RegisteredSubscribers);
Assert.Equal(0, scope.UnregisteredSubscribers);
}
[Fact]
@ -92,14 +98,18 @@ namespace Avalonia.Styling.UnitTests
}
}
};
var scope = Register(root, target);
Register(root, relativeTo);
var locator = ControlLocator.Track(relativeTo, "target");
var result = new List<ILogical>();
locator.Subscribe(x => result.Add(x));
var other = new TextBlock { Name = "target" };
panel.Children.Remove(target);
scope.Unregister(target.Name);
panel.Children.Add(other);
Register(root, other);
Assert.Equal(new[] { target, null, other }, result);
}
@ -125,6 +135,9 @@ namespace Avalonia.Styling.UnitTests
}
}
};
var scope1 = Register(root1, relativeTo);
Register(root1, relativeTo);
Register(root1, target1);
var root2 = new TestRoot
{
@ -136,20 +149,73 @@ namespace Avalonia.Styling.UnitTests
}
}
};
var scope2 = Register(root2, target2);
var locator = ControlLocator.Track(relativeTo, "target");
var target = new TextBlock { Name = "target" };
var result = new List<ILogical>();
using (locator.Subscribe(x => result.Add(x)))
{
((StackPanel)root1.Child).Children.Remove(relativeTo);
scope1.Unregister(relativeTo.Name);
((StackPanel)root2.Child).Children.Add(relativeTo);
Register(root2, relativeTo);
}
Assert.Equal(new[] { target1, null, target2 }, result);
Assert.Equal(0, root1.NameScopeRegisteredSubscribers);
Assert.Equal(0, root1.NameScopeUnregisteredSubscribers);
Assert.Equal(0, scope1.RegisteredSubscribers);
Assert.Equal(0, scope1.UnregisteredSubscribers);
Assert.Equal(0, scope2.RegisteredSubscribers);
Assert.Equal(0, scope2.UnregisteredSubscribers);
}
TrackingNameScope Register(StyledElement anchor, StyledElement element)
{
var scope = (TrackingNameScope)NameScope.GetNameScope(anchor);
if (scope == null)
NameScope.SetNameScope(anchor, scope = new TrackingNameScope());
NameScope.Register(anchor, element.Name, element);
return scope;
}
class TrackingNameScope : INameScope
{
public int RegisteredSubscribers { get; private set; }
public int UnregisteredSubscribers { get; private set; }
private NameScope _inner = new NameScope();
public event EventHandler<NameScopeEventArgs> Registered
{
add
{
_inner.Registered += value;
RegisteredSubscribers++;
}
remove
{
_inner.Registered -= value;
RegisteredSubscribers--;
}
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add
{
_inner.Unregistered += value;
UnregisteredSubscribers++;
}
remove
{
_inner.Unregistered -= value;
UnregisteredSubscribers--;
}
}
public void Register(string name, object element) => _inner.Register(name, element);
public object Find(string name) => _inner.Find(name);
public void Unregister(string name) => _inner.Unregister(name);
}
}
}

12
tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs

@ -16,12 +16,12 @@ namespace Avalonia.Styling.UnitTests
[Fact]
public void Named_Template_Child_Of_Control_With_Two_Classes()
{
var template = new FuncControlTemplate(parent =>
var template = new FuncControlTemplate((parent, scope) =>
{
return new Border
{
Name = "border",
};
}.RegisterInNameScope(scope).WithNameScope(scope);
});
var control = new Button
@ -55,12 +55,12 @@ namespace Avalonia.Styling.UnitTests
[Fact]
public void Named_OfType_Template_Child_Of_Control_With_Two_Classes_Wrong_Type()
{
var template = new FuncControlTemplate(parent =>
var template = new FuncControlTemplate((parent, scope) =>
{
return new Border
{
Name = "border",
};
}.RegisterInNameScope(scope).WithNameScope(scope);
});
var control = new Button
@ -88,12 +88,12 @@ namespace Avalonia.Styling.UnitTests
[Fact]
public void Named_Class_Template_Child_Of_Control()
{
var template = new FuncControlTemplate(parent =>
var template = new FuncControlTemplate((parent, scope) =>
{
return new Border
{
Name = "border",
};
}.RegisterInNameScope(scope).WithNameScope(scope);
});
var control = new Button

13
tests/Avalonia.Styling.UnitTests/SetterTests.cs

@ -51,19 +51,6 @@ namespace Avalonia.Styling.UnitTests
Assert.IsType<Canvas>(control.Child);
}
[Fact]
public void Materializes_Template_Should_Be_NameScope()
{
var control = new Decorator();
var template = new FuncTemplate<Canvas>(() => new Canvas());
var style = Mock.Of<IStyle>();
var setter = new Setter(Decorator.ChildProperty, template);
setter.Apply(style, control, null);
Assert.NotNull(NameScope.GetNameScope((Control)control.Child));
}
[Fact]
public void Does_Not_Call_Converter_ConvertBack_On_OneWay_Binding()
{

15
tests/Avalonia.Styling.UnitTests/StyledElementTests.cs

@ -236,21 +236,6 @@ namespace Avalonia.Styling.UnitTests
}
}
[Fact]
public void Adding_To_Logical_Tree_Should_Register_With_NameScope()
{
using (AvaloniaLocator.EnterScope())
{
var root = new TestRoot();
var child = new Border();
child.Name = "foo";
root.Child = child;
Assert.Same(root.FindControl<Border>("foo"), child);
}
}
[Fact]
public void Name_Cannot_Be_Set_After_Added_To_Logical_Tree()
{

69
tests/Avalonia.Styling.UnitTests/StyledElementTests_NameScope.cs

@ -1,69 +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.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests
{
public class StyledElementTests_NameScope
{
[Fact]
public void Controls_Should_Register_With_NameScope()
{
var root = new TestRoot
{
Child = new Border
{
Name = "foo",
Child = new Border
{
Name = "bar",
}
}
};
root.ApplyTemplate();
Assert.Same(root.FindControl<Border>("foo"), root.Child);
Assert.Same(root.FindControl<Border>("bar"), ((Border)root.Child).Child);
}
[Fact]
public void Control_Should_Unregister_With_NameScope()
{
var root = new TestRoot
{
Child = new Border
{
Name = "foo",
Child = new Border
{
Name = "bar",
}
}
};
root.Child = null;
Assert.Null(root.FindControl<Border>("foo"));
Assert.Null(root.FindControl<Border>("bar"));
}
[Fact]
public void Control_Should_Not_Register_With_Template_NameScope()
{
var root = new TestTemplatedRoot
{
Content = new Border
{
Name = "foo",
}
};
root.ApplyTemplate();
Assert.Null(NameScope.GetNameScope((StyledElement)root.Presenter).Find("foo"));
}
}
}

4
tests/Avalonia.Styling.UnitTests/StyledElementTests_Resources.cs

@ -222,12 +222,12 @@ namespace Avalonia.Controls.UnitTests
private IControlTemplate ContentControlTemplate()
{
return new FuncControlTemplate<ContentControl>(x =>
return new FuncControlTemplate<ContentControl>((x, scope) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
});
}.RegisterInNameScope(scope).WithNameScope(scope));
}
}
}

48
tests/Avalonia.UnitTests/TestRoot.cs

@ -9,11 +9,12 @@ using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Styling;
using Avalonia.VisualTree;
using Moq;
namespace Avalonia.UnitTests
{
public class TestRoot : Decorator, IFocusScope, ILayoutRoot, IInputRoot, INameScope, IRenderRoot, IStyleRoot
public class TestRoot : Decorator, IFocusScope, ILayoutRoot, IInputRoot, IRenderRoot, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();
@ -28,22 +29,6 @@ namespace Avalonia.UnitTests
Child = child;
}
event EventHandler<NameScopeEventArgs> INameScope.Registered
{
add { _nameScope.Registered += value; ++NameScopeRegisteredSubscribers; }
remove { _nameScope.Registered -= value; --NameScopeRegisteredSubscribers; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; ++NameScopeUnregisteredSubscribers; }
remove { _nameScope.Unregistered -= value; --NameScopeUnregisteredSubscribers; }
}
public int NameScopeRegisteredSubscribers { get; private set; }
public int NameScopeUnregisteredSubscribers { get; private set; }
public Size ClientSize { get; set; } = new Size(100, 100);
public Size MaxClientSize { get; set; } = Size.Infinity;
@ -94,19 +79,24 @@ namespace Avalonia.UnitTests
public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
void INameScope.Register(string name, object element)
public void RegisterChildrenNames()
{
_nameScope.Register(name, element);
}
object INameScope.Find(string name)
{
return _nameScope.Find(name);
}
void INameScope.Unregister(string name)
{
_nameScope.Unregister(name);
var scope = NameScope.GetNameScope(this) ?? new NameScope();
NameScope.SetNameScope(this, scope);
void Visit(StyledElement element, bool force = false)
{
if (element.Name != null)
{
if (scope.Find(element.Name) != element)
NameScope.Register(this, element.Name, element);
}
if(element is IVisual visual && (force || NameScope.GetNameScope(element) == null))
foreach(var child in visual.GetVisualChildren())
if (child is StyledElement styledChild)
Visit(styledChild);
}
Visit(this, true);
}
}
}

33
tests/Avalonia.UnitTests/TestTemplatedRoot.cs

@ -12,28 +12,16 @@ using Avalonia.Styling;
namespace Avalonia.UnitTests
{
public class TestTemplatedRoot : ContentControl, ILayoutRoot, INameScope, IRenderRoot, IStyleRoot
public class TestTemplatedRoot : ContentControl, ILayoutRoot, IRenderRoot, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();
public TestTemplatedRoot()
{
Template = new FuncControlTemplate<TestTemplatedRoot>(x => new ContentPresenter
Template = new FuncControlTemplate<TestTemplatedRoot>((x, scope) => new ContentPresenter
{
Name = "PART_ContentPresenter",
});
}
public event EventHandler<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}.RegisterInNameScope(scope).WithNameScope(scope));
}
public Size ClientSize => new Size(100, 100);
@ -63,20 +51,5 @@ namespace Avalonia.UnitTests
public Point PointToClient(PixelPoint p) => p.ToPoint(1);
public PixelPoint PointToScreen(Point p) => PixelPoint.FromPoint(p, 1);
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);
}
}
}

Loading…
Cancel
Save