diff --git a/src/Avalonia.Base/Data/Core/BindingExpression.cs b/src/Avalonia.Base/Data/Core/BindingExpression.cs index 22be30b4b3..1203b3d0e3 100644 --- a/src/Avalonia.Base/Data/Core/BindingExpression.cs +++ b/src/Avalonia.Base/Data/Core/BindingExpression.cs @@ -205,8 +205,8 @@ internal partial class BindingExpression : UntypedBindingExpressionBase, IDescri ConvertAndPublishValue(value, error); } - // If the binding mode is OneTime, then stop the binding. - if (_mode == BindingMode.OneTime) + // If the binding mode is OneTime, then stop the binding if a valid value was published. + if (_mode == BindingMode.OneTime && GetValue() != AvaloniaProperty.UnsetValue) Stop(); } else if (_mode == BindingMode.OneWayToSource && nodeIndex == _nodes.Count - 2 && value is not null) diff --git a/tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests_Mode.cs b/tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests_Mode.cs index 972cd71b43..42b3583051 100644 --- a/tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests_Mode.cs +++ b/tests/Avalonia.Base.UnitTests/Data/Core/BindingExpressionTests_Mode.cs @@ -58,6 +58,24 @@ namespace Avalonia.Base.UnitTests.Data.Core Assert.Equal("foo", target.Tag); } + [Fact] + public void OneTime_Binding_Waits_For_DataContext_With_Matching_Property_Type() + { + var data1 = new { Bar = new object() }; + var data2 = new ViewModel(); + var binding = new Binding(nameof(data2.Bar), BindingMode.OneTime); + var target = new Control { DataContext = data1 }; + + target.Bind(Control.OpacityProperty, binding); + Assert.Equal(1, target.Opacity); + + target.DataContext = data2; + Assert.Equal(0.5, target.Opacity); + + data2.Bar = 0.2; + Assert.Equal(0.5, target.Opacity); + } + private class ViewModel : NotifyingBase { private string _foo;