diff --git a/build/Base.props b/build/Base.props
index e565ab1664..a60373ebb3 100644
--- a/build/Base.props
+++ b/build/Base.props
@@ -2,4 +2,4 @@
-
\ No newline at end of file
+
diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
index c2c0cd4301..9c72321472 100644
--- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
+++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
@@ -150,6 +150,7 @@
+
diff --git a/src/Avalonia.Base/Utilities/SynchronousCompletionAsyncResult.cs b/src/Avalonia.Base/Utilities/SynchronousCompletionAsyncResult.cs
new file mode 100644
index 0000000000..f321b2b2f1
--- /dev/null
+++ b/src/Avalonia.Base/Utilities/SynchronousCompletionAsyncResult.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+namespace Avalonia.Utilities
+{
+ ///
+ /// A task-like operation that is guaranteed to finish continuations synchronously,
+ /// can be used for parametrized one-shot events
+ ///
+ public struct SynchronousCompletionAsyncResult : INotifyCompletion
+ {
+ private readonly SynchronousCompletionAsyncResultSource _source;
+ private readonly T _result;
+ private readonly bool _isValid;
+ internal SynchronousCompletionAsyncResult(SynchronousCompletionAsyncResultSource source)
+ {
+ _source = source;
+ _result = default;
+ _isValid = true;
+ }
+
+ public SynchronousCompletionAsyncResult(T result)
+ {
+ _result = result;
+ _source = null;
+ _isValid = true;
+ }
+
+ static void ThrowNotInitialized() =>
+ throw new InvalidOperationException("This SynchronousCompletionAsyncResult was not initialized");
+
+ public bool IsCompleted
+ {
+ get
+ {
+ if (!_isValid)
+ ThrowNotInitialized();
+ return _source == null || _source.IsCompleted;
+ }
+ }
+
+ public T GetResult()
+ {
+ if (!_isValid)
+ ThrowNotInitialized();
+ return _source == null ? _result : _source.Result;
+ }
+
+
+ public void OnCompleted(Action continuation)
+ {
+ if (!_isValid)
+ ThrowNotInitialized();
+ if (_source == null)
+ continuation();
+ else
+ _source.OnCompleted(continuation);
+ }
+
+ public SynchronousCompletionAsyncResult GetAwaiter() => this;
+ }
+
+ ///
+ /// Source for incomplete SynchronousCompletionAsyncResult
+ ///
+ ///
+ public class SynchronousCompletionAsyncResultSource
+ {
+ private T _result;
+ internal bool IsCompleted { get; private set; }
+ public SynchronousCompletionAsyncResult AsyncResult => new SynchronousCompletionAsyncResult(this);
+
+ internal T Result => IsCompleted ?
+ _result :
+ throw new InvalidOperationException("Asynchronous operation is not yet completed");
+
+ private List _continuations;
+
+ internal void OnCompleted(Action continuation)
+ {
+ if(_continuations==null)
+ _continuations = new List();
+ _continuations.Add(continuation);
+ }
+
+ public void SetResult(T result)
+ {
+ if (IsCompleted)
+ throw new InvalidOperationException("Asynchronous operation is already completed");
+ _result = result;
+ IsCompleted = true;
+ if(_continuations!=null)
+ foreach (var c in _continuations)
+ c();
+ _continuations = null;
+ }
+
+ public void TrySetResult(T result)
+ {
+ if(IsCompleted)
+ return;
+ SetResult(result);
+ }
+ }
+}
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
index c54d8e19a1..0dd52c9b48 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
@@ -75,9 +75,9 @@ namespace Avalonia.Build.Tasks
.First(c => c.Parameters.Count == 1));
var runtimeHelpers = typeSystem.GetType("Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers");
- var rootServiceProviderField = asm.MainModule.ImportReference(
- typeSystem.GetTypeReference(runtimeHelpers).Resolve().Fields
- .First(x => x.Name == "RootServiceProviderV1"));
+ var createRootServiceProviderMethod = asm.MainModule.ImportReference(
+ typeSystem.GetTypeReference(runtimeHelpers).Resolve().Methods
+ .First(x => x.Name == "CreateRootServiceProviderV2"));
var loaderDispatcherDef = new TypeDefinition("CompiledAvaloniaXaml", "!XamlLoader",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
@@ -211,7 +211,7 @@ namespace Avalonia.Build.Tasks
trampoline.Parameters.Add(new ParameterDefinition(classTypeDefinition));
classTypeDefinition.Methods.Add(trampoline);
- var regularStart = Instruction.Create(OpCodes.Ldsfld, rootServiceProviderField);
+ var regularStart = Instruction.Create(OpCodes.Call, createRootServiceProviderMethod);
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, designLoaderField));
trampoline.Body.Instructions.Add(Instruction.Create(OpCodes.Brfalse, regularStart));
@@ -307,7 +307,7 @@ namespace Avalonia.Build.Tasks
i.Add(Instruction.Create(OpCodes.Newobj, parameterlessConstructor));
else
{
- i.Add(Instruction.Create(OpCodes.Ldsfld, rootServiceProviderField));
+ i.Add(Instruction.Create(OpCodes.Call, createRootServiceProviderMethod));
i.Add(Instruction.Create(OpCodes.Call, compiledBuildMethod));
}
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index b87e10d284..473c4fe21b 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -795,7 +795,7 @@ namespace Avalonia.Controls
var template =
new FuncDataTemplate(
typeof(object),
- o =>
+ (o, _) =>
{
var control = new ContentControl();
control.Bind(ContentControl.ContentProperty, value);
diff --git a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
index 83d1c4aae3..2d48a7d33b 100644
--- a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
+++ b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
@@ -8,7 +8,7 @@ using JetBrains.Annotations;
namespace Avalonia.Controls.Embedding
{
- public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, INameScope, IDisposable
+ public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, IDisposable
{
public EmbeddableControlRoot(IEmbeddableWindowImpl impl) : base(impl)
{
@@ -51,25 +51,6 @@ namespace Avalonia.Controls.Embedding
return rv;
}
- private readonly NameScope _nameScope = new NameScope();
- public event EventHandler Registered
- {
- add { _nameScope.Registered += value; }
- remove { _nameScope.Registered -= value; }
- }
-
- public event EventHandler Unregistered
- {
- add { _nameScope.Unregistered += value; }
- remove { _nameScope.Unregistered -= value; }
- }
-
- public void Register(string name, object element) => _nameScope.Register(name, element);
-
- public object Find(string name) => _nameScope.Find(name);
-
- public void Unregister(string name) => _nameScope.Unregister(name);
-
Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
public void Dispose() => PlatformImpl?.Dispose();
}
diff --git a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
index c4f83ffd54..d326ab5734 100644
--- a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
+++ b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
@@ -30,25 +30,6 @@ namespace Avalonia.Controls.Embedding.Offscreen
init.EndInit();
}
}
-
- private readonly NameScope _nameScope = new NameScope();
- public event EventHandler Registered
- {
- add { _nameScope.Registered += value; }
- remove { _nameScope.Registered -= value; }
- }
-
- public event EventHandler Unregistered
- {
- add { _nameScope.Unregistered += value; }
- remove { _nameScope.Unregistered -= value; }
- }
-
- public void Register(string name, object element) => _nameScope.Register(name, element);
-
- public object Find(string name) => _nameScope.Find(name);
-
- public void Unregister(string name) => _nameScope.Unregister(name);
Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
public void Dispose()
diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
index 304c86dbf7..43d1108fb9 100644
--- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
@@ -92,7 +92,6 @@ namespace Avalonia.Controls.Generators
result.DataContext = item;
}
- NameScope.SetNameScope((Control)(object)result, new NameScope());
Index.Add(item, result);
return result;
@@ -123,11 +122,20 @@ namespace Avalonia.Controls.Generators
return false;
}
+ class WrapperTreeDataTemplate : ITreeDataTemplate
+ {
+ private readonly IDataTemplate _inner;
+ public WrapperTreeDataTemplate(IDataTemplate inner) => _inner = inner;
+ public IControl Build(object param) => _inner.Build(param);
+ public bool SupportsRecycling => _inner.SupportsRecycling;
+ public bool Match(object data) => _inner.Match(data);
+ public InstancedBinding ItemsSelector(object item) => null;
+ }
+
private ITreeDataTemplate GetTreeDataTemplate(object item, IDataTemplate primary)
{
var template = Owner.FindDataTemplate(item, primary) ?? FuncDataTemplate.Default;
- var treeTemplate = template as ITreeDataTemplate ??
- new FuncTreeDataTemplate(typeof(object), template.Build, x => null);
+ var treeTemplate = template as ITreeDataTemplate ?? new WrapperTreeDataTemplate(template);
return treeTemplate;
}
}
diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
index 49f268c128..c2690d503d 100644
--- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
@@ -325,12 +325,6 @@ namespace Avalonia.Controls.Presenters
{
_dataTemplate = dataTemplate;
newChild = _dataTemplate.Build(content);
-
- // Give the new control its own name scope.
- if (newChild is Control controlResult)
- {
- NameScope.SetNameScope(controlResult, new NameScope());
- }
}
}
else
diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
index 32e220b789..47c3240374 100644
--- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs
+++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
@@ -257,13 +257,14 @@ 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);
+ var (child, nameScope) = template.Build(this);
ApplyTemplatedParent(child);
- RegisterNames(child, nameScope);
((ISetLogicalParent)child).SetParent(this);
VisualChildren.Add(child);
+
+ // 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 +343,5 @@ namespace Avalonia.Controls.Primitives
}
}
}
-
- ///
- /// Registers each control with its name scope.
- ///
- /// The control.
- /// The name scope.
- private void RegisterNames(IControl control, INameScope nameScope)
- {
- if (control.Name != null)
- {
- nameScope.Register(control.Name, control);
- }
-
- if (control.TemplatedParent == this)
- {
- foreach (IControl child in control.GetLogicalChildren())
- {
- RegisterNames(child, nameScope);
- }
- }
- }
}
}
diff --git a/src/Avalonia.Controls/Templates/FuncControlTemplate.cs b/src/Avalonia.Controls/Templates/FuncControlTemplate.cs
index 4c3c92309e..19458cc6b8 100644
--- a/src/Avalonia.Controls/Templates/FuncControlTemplate.cs
+++ b/src/Avalonia.Controls/Templates/FuncControlTemplate.cs
@@ -16,9 +16,15 @@ namespace Avalonia.Controls.Templates
/// Initializes a new instance of the class.
///
/// The build function.
- public FuncControlTemplate(Func build)
+ public FuncControlTemplate(Func build)
: base(build)
{
}
+
+ public new ControlTemplateResult Build(ITemplatedControl param)
+ {
+ var (control, scope) = BuildWithNameScope(param);
+ return new ControlTemplateResult(control, scope);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs b/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs
index 8e49b51cb8..eec7a6030f 100644
--- a/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs
+++ b/src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs
@@ -17,9 +17,9 @@ namespace Avalonia.Controls.Templates
/// Initializes a new instance of the class.
///
/// The build function.
- public FuncControlTemplate(Func build)
- : base(x => build((T)x))
+ public FuncControlTemplate(Func build)
+ : base((x, s) => build((T)x, s))
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs
index 1d90fcd01e..204540e431 100644
--- a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs
+++ b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs
@@ -17,7 +17,7 @@ namespace Avalonia.Controls.Templates
///
public static readonly FuncDataTemplate Default =
new FuncDataTemplate