@@ -79,6 +79,8 @@ internal partial class XamlFileGenerator
79
79
private readonly Dictionary < string , string [ ] > _uiAutomationMappings ;
80
80
private readonly string _defaultLanguage ;
81
81
private readonly bool _isDebug ;
82
+ private readonly bool _isHotReloadEnabled ;
83
+ private readonly bool _isUnoHead ;
82
84
private readonly bool _isDesignTimeBuild ;
83
85
private readonly string _relativePath ;
84
86
@@ -150,6 +152,8 @@ internal partial class XamlFileGenerator
150
152
private readonly INamedTypeSymbol _dependencyObjectSymbol ;
151
153
private readonly INamedTypeSymbol _markupExtensionSymbol ;
152
154
private readonly INamedTypeSymbol _brushSymbol ;
155
+ private readonly INamedTypeSymbol _imageSourceSymbol ;
156
+ private readonly INamedTypeSymbol _imageSymbol ;
153
157
private readonly INamedTypeSymbol _dependencyObjectParseSymbol ;
154
158
private readonly INamedTypeSymbol ? _androidContentContextSymbol ; // Android.Content.Context
155
159
private readonly INamedTypeSymbol ? _androidViewSymbol ; // Android.Views.View
@@ -207,8 +211,6 @@ internal partial class XamlFileGenerator
207
211
/// </summary>
208
212
private string SingletonClassName => $ "ResourceDictionarySingleton__{ _fileDefinition . UniqueID } ";
209
213
210
- private readonly bool _isHotReloadEnabled ;
211
-
212
214
private const string DictionaryProviderInterfaceName = "global::Uno.UI.IXamlResourceDictionaryProvider" ;
213
215
214
216
static XamlFileGenerator ( )
@@ -237,6 +239,7 @@ public XamlFileGenerator(
237
239
bool isDebug ,
238
240
bool isHotReloadEnabled ,
239
241
bool isDesignTimeBuild ,
242
+ bool isUnoHead ,
240
243
bool skipUserControlsInVisualTree ,
241
244
bool shouldAnnotateGeneratedXaml ,
242
245
bool isUnoAssembly ,
@@ -261,6 +264,7 @@ public XamlFileGenerator(
261
264
_defaultLanguage = defaultLanguage . HasValue ( ) ? defaultLanguage : "en-US" ;
262
265
_isDebug = isDebug ;
263
266
_isHotReloadEnabled = isHotReloadEnabled ;
267
+ _isUnoHead = isUnoHead ;
264
268
_isDesignTimeBuild = isDesignTimeBuild ;
265
269
_skipUserControlsInVisualTree = skipUserControlsInVisualTree ;
266
270
_shouldAnnotateGeneratedXaml = shouldAnnotateGeneratedXaml ;
@@ -281,6 +285,8 @@ public XamlFileGenerator(
281
285
_contentPresenterSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . ContentPresenter ) ;
282
286
_frameworkElementSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . FrameworkElement ) ;
283
287
_uiElementSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . UIElement ) ;
288
+ _imageSourceSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . ImageSource ) ;
289
+ _imageSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . Image ) ;
284
290
_dependencyObjectSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . DependencyObject ) ;
285
291
_markupExtensionSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . MarkupExtension ) ;
286
292
_brushSymbol = ( INamedTypeSymbol ) _metadataHelper . GetTypeByFullName ( XamlConstants . Types . Brush ) ;
@@ -463,6 +469,8 @@ private string InnerGenerateFile()
463
469
464
470
using ( writer . BlockInvariant ( "partial class {0} : {1}" , _xClassName . ClassName , controlBaseType . ToDisplayString ( ) ) )
465
471
{
472
+ BuildBaseUri ( writer ) ;
473
+
466
474
using ( Scope ( _xClassName . Namespace , _xClassName . ClassName ) )
467
475
{
468
476
var componentBuilder = new IndentedStringBuilder ( ) ;
@@ -501,6 +509,19 @@ private string InnerGenerateFile()
501
509
return writer . ToString ( ) ;
502
510
}
503
511
512
+ /// <summary>
513
+ /// Builds the BaseUri strings constants to be set to all FrameworkElement instances
514
+ /// </summary>
515
+ private void BuildBaseUri ( IIndentedStringBuilder writer )
516
+ {
517
+ var assembly = _isUnoHead ? "" : _generatorContext . Compilation . AssemblyName + "/" ;
518
+
519
+ writer . AppendLineIndented ( "[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]" ) ;
520
+ writer . AppendLineInvariantIndented ( $ "private const string __baseUri_prefix_{ _fileUniqueId } = \" ms-appx:///{ assembly } \" ;") ;
521
+ writer . AppendLineIndented ( "[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]" ) ;
522
+ writer . AppendLineInvariantIndented ( $ "private const string __baseUri_{ _fileUniqueId } = \" ms-appx:///{ assembly } { _fileDefinition . TargetFilePath } \" ;") ;
523
+ }
524
+
504
525
private void BuildInitializeComponent ( IndentedStringBuilder writer , XamlObjectDefinition topLevelControl , INamedTypeSymbol controlBaseType , bool isDirectUserControlChild )
505
526
{
506
527
writer . AppendLineIndented ( "global::Windows.UI.Xaml.NameScope __nameScope = new global::Windows.UI.Xaml.NameScope();" ) ;
@@ -989,6 +1010,8 @@ private void BuildChildSubclasses(IIndentedStringBuilder writer, bool isTopLevel
989
1010
990
1011
using ( writer . BlockInvariant ( $ "{ classAccessibility } class { className } ") )
991
1012
{
1013
+ BuildBaseUri ( writer ) ;
1014
+
992
1015
using ( ResourceOwnerScope ( ) )
993
1016
{
994
1017
writer . AppendLineIndented ( "global::Windows.UI.Xaml.NameScope __nameScope = new global::Windows.UI.Xaml.NameScope();" ) ;
@@ -1272,6 +1295,7 @@ private void BuildTopLevelResourceDictionary(IIndentedStringBuilder writer, Xaml
1272
1295
AnalyzerSuppressionsGenerator . Generate ( writer , _analyzerSuppressions ) ;
1273
1296
using ( writer . BlockInvariant ( "public sealed partial class GlobalStaticResources" ) )
1274
1297
{
1298
+ BuildBaseUri ( writer ) ;
1275
1299
1276
1300
IDisposable WrapSingleton ( )
1277
1301
{
@@ -1653,6 +1677,8 @@ private void BuildResourceDictionaryBackingClass(IIndentedStringBuilder writer,
1653
1677
AnalyzerSuppressionsGenerator . Generate ( writer , _analyzerSuppressions ) ;
1654
1678
using ( writer . BlockInvariant ( "public sealed partial class {0} : {1}" , className . ClassName , GetGlobalizedTypeName ( controlBaseType . ToDisplayString ( ) ) ) )
1655
1679
{
1680
+ BuildBaseUri ( writer ) ;
1681
+
1656
1682
using ( Scope ( className . Namespace , className . ClassName ! ) )
1657
1683
{
1658
1684
using ( writer . BlockInvariant ( "public void InitializeComponent()" ) )
@@ -3630,9 +3656,23 @@ private void BuildExtendedProperties(IIndentedStringBuilder outerwriter, XamlObj
3630
3656
writer . AppendLineIndented ( $ ");") ;
3631
3657
}
3632
3658
3633
- if ( _isDebug && IsFrameworkElement ( objectDefinition . Type ) )
3659
+ if ( IsFrameworkElement ( objectDefinition . Type ) )
3634
3660
{
3635
- writer . AppendLineIndented ( $ "global::Uno.UI.FrameworkElementHelper.SetBaseUri({ closureName } , \" file:///{ _fileDefinition . FilePath . Replace ( "\\ " , "/" ) } \" );") ;
3661
+ if ( _isDebug )
3662
+ {
3663
+ writer . AppendLineIndented (
3664
+ $ "global::Uno.UI.FrameworkElementHelper.SetBaseUri(" +
3665
+ $ "{ closureName } , " +
3666
+ $ "__baseUri_{ _fileUniqueId } , " +
3667
+ $ "\" file:///{ _fileDefinition . FilePath . Replace ( "\\ " , "/" ) } \" , " +
3668
+ $ "{ objectDefinition . LineNumber } , " +
3669
+ $ "{ objectDefinition . LinePosition } " +
3670
+ $ ");") ;
3671
+ }
3672
+ else
3673
+ {
3674
+ writer . AppendLineIndented ( $ "global::Uno.UI.FrameworkElementHelper.SetBaseUri({ closureName } , __baseUri_{ _fileUniqueId } );") ;
3675
+ }
3636
3676
}
3637
3677
3638
3678
if ( _isUiAutomationMappingEnabled )
@@ -4893,15 +4933,7 @@ string Inner()
4893
4933
4894
4934
case "System.Uri" :
4895
4935
var uriValue = GetMemberValue ( ) ;
4896
-
4897
- if ( uriValue . StartsWith ( "/" , StringComparison . Ordinal ) )
4898
- {
4899
- return "new System.Uri(\" ms-appx://" + uriValue + "\" )" ;
4900
- }
4901
- else
4902
- {
4903
- return "new System.Uri(\" " + uriValue + "\" , global::System.UriKind.RelativeOrAbsolute)" ;
4904
- }
4936
+ return $ "new System.Uri({ RewriteUri ( uriValue ) } , global::System.UriKind.RelativeOrAbsolute)";
4905
4937
4906
4938
case "System.Type" :
4907
4939
return $ "typeof({ GetGlobalizedTypeName ( GetType ( GetMemberValue ( ) ) . ToDisplayString ( ) ) } )";
@@ -4965,9 +4997,7 @@ string Inner()
4965
4997
return "Windows.Media.Core.MediaSource.CreateFromUri(new Uri(\" " + memberValue + "\" ))" ;
4966
4998
4967
4999
case "Windows.UI.Xaml.Media.ImageSource" :
4968
- // We have an implicit conversion from string to ImageSource.
4969
- //
4970
- return $ "\" { memberValue } \" ";
5000
+ return RewriteUri ( memberValue ) ;
4971
5001
}
4972
5002
4973
5003
var isEnum = propertyType . TypeKind == TypeKind . Enum ;
@@ -5041,9 +5071,55 @@ string Inner()
5041
5071
5042
5072
static string ? SplitAndJoin ( string ? value )
5043
5073
=> value == null ? null : splitRegex . Replace ( value , ", " ) ;
5074
+
5075
+ string RewriteUri ( string ? rawValue )
5076
+ {
5077
+ if ( rawValue is not null
5078
+ && Uri . TryCreate ( rawValue , UriKind . RelativeOrAbsolute , out var parsedUri )
5079
+ && ! parsedUri . IsAbsoluteUri )
5080
+ {
5081
+ var declaringType = FindFirstConcreteAncestorType ( owner ? . Owner ) ;
5082
+
5083
+ if (
5084
+ declaringType . Is ( _imageSourceSymbol )
5085
+ || declaringType . Is ( _imageSymbol )
5086
+ )
5087
+ {
5088
+ var uriBase = rawValue . StartsWith ( "/" , StringComparison . Ordinal )
5089
+ ? "\" ms-appx:///\" "
5090
+ : $ "__baseUri_prefix_{ _fileUniqueId } ";
5091
+
5092
+ return $ "{ uriBase } + \" { rawValue . TrimStart ( '/' ) } \" ";
5093
+ }
5094
+ else
5095
+ {
5096
+ // Breaking change, support for ms-resource:// for non framework owners (https://github.com/unoplatform/uno/issues/8339)
5097
+ }
5098
+ }
5099
+
5100
+ return $ "\" { rawValue } \" ";
5101
+ }
5044
5102
}
5045
5103
}
5046
5104
5105
+ /// <summary>
5106
+ /// Finds the first ancestor type that is resolving to a known type (excluding _unknownContent members)
5107
+ /// </summary>
5108
+ private INamedTypeSymbol ? FindFirstConcreteAncestorType ( XamlObjectDefinition ? objectDefinition )
5109
+ {
5110
+ while ( objectDefinition is not null )
5111
+ {
5112
+ if ( FindType ( objectDefinition . Type ) is { } type )
5113
+ {
5114
+ return type ;
5115
+ }
5116
+
5117
+ objectDefinition = objectDefinition . Owner ;
5118
+ }
5119
+
5120
+ return null ;
5121
+ }
5122
+
5047
5123
private string ? BuildLocalizedResourceValue ( INamedTypeSymbol ? owner , string memberName , string objectUid )
5048
5124
{
5049
5125
// see: https://docs.microsoft.com/en-us/windows/uwp/app-resources/localize-strings-ui-manifest
@@ -5159,7 +5235,7 @@ string Inner()
5159
5235
5160
5236
if ( propertyType != null )
5161
5237
{
5162
- var s = BuildLiteralValue ( propertyType , memberValue , owner , member . Member . Name , objectUid ) ;
5238
+ var s = BuildLiteralValue ( propertyType , memberValue , owner ?? member , member . Member . Name , objectUid ) ;
5163
5239
5164
5240
s += $ "/* { propertyType } /{ originalType } , { memberValue } , { member ? . Member ? . DeclaringType ? . Name } /{ member ? . Member ? . Name } */";
5165
5241
0 commit comments