diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index d7db04f369..f8440aac47 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -289,12 +289,12 @@ namespace Avalonia.Controls.Primitives
///
public override void EndInit()
{
- base.EndInit();
-
if (--_updateCount == 0)
{
UpdateFinished();
}
+
+ base.EndInit();
}
///
diff --git a/src/Avalonia.Visuals/Rendering/RenderLoop.cs b/src/Avalonia.Visuals/Rendering/RenderLoop.cs
index d0d5b2250d..df32d9eec1 100644
--- a/src/Avalonia.Visuals/Rendering/RenderLoop.cs
+++ b/src/Avalonia.Visuals/Rendering/RenderLoop.cs
@@ -19,7 +19,8 @@ namespace Avalonia.Rendering
private readonly IDispatcher _dispatcher;
private List _items = new List();
private IRenderTimer _timer;
- private int inTick;
+ private int _inTick;
+ private int _inUpdate;
///
/// Initializes a new instance of the class.
@@ -84,21 +85,36 @@ namespace Avalonia.Rendering
}
}
- private async void TimerTick(TimeSpan time)
+ private void TimerTick(TimeSpan time)
{
- if (Interlocked.CompareExchange(ref inTick, 1, 0) == 0)
+ if (Interlocked.CompareExchange(ref _inTick, 1, 0) == 0)
{
try
{
- if (_items.Any(item => item.NeedsUpdate))
+ if (_items.Any(item => item.NeedsUpdate) &&
+ Interlocked.CompareExchange(ref _inUpdate, 1, 0) == 0)
{
- await _dispatcher.InvokeAsync(() =>
+ _dispatcher.Post(() =>
{
- foreach (var i in _items)
+ for (var i = 0; i < _items.Count; ++i)
{
- i.Update(time);
+ var item = _items[i];
+
+ if (item.NeedsUpdate)
+ {
+ try
+ {
+ item.Update(time);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(LogArea.Visual, this, "Exception in render update: {Error}", ex);
+ }
+ }
}
- }, DispatcherPriority.Render).ConfigureAwait(false);
+
+ Interlocked.Exchange(ref _inUpdate, 0);
+ }, DispatcherPriority.Render);
}
foreach (var i in _items)
@@ -112,7 +128,7 @@ namespace Avalonia.Rendering
}
finally
{
- Interlocked.Exchange(ref inTick, 0);
+ Interlocked.Exchange(ref _inTick, 0);
}
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
index 14e1b15ebc..bbe1d85acb 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
@@ -707,6 +707,26 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.True(target.SelectedIndex == 1);
}
+ [Fact]
+ public void Binding_With_DelayedBinding_And_Initialization_Where_DataContext_Is_Root_Works()
+ {
+ // Test for #1932.
+ var root = new RootWithItems();
+
+ root.BeginInit();
+ root.DataContext = root;
+
+ var target = new ListBox();
+ target.BeginInit();
+ root.Child = target;
+
+ DelayedBinding.Add(target, ItemsControl.ItemsProperty, new Binding(nameof(RootWithItems.Items)));
+ DelayedBinding.Add(target, ListBox.SelectedItemProperty, new Binding(nameof(RootWithItems.Selected)));
+ target.EndInit();
+ root.EndInit();
+
+ Assert.Equal("b", target.SelectedItem);
+ }
private FuncControlTemplate Template()
{
@@ -745,5 +765,11 @@ namespace Avalonia.Controls.UnitTests.Primitives
public IList- Items { get; set; }
public Item SelectedItem { get; set; }
}
+
+ private class RootWithItems : TestRoot
+ {
+ public List Items { get; set; } = new List() { "a", "b", "c", "d", "e" };
+ public string Selected { get; set; } = "b";
+ }
}
}
diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs
index 16c2d3ee18..e9aefc46e6 100644
--- a/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Rendering/RenderLoopTests.cs
@@ -19,14 +19,13 @@ namespace Avalonia.Visuals.UnitTests.Rendering
bool inDispatcher = false;
dispatcher.Setup(
- d => d.InvokeAsync(It.IsAny(), DispatcherPriority.Render))
+ d => d.Post(It.IsAny(), DispatcherPriority.Render))
.Callback((Action a, DispatcherPriority _) =>
{
inDispatcher = true;
a();
inDispatcher = false;
- })
- .Returns(Task.CompletedTask);
+ });
var timer = new Mock();
@@ -71,14 +70,13 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var dispatcher = new Mock();
bool inDispatcher = false;
dispatcher.Setup(
- d => d.InvokeAsync(It.IsAny(), DispatcherPriority.Render))
+ d => d.Post(It.IsAny(), DispatcherPriority.Render))
.Callback((Action a, DispatcherPriority _) =>
{
inDispatcher = true;
a();
inDispatcher = false;
- })
- .Returns(Task.CompletedTask);
+ });
var timer = new Mock();
var loop = new RenderLoop(timer.Object, dispatcher.Object);
@@ -100,9 +98,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
{
var dispatcher = new Mock();
dispatcher.Setup(
- d => d.InvokeAsync(It.IsAny(), DispatcherPriority.Render))
- .Callback((Action a, DispatcherPriority _) => a())
- .Returns(Task.CompletedTask);
+ d => d.Post(It.IsAny(), DispatcherPriority.Render))
+ .Callback((Action a, DispatcherPriority _) => a());
var timer = new Mock();
var loop = new RenderLoop(timer.Object, dispatcher.Object);