diff --git a/src/Avalonia.Themes.Fluent/Accents/Base.xaml b/src/Avalonia.Themes.Fluent/Accents/Base.xaml index 9cf2824c06..8358297f8b 100644 --- a/src/Avalonia.Themes.Fluent/Accents/Base.xaml +++ b/src/Avalonia.Themes.Fluent/Accents/Base.xaml @@ -12,8 +12,8 @@ #FF0066CC #FFFFFFFF #FF000000 - avares://Avalonia.Themes.Fluent/Assets#Lato - 13 + avares://Avalonia.Themes.Fluent/Assets#Roboto + 14 True diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Black.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Black.ttf deleted file mode 100644 index e2aeb6cc35..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Black.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Bold.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Bold.ttf deleted file mode 100644 index ef5ae3b43e..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Bold.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Hairline.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Hairline.ttf deleted file mode 100644 index 4c5a8fdd99..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Hairline.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Heavy.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Heavy.ttf deleted file mode 100644 index fc70ab7c35..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Heavy.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Italic.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Italic.ttf deleted file mode 100644 index b23256ff53..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Italic.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Light.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Light.ttf deleted file mode 100644 index 0809b8e6b5..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Light.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Medium.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Medium.ttf deleted file mode 100644 index 2c612da2ae..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Medium.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Regular.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Regular.ttf deleted file mode 100644 index adbfc467d2..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Regular.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Semibold.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Semibold.ttf deleted file mode 100644 index 60ac82d65b..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Semibold.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Lato-Thin.ttf b/src/Avalonia.Themes.Fluent/Assets/Lato-Thin.ttf deleted file mode 100644 index 0f84dc1b19..0000000000 Binary files a/src/Avalonia.Themes.Fluent/Assets/Lato-Thin.ttf and /dev/null differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Black.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Black.ttf new file mode 100644 index 0000000000..38f809991d Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Roboto-Black.ttf differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Bold.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Bold.ttf new file mode 100644 index 0000000000..5fd9dd9eed Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Roboto-Bold.ttf differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Light.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Light.ttf new file mode 100644 index 0000000000..113d545eea Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Roboto-Light.ttf differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Medium.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Medium.ttf new file mode 100644 index 0000000000..98c4538462 Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Roboto-Medium.ttf differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Regular.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Regular.ttf new file mode 100644 index 0000000000..c1c3700fe5 Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Roboto-Regular.ttf differ diff --git a/src/Avalonia.Themes.Fluent/Assets/Roboto-Thin.ttf b/src/Avalonia.Themes.Fluent/Assets/Roboto-Thin.ttf new file mode 100644 index 0000000000..04b15402d9 Binary files /dev/null and b/src/Avalonia.Themes.Fluent/Assets/Roboto-Thin.ttf differ diff --git a/src/Avalonia.Themes.Fluent/Button.xaml b/src/Avalonia.Themes.Fluent/Button.xaml index 561b84521d..34bcd0f0c1 100644 --- a/src/Avalonia.Themes.Fluent/Button.xaml +++ b/src/Avalonia.Themes.Fluent/Button.xaml @@ -81,7 +81,7 @@ - + diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs index 1f527e9569..03ec32b9cf 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlBindingPathHelper.cs @@ -121,7 +121,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } else { - var clrProperty = targetType.GetAllProperties().FirstOrDefault(p => p.Name == propName.PropertyName); + var clrProperty = GetAllDefinedProperties(targetType).FirstOrDefault(p => p.Name == propName.PropertyName); if (clrProperty is null) { @@ -139,15 +139,15 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions } IXamlProperty property = null; - for (var currentType = targetType; currentType != null; currentType = currentType.BaseType) + foreach (var currentType in TraverseTypeHierarchy(targetType)) { var defaultMemberAttribute = currentType.CustomAttributes.FirstOrDefault(x => x.Type.Namespace == "System.Reflection" && x.Type.Name == "DefaultMemberAttribute"); if (defaultMemberAttribute != null) { - property = targetType.GetAllProperties().FirstOrDefault(x => x.Name == (string)defaultMemberAttribute.Parameters[0]); + property = currentType.GetAllProperties().FirstOrDefault(x => x.Name == (string)defaultMemberAttribute.Parameters[0]); break; } - }; + } if (property is null) { throw new XamlX.XamlParseException($"The type '${targetType}' does not have an indexer.", lineInfo); @@ -252,6 +252,39 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false, lineInfo, true).GetClrType(); } + + static IEnumerable GetAllDefinedProperties(IXamlType type) + { + foreach (var t in TraverseTypeHierarchy(type)) + { + foreach (var p in t.Properties) + { + yield return p; + } + } + } + + static IEnumerable TraverseTypeHierarchy(IXamlType type) + { + if (type.IsInterface) + { + yield return type; + foreach (var iface in type.Interfaces) + { + foreach (var h in TraverseTypeHierarchy(iface)) + { + yield return h; + } + } + } + else + { + for (var currentType = type; currentType != null; currentType = currentType.BaseType) + { + yield return currentType; + } + } + } } class ScopeRegistrationFinder : IXamlAstVisitor diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index 37aa123cfc..4e574f2b9e 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -43,6 +43,33 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } } + [Fact] + public void ResolvesClrPropertyBasedOnDataContextType_InterfaceInheritance() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var textBlock = window.FindControl("textBlock"); + + var dataContext = new TestDataContext + { + StringProperty = "foobar" + }; + + window.DataContext = dataContext; + + Assert.Equal(dataContext.StringProperty, textBlock.Text); + } + } + [Fact] public void ResolvesPathPassedByProperty() { @@ -274,6 +301,36 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } } + [Fact] + public void ResolvesNonIntegerIndexerBindingFromParentInterfaceCorrectly() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var textBlock = window.FindControl("textBlock"); + + var dataContext = new TestDataContext(); + + dataContext.NonIntegerIndexerInterfaceProperty["Test"] = "Initial Value"; + + window.DataContext = dataContext; + + Assert.Equal(dataContext.NonIntegerIndexerInterfaceProperty["Test"], textBlock.Text); + + dataContext.NonIntegerIndexerInterfaceProperty["Test"] = "New Value"; + + Assert.Equal(dataContext.NonIntegerIndexerInterfaceProperty["Test"], textBlock.Text); + } + } + [Fact] public void InfersDataTemplateTypeFromDataTypeProperty() { @@ -584,7 +641,23 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions } } - public class TestDataContext + public interface INonIntegerIndexer + { + string this[string key] {get; set;} + } + + public interface INonIntegerIndexerDerived : INonIntegerIndexer + {} + + public interface IHasProperty + { + string StringProperty {get; set; } + } + + public interface IHasPropertyDerived : IHasProperty + {} + + public class TestDataContext : IHasPropertyDerived { public string StringProperty { get; set; } @@ -600,7 +673,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions public NonIntegerIndexer NonIntegerIndexerProperty { get; set; } = new NonIntegerIndexer(); - public class NonIntegerIndexer : NotifyingBase + public INonIntegerIndexerDerived NonIntegerIndexerInterfaceProperty => NonIntegerIndexerProperty; + + public class NonIntegerIndexer : NotifyingBase, INonIntegerIndexerDerived { private readonly Dictionary _storage = new Dictionary();