diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 0e2f0feada..94558c4367 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -208,20 +208,9 @@ namespace Avalonia
{
return ((IDirectPropertyAccessor)GetRegistered(property)).GetValue(this);
}
- else if (_values != null)
- {
- var result = Values.GetValue(property);
-
- if (result == AvaloniaProperty.UnsetValue)
- {
- result = GetDefaultValue(property);
- }
-
- return result;
- }
else
{
- return GetDefaultValue(property);
+ return GetValueOrDefaultUnchecked(property);
}
}
@@ -598,10 +587,46 @@ namespace Avalonia
private object GetDefaultValue(AvaloniaProperty property)
{
if (property.Inherits && InheritanceParent is AvaloniaObject aobj)
- return aobj.GetValue(property);
+ return aobj.GetValueOrDefaultUnchecked(property);
return ((IStyledPropertyAccessor) property).GetDefaultValue(GetType());
}
+ ///
+ /// Gets the value or default value for a property.
+ ///
+ /// The property.
+ /// The default value.
+ private object GetValueOrDefaultUnchecked(AvaloniaProperty property)
+ {
+ var aobj = this;
+ var valuestore = aobj._values;
+ if (valuestore != null)
+ {
+ var result = valuestore.GetValue(property);
+ if (result != AvaloniaProperty.UnsetValue)
+ {
+ return result;
+ }
+ }
+ if (property.Inherits)
+ {
+ while (aobj.InheritanceParent is AvaloniaObject parent)
+ {
+ aobj = parent;
+ valuestore = aobj._values;
+ if (valuestore != null)
+ {
+ var result = valuestore.GetValue(property);
+ if (result != AvaloniaProperty.UnsetValue)
+ {
+ return result;
+ }
+ }
+ }
+ }
+ return ((IStyledPropertyAccessor)property).GetDefaultValue(GetType());
+ }
+
///
/// Sets the value of a direct property.
///
diff --git a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml
index eaa267ba66..7b6870fec3 100644
--- a/src/Avalonia.Controls.DataGrid/Themes/Default.xaml
+++ b/src/Avalonia.Controls.DataGrid/Themes/Default.xaml
@@ -217,12 +217,12 @@
-
+
-
+
diff --git a/src/Avalonia.Input/Gestures.cs b/src/Avalonia.Input/Gestures.cs
index bb8c8b8c40..ea4892ebfc 100644
--- a/src/Avalonia.Input/Gestures.cs
+++ b/src/Avalonia.Input/Gestures.cs
@@ -31,7 +31,7 @@ namespace Avalonia.Input
RoutedEvent.Register(
"ScrollGestureEnded", RoutingStrategies.Bubble, typeof(Gestures));
- private static WeakReference s_lastPress;
+ private static WeakReference s_lastPress = new WeakReference(null);
static Gestures()
{
diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs
index 19f92149ec..29945e25c3 100644
--- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs
+++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs
@@ -76,7 +76,12 @@ namespace Avalonia.Data
}
var children = Bindings.Select(x => x.Initiate(target, null));
- var input = children.Select(x => x.Observable).CombineLatest().Select(x => ConvertValue(x, targetType, converter));
+
+ var input = children.Select(x => x.Observable)
+ .CombineLatest()
+ .Select(x => ConvertValue(x, targetType, converter))
+ .Where(x => x != BindingOperations.DoNothing);
+
var mode = Mode == BindingMode.Default ?
targetProperty?.GetMetadata(target.GetType()).DefaultBindingMode : Mode;
@@ -97,11 +102,6 @@ namespace Avalonia.Data
var culture = CultureInfo.CurrentCulture;
var converted = converter.Convert(values, targetType, ConverterParameter, culture);
- if (converted == BindingOperations.DoNothing)
- {
- return converted;
- }
-
if (converted == AvaloniaProperty.UnsetValue)
{
converted = FallbackValue;
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Converters/MultiValueConverterTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Converters/MultiValueConverterTests.cs
new file mode 100644
index 0000000000..a77723afe1
--- /dev/null
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Converters/MultiValueConverterTests.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Data.Converters;
+using Avalonia.UnitTests;
+using Xunit;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Converters
+{
+ public class MultiValueConverterTests : XamlTestBase
+ {
+ [Fact]
+ public void MultiValueConverter_Special_Values_Work()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+
+
+
+
+
+
+
+";
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var textBlock = window.FindControl("textBlock");
+
+ window.ApplyTemplate();
+
+ window.DataContext = Tuple.Create(2, 2);
+ Assert.Equal("foo", textBlock.Text);
+
+ window.DataContext = Tuple.Create(-3, 3);
+ Assert.Equal("foo", textBlock.Text);
+
+ window.DataContext = Tuple.Create(0, 2);
+ Assert.Equal("bar", textBlock.Text);
+ }
+ }
+ }
+
+ public class TestMultiValueConverter : IMultiValueConverter
+ {
+ public static readonly TestMultiValueConverter Instance = new TestMultiValueConverter();
+
+ public object Convert(IList