diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems index b6b447e1640c..dc822501cdf3 100644 --- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems +++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems @@ -97,6 +97,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -2107,6 +2111,7 @@ Localization_Implicit.xaml + @@ -3705,6 +3710,9 @@ XamlGlobalResources.xaml + + XamlLocalResources.xaml + diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/Resources/XamlLocalResources.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/Resources/XamlLocalResources.xaml new file mode 100644 index 000000000000..c6c2709a6b8a --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/Resources/XamlLocalResources.xaml @@ -0,0 +1,19 @@ + + + + + Blue + + + + + diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/Resources/XamlLocalResources.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/Resources/XamlLocalResources.xaml.cs new file mode 100644 index 000000000000..982d6b2ff6a6 --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml/Resources/XamlLocalResources.xaml.cs @@ -0,0 +1,18 @@ +using Windows.UI.Xaml.Controls; +using Uno.UI.Samples.Controls; + +namespace UITests.Shared.Windows_UI_Xaml.Resources +{ + public sealed partial class XamlLocalResources : Page + { + public XamlLocalResources() + { + this.InitializeComponent(); + } + } + + internal class CustomTemplateSelector : DataTemplateSelector + { + + } +} diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs index 7877f2397732..dc4427becebc 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs @@ -4,6 +4,7 @@ using Uno.UI.SourceGenerators.XamlGenerator.Utils; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -73,6 +74,7 @@ internal partial class XamlFileGenerator private readonly INamedTypeSymbol _stringSymbol; private readonly INamedTypeSymbol _objectSymbol; private readonly INamedTypeSymbol _iFrameworkElementSymbol; + private readonly INamedTypeSymbol _dependencyObjectSymbol; private readonly INamedTypeSymbol _iCollectionSymbol; private readonly INamedTypeSymbol _iCollectionOfTSymbol; @@ -80,6 +82,7 @@ internal partial class XamlFileGenerator private readonly INamedTypeSymbol _iListOfTSymbol; private readonly INamedTypeSymbol _iDictionaryOfTKeySymbol; private readonly INamedTypeSymbol _dataBindingSymbol; + private readonly INamedTypeSymbol _styleSymbol; private readonly bool _isWasm; @@ -130,12 +133,14 @@ bool isDebug _elementStubSymbol = GetType(XamlConstants.Types.ElementStub); _contentPresenterSymbol = GetType(XamlConstants.Types.ContentPresenter); _iFrameworkElementSymbol = GetType(XamlConstants.Types.IFrameworkElement); + _dependencyObjectSymbol = GetType(XamlConstants.Types.DependencyObject); _iCollectionSymbol = GetType("System.Collections.ICollection"); _iCollectionOfTSymbol = GetType("System.Collections.Generic.ICollection`1"); _iListSymbol = GetType("System.Collections.IList"); _iListOfTSymbol = GetType("System.Collections.Generic.IList`1"); _iDictionaryOfTKeySymbol = GetType("System.Collections.Generic.IDictionary`2"); _dataBindingSymbol = GetType("Windows.UI.Xaml.Data.Binding"); + _styleSymbol = GetType(XamlConstants.Types.Style); _isWasm = isWasm; } @@ -855,20 +860,39 @@ IEnumerable> namedResources writer.AppendLineInvariant(0, ";", namedResource.Value.Type); } - // Styles are handled differently for now, and there's no variable generated - // for those entries. Skip the ApplyCompiledBindings for those. See - // ImportResourceDictionary handling of x:Name for more details. - var namedResourcesExcludingStyles = namedResources - .Where(nr => nr.Value.Type.Name.Equals("Style", StringComparison.Ordinal)) + bool IsGenerateCompiledBindings(KeyValuePair nr) + { + var type = GetType(nr.Value.Type); + + // Styles are handled differently for now, and there's no variable generated + // for those entries. Skip the ApplyCompiledBindings for those. See + // ImportResourceDictionary handling of x:Name for more details. + if (type.Equals(_styleSymbol)) + { + return false; + } + + if (type.AllInterfaces.Any(i => i.Equals(_dependencyObjectSymbol))) + { + return true; + } + + return false; + } + + var resourcesTogenerateApplyCompiledBindings = namedResources + .Where(IsGenerateCompiledBindings) .ToArray(); - if (namedResourcesExcludingStyles.Any()) + if (resourcesTogenerateApplyCompiledBindings.Any()) { using (writer.BlockInvariant("Loading += (s, e) =>")) { - foreach (var namedResource in namedResourcesExcludingStyles) + foreach (var namedResource in resourcesTogenerateApplyCompiledBindings) { - writer.AppendFormatInvariant($"{namedResource.Key}.ApplyCompiledBindings();"); + var type = GetType(namedResource.Value.Type); + + writer.AppendLineInvariant($"{namedResource.Key}.ApplyCompiledBindings();"); } } writer.AppendLineInvariant(0, ";"); @@ -962,7 +986,7 @@ IEnumerable> keyedResources } else { - // If there is no method suffix, + // If there is no method suffix, using (writer.BlockInvariant("public static object FindResource(string name)")) { BuildGetResources(writer, keyedResources); @@ -1678,7 +1702,7 @@ private void RegisterResources(XamlObjectDefinition topLevelControl) if (isExplicitResDictionary) { - // To be able to have MergedDictionaries, the first node of the Resource node + // To be able to have MergedDictionaries, the first node of the Resource node // must be an explicit resource dictionary. resourcesMember = FindImplicitContentMember(resourcesMember.Objects.First()); @@ -1731,8 +1755,8 @@ private void TryExtractAutomationId(XamlMemberDefinition member, string[] target var fullMemberName = $"{FindType(member.Member.DeclaringType)?.GetFullMetadataName()}.{member.Member.Name}"; - // Try to match each potential candidate by comparing based only on the name of the member first. - // If that fails, try matching based on the full metadata name of the member + // Try to match each potential candidate by comparing based only on the name of the member first. + // If that fails, try matching based on the full metadata name of the member var hasUiAutomationMapping = targetMembers .Any(candidateMember => (!candidateMember.Contains(".") && candidateMember == member.Member.Name) || @@ -1752,7 +1776,7 @@ private void TryExtractAutomationId(XamlMemberDefinition member, string[] target string bindingPath; - // Checks the first binding member, which can be used to implicitlty declare the binding path (i.e. without + // Checks the first binding member, which can be used to implicitlty declare the binding path (i.e. without // declaring a "Path=" specifier). Otherwise, the we look for any explicit binding path declaration. var firstBindingMember = bindingMembers?.FirstOrDefault(); if (firstBindingMember != null && @@ -2162,7 +2186,7 @@ private void TryValidateContentPresenterBinding(IIndentedStringBuilder writer, X var hasRelativeSource = binding.Members .Any(m => m.Member.Name == "RelativeSource" - // It can either be TemplatedParent or Self. In either cases, it does not use the inherited + // It can either be TemplatedParent or Self. In either cases, it does not use the inherited // DataContext, which falls outside of the scenario we want to avoid. ); @@ -2229,9 +2253,9 @@ private XamlLazyApplyBlockIIndentedStringBuilder CreateApplyBlock(IIndentedStrin closureName = "c" + (_applyIndex++).ToString(CultureInfo.InvariantCulture); // - // Since we're using strings to generate the code, we can't know ahead of time if + // Since we're using strings to generate the code, we can't know ahead of time if // content will be generated only by looking at the Xaml object model. - // For now, we only observe if the inner code has generated code, and we create + // For now, we only observe if the inner code has generated code, and we create // the apply block at that time. // string delegateType = null; @@ -2604,7 +2628,7 @@ private string BuildLiteralValue(INamedTypeSymbol propertyType, string memberVal throw new Exception("Unable to convert {0} for {1} with type {2}".InvariantCultureFormat(memberValue, memberName, propertyType)); } - + private string BuildLocalizedResourceValue(XamlMemberDefinition owner, string memberName, string objectUid) { var uidParts = objectUid.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); @@ -3028,7 +3052,7 @@ private void BuildLiteralProperties(IIndentedStringBuilder writer, XamlObjectDef } else if (member.Member.DeclaringType == null && member.Member.Name == "Name") { - // This is a special case, where the declaring type is from the x: namespace, + // This is a special case, where the declaring type is from the x: namespace, // but is considered of an unknown type. This can happen when providing the // name of a control using x:Name instead of Name. var hasNameProperty = HasProperty(objectDefinition.Type, "Name"); @@ -3195,7 +3219,7 @@ private void BuildChild(IIndentedStringBuilder writer, XamlMemberDefinition owne if (contentOwner != null) { - // This case is to support the layout switching for the ListViewBaseLayout, which is not + // This case is to support the layout switching for the ListViewBaseLayout, which is not // a FrameworkTemplate. Thsi will need to be removed when this custom list view is removed. var returnType = typeName == "ListViewBaseLayoutTemplate" ? "Uno.UI.Controls.Legacy.ListViewBaseLayout" : "_View"; @@ -3294,7 +3318,7 @@ private void BuildChild(IIndentedStringBuilder writer, XamlMemberDefinition owne } } - // Attached properties need to be expanded using the namespace, otherwise the resolution will be + // Attached properties need to be expanded using the namespace, otherwise the resolution will be // performed at runtime at a higher cost. propertyName = RewriteAttachedPropertyPath(propertyName); diff --git a/src/Uno.UI/UI/Xaml/DependencyObjectExtensions.cs b/src/Uno.UI/UI/Xaml/DependencyObjectExtensions.cs index 2d798123a152..59280b83de53 100644 --- a/src/Uno.UI/UI/Xaml/DependencyObjectExtensions.cs +++ b/src/Uno.UI/UI/Xaml/DependencyObjectExtensions.cs @@ -292,7 +292,7 @@ internal static IDisposable RegisterDisposableNestedPropertyChangedCallback(this /// Register for changes all dependency properties changes notifications for the specified instance. /// /// The instance for which to observe properties changes - /// The callback + /// The callback /// A disposable that will unregister the callback when disposed. internal static IDisposable RegisterInheritedPropertyChangedCallback(this object instance, ExplicitPropertyChangedCallback handler) { @@ -300,10 +300,10 @@ internal static IDisposable RegisterInheritedPropertyChangedCallback(this object } /// - /// Register for compiled bindinds updates progapation + /// Register for compiled bindings updates propagation /// /// The instance for which to observe compiled bindings updates - /// The callback + /// The callback /// A disposable that will unregister the callback when disposed. internal static IDisposable RegisterCompiledBindingsUpdateCallback(this object instance, Action handler) => GetStore(instance).RegisterCompiledBindingsUpdateCallback(handler); @@ -312,8 +312,8 @@ internal static IDisposable RegisterCompiledBindingsUpdateCallback(this object i /// Registers to parent changes. /// /// The target dependency object - /// A key to be passed to the callack parameter. - /// A callback to be called + /// A key to be passed to the callback parameter. + /// A callback to be called /// A disposable that cancels the subscription. internal static IDisposable RegisterParentChangedCallback(this DependencyObject instance, object key, ParentChangedCallback handler) {