Browse Source

Use `avares://` scheme with proper relative uri handling

pull/2104/head
Nikita Tsukanov 8 years ago
parent
commit
b092c51a55
  1. 4
      samples/ControlCatalog/App.xaml
  2. 2
      samples/ControlCatalog/MainWindow.xaml
  3. 8
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  4. 2
      src/Avalonia.DesignerSupport/DesignWindowLoader.cs
  5. 4
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  6. 52
      src/Shared/PlatformSupport/AssetLoader.cs
  7. 1
      src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs

4
samples/ControlCatalog/App.xaml

@ -2,8 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.App"> x:Class="ControlCatalog.App">
<Application.Styles> <Application.Styles>
<StyleInclude Source="res:asm:Avalonia.Themes.Default/DefaultTheme.xaml"/> <StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="res:asm:Avalonia.Themes.Default/Accents/BaseLight.xaml"/> <StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
<Style Selector="TextBlock.h1"> <Style Selector="TextBlock.h1">
<Setter Property="FontSize" Value="{DynamicResource FontSizeLarge}"/> <Setter Property="FontSize" Value="{DynamicResource FontSizeLarge}"/>
<Setter Property="FontWeight" Value="Medium"/> <Setter Property="FontWeight" Value="Medium"/>

2
samples/ControlCatalog/MainWindow.xaml

@ -1,6 +1,6 @@
<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300" <Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
Title="Avalonia Control Gallery" Title="Avalonia Control Gallery"
Icon="/Assets/test_icon.ico?assembly=ControlCatalog" Icon="/Assets/test_icon.ico"
xmlns:local="clr-namespace:ControlCatalog" xmlns:local="clr-namespace:ControlCatalog"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.MainWindow"> x:Class="ControlCatalog.MainWindow">

8
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -44,10 +44,10 @@
<StackPanel Orientation="Vertical" Spacing="8"> <StackPanel Orientation="Vertical" Spacing="8">
<TextBlock Classes="h2">res fonts</TextBlock> <TextBlock Classes="h2">res fonts</TextBlock>
<TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="res:asm:ControlCatalog/Assets/Fonts#Source Sans Pro"/> <TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="res:asm:ControlCatalog/Assets/Fonts#Source Sans Pro"/> <TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="res:asm:ControlCatalog/Assets/Fonts/SourceSansPro-Italic.ttf#Source Sans Pro"/> <TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="avares://ControlCatalog/Assets/Fonts/SourceSansPro-Italic.ttf#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="res:asm:ControlCatalog/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/> <TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="avares://ControlCatalog/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>

2
src/Avalonia.DesignerSupport/DesignWindowLoader.cs

@ -30,7 +30,7 @@ namespace Avalonia.DesignerSupport
xamlFileProjectPath = "/Designer/Fake.xaml"; xamlFileProjectPath = "/Designer/Fake.xaml";
//Fabricate fake Uri //Fabricate fake Uri
baseUri = baseUri =
new Uri($"res:asm:{Path.GetFileNameWithoutExtension(assemblyPath)}{xamlFileProjectPath}"); new Uri($"avares://{Path.GetFileNameWithoutExtension(assemblyPath)}{xamlFileProjectPath}");
} }
var localAsm = assemblyPath != null ? Assembly.LoadFile(Path.GetFullPath(assemblyPath)) : null; var localAsm = assemblyPath != null ? Assembly.LoadFile(Path.GetFullPath(assemblyPath)) : null;

4
src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs

@ -231,7 +231,7 @@ namespace Avalonia.Markup.Xaml
private static IEnumerable<Uri> GetUrisFor(IAssetLoader assetLocator, Type type) private static IEnumerable<Uri> GetUrisFor(IAssetLoader assetLocator, Type type)
{ {
var asm = type.GetTypeInfo().Assembly.GetName().Name; var asm = type.GetTypeInfo().Assembly.GetName().Name;
var xamlInfoUri = new Uri($"res:asm:{asm}/!AvaloniaResourceXamlInfo"); var xamlInfoUri = new Uri($"avares://{asm}/!AvaloniaResourceXamlInfo");
var typeName = type.FullName; var typeName = type.FullName;
if (typeName == null) if (typeName == null)
throw new ArgumentException("Type doesn't have a FullName"); throw new ArgumentException("Type doesn't have a FullName");
@ -243,7 +243,7 @@ namespace Avalonia.Markup.Xaml
var xamlInfo = (AvaloniaResourceXamlInfo)s_xamlInfoSerializer.ReadObject(xamlInfoStream); var xamlInfo = (AvaloniaResourceXamlInfo)s_xamlInfoSerializer.ReadObject(xamlInfoStream);
if (xamlInfo.ClassToResourcePathIndex.TryGetValue(typeName, out var rv) == true) if (xamlInfo.ClassToResourcePathIndex.TryGetValue(typeName, out var rv) == true)
{ {
yield return new Uri($"res:asm:{asm}{rv}"); yield return new Uri($"avares://{asm}{rv}");
yield break; yield break;
} }
} }

52
src/Shared/PlatformSupport/AssetLoader.cs

@ -20,20 +20,20 @@ namespace Avalonia.Shared.PlatformSupport
private static readonly Dictionary<string, AssemblyDescriptor> AssemblyNameCache private static readonly Dictionary<string, AssemblyDescriptor> AssemblyNameCache
= new Dictionary<string, AssemblyDescriptor>(); = new Dictionary<string, AssemblyDescriptor>();
private AssemblyDescriptor _defaultAssembly; private AssemblyDescriptor _defaultResmAssembly;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AssetLoader"/> class. /// Initializes a new instance of the <see cref="AssetLoader"/> class.
/// </summary> /// </summary>
/// <param name="assembly"> /// <param name="assembly">
/// The default assembly from which to load assets for which no assembly is specified. /// The default assembly from which to load resm: assets for which no assembly is specified.
/// </param> /// </param>
public AssetLoader(Assembly assembly = null) public AssetLoader(Assembly assembly = null)
{ {
if (assembly == null) if (assembly == null)
assembly = Assembly.GetEntryAssembly(); assembly = Assembly.GetEntryAssembly();
if (assembly != null) if (assembly != null)
_defaultAssembly = new AssemblyDescriptor(assembly); _defaultResmAssembly = new AssemblyDescriptor(assembly);
} }
/// <summary> /// <summary>
@ -42,7 +42,7 @@ namespace Avalonia.Shared.PlatformSupport
/// <param name="assembly">The default assembly.</param> /// <param name="assembly">The default assembly.</param>
public void SetDefaultAssembly(Assembly assembly) public void SetDefaultAssembly(Assembly assembly)
{ {
_defaultAssembly = new AssemblyDescriptor(assembly); _defaultResmAssembly = new AssemblyDescriptor(assembly);
} }
/// <summary> /// <summary>
@ -115,7 +115,7 @@ namespace Avalonia.Shared.PlatformSupport
} }
uri = EnsureAbsolute(uri, baseUri); uri = EnsureAbsolute(uri, baseUri);
if (uri.Scheme == "res") if (uri.Scheme == "avares")
{ {
var (asm, path) = GetResAsmAndPath(uri); var (asm, path) = GetResAsmAndPath(uri);
if (asm == null) if (asm == null)
@ -129,7 +129,7 @@ namespace Avalonia.Shared.PlatformSupport
return Enumerable.Empty<Uri>(); return Enumerable.Empty<Uri>();
path = path.TrimEnd('/') + '/'; path = path.TrimEnd('/') + '/';
return asm.AvaloniaResources.Where(r => r.Key.StartsWith(path)) return asm.AvaloniaResources.Where(r => r.Key.StartsWith(path))
.Select(x => new Uri($"res:asm:{asm.Name}{x.Key}")); .Select(x => new Uri($"avares://{asm.Name}{x.Key}"));
} }
return Enumerable.Empty<Uri>(); return Enumerable.Empty<Uri>();
@ -153,7 +153,7 @@ namespace Avalonia.Shared.PlatformSupport
{ {
if (uri.IsAbsoluteUri && uri.Scheme == "resm") if (uri.IsAbsoluteUri && uri.Scheme == "resm")
{ {
var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultAssembly; var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultResmAssembly;
if (asm == null) if (asm == null)
{ {
@ -171,13 +171,9 @@ namespace Avalonia.Shared.PlatformSupport
uri = EnsureAbsolute(uri, baseUri); uri = EnsureAbsolute(uri, baseUri);
if (uri.Scheme == "res") if (uri.Scheme == "avares")
{ {
var (asm, path) = GetResAsmAndPath(uri); var (asm, path) = GetResAsmAndPath(uri);
if(asm == null)
throw new ArgumentException(
"No default assembly, entry assembly or explicit assembly specified; " +
"don't know where to look up for the resource, try specifying assembly explicitly.");
if (asm.AvaloniaResources == null) if (asm.AvaloniaResources == null)
return null; return null;
asm.AvaloniaResources.TryGetValue(path, out var desc); asm.AvaloniaResources.TryGetValue(path, out var desc);
@ -189,18 +185,8 @@ namespace Avalonia.Shared.PlatformSupport
private (AssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri) private (AssemblyDescriptor asm, string path) GetResAsmAndPath(Uri uri)
{ {
string path = null, asmPart = null; var asm = GetAssembly(uri.Authority);
if (!uri.AbsolutePath.StartsWith("asm:")) return (asm, uri.AbsolutePath);
path = uri.AbsolutePath;
else
{
var sp = uri.AbsolutePath.Split(new[] {'/'}, 2);
asmPart = sp[0].Substring(4);
path = '/' + sp[1];
}
var asm = (asmPart == null ? null : GetAssembly(asmPart)) ?? _defaultAssembly;
return (asm, path);
} }
private AssemblyDescriptor GetAssembly(Uri uri) private AssemblyDescriptor GetAssembly(Uri uri)
@ -209,7 +195,7 @@ namespace Avalonia.Shared.PlatformSupport
{ {
if (!uri.IsAbsoluteUri) if (!uri.IsAbsoluteUri)
return null; return null;
if (uri.Scheme == "res") if (uri.Scheme == "avares")
return GetResAsmAndPath(uri).asm; return GetResAsmAndPath(uri).asm;
if (uri.Scheme == "resm") if (uri.Scheme == "resm")
@ -230,9 +216,7 @@ namespace Avalonia.Shared.PlatformSupport
private AssemblyDescriptor GetAssembly(string name) private AssemblyDescriptor GetAssembly(string name)
{ {
if (name == null) if (name == null)
{ throw new ArgumentNullException(nameof(name));
return _defaultAssembly;
}
AssemblyDescriptor rv; AssemblyDescriptor rv;
if (!AssemblyNameCache.TryGetValue(name, out rv)) if (!AssemblyNameCache.TryGetValue(name, out rv))
@ -247,9 +231,7 @@ namespace Avalonia.Shared.PlatformSupport
{ {
// iOS does not support loading assemblies dynamically! // iOS does not support loading assemblies dynamically!
// //
#if NETCOREAPP1_0 #if __IOS__
AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name)));
#elif __IOS__
throw new InvalidOperationException( throw new InvalidOperationException(
$"Assembly {name} needs to be referenced and explicitly loaded before loading resources"); $"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
#else #else
@ -400,5 +382,13 @@ namespace Avalonia.Shared.PlatformSupport
public Dictionary<string, IAssetDescriptor> AvaloniaResources { get; } public Dictionary<string, IAssetDescriptor> AvaloniaResources { get; }
public string Name { get; } public string Name { get; }
} }
public static void RegisterResUriParsers()
{
UriParser.Register(new GenericUriParser(GenericUriParserOptions.GenericAuthority |
GenericUriParserOptions.NoUserInfo |
GenericUriParserOptions.NoPort | GenericUriParserOptions.NoQuery |
GenericUriParserOptions.NoFragment), "avares", -1);
}
} }
} }

1
src/Shared/PlatformSupport/StandardRuntimePlatformServices.cs

@ -10,6 +10,7 @@ namespace Avalonia.Shared.PlatformSupport
public static void Register(Assembly assembly = null) public static void Register(Assembly assembly = null)
{ {
var standardPlatform = new StandardRuntimePlatform(); var standardPlatform = new StandardRuntimePlatform();
AssetLoader.RegisterResUriParsers();
AvaloniaLocator.CurrentMutable AvaloniaLocator.CurrentMutable
.Bind<IRuntimePlatform>().ToConstant(standardPlatform) .Bind<IRuntimePlatform>().ToConstant(standardPlatform)
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly)) .Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly))

Loading…
Cancel
Save