csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
4.3 KiB
122 lines
4.3 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using Avalonia.Markup.Xaml;
|
|
using Avalonia.Markup.Xaml.XamlIl;
|
|
using TinyJson;
|
|
|
|
namespace Avalonia.Designer.HostApp;
|
|
|
|
[RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)]
|
|
class DesignXamlLoader : AvaloniaXamlLoader.IRuntimeXamlLoader
|
|
{
|
|
public object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration)
|
|
{
|
|
PreloadDepsAssemblies(configuration.LocalAssembly ?? Assembly.GetEntryAssembly());
|
|
|
|
return AvaloniaXamlIlRuntimeCompiler.Load(document, configuration);
|
|
}
|
|
|
|
private void PreloadDepsAssemblies(Assembly targetAssembly)
|
|
{
|
|
// Assemblies loaded in memory (e.g. single file) return empty string from Location.
|
|
// In these cases, don't try probing next to the assembly.
|
|
var assemblyLocation = targetAssembly.Location;
|
|
if (string.IsNullOrEmpty(assemblyLocation))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var depsJsonFile = Path.ChangeExtension(assemblyLocation, ".deps.json");
|
|
if (!File.Exists(depsJsonFile))
|
|
{
|
|
var sameDir = Path.GetDirectoryName(depsJsonFile);
|
|
var fallbackDepsFiles = Directory.GetFiles(sameDir, "*.deps.json");
|
|
if (fallbackDepsFiles.Length == 1)
|
|
{
|
|
depsJsonFile = fallbackDepsFiles[0];
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($".deps.json file \"{depsJsonFile}\" doesn't exist, it might affect previewer stability.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
using var stream = File.OpenRead(depsJsonFile);
|
|
|
|
/*
|
|
We can't use any references in the Avalonia.Designer.HostApp. Including even json.
|
|
Ideally we would prefer Microsoft.Extensions.DependencyModel package, but can't use it here.
|
|
So, instead we need to fallback to some JSON parsing with copy-paste tiny json.
|
|
|
|
Json part example:
|
|
"Avalonia.Xaml.Interactions/11.0.0-preview5": {
|
|
"dependencies": {
|
|
"Avalonia": "11.0.999",
|
|
"Avalonia.Xaml.Interactivity": "11.0.0-preview5"
|
|
},
|
|
"runtime": {
|
|
"lib/net6.0/Avalonia.Xaml.Interactions.dll": {
|
|
"assemblyVersion": "11.0.0.0",
|
|
"fileVersion": "11.0.0.0"
|
|
}
|
|
}
|
|
},
|
|
We want to extract "lib/net6.0/Avalonia.Xaml.Interactions.dll" from here.
|
|
No need to resolve real path of ref assemblies.
|
|
No need to handle special cases with .NET Framework and GAC.
|
|
*/
|
|
var text = new StreamReader(stream).ReadToEnd();
|
|
var deps = ParseRuntimeDeps(text);
|
|
|
|
foreach (var dependencyRuntimeLibs in deps)
|
|
{
|
|
foreach (var runtimeLib in dependencyRuntimeLibs)
|
|
{
|
|
var assemblyName = Path.GetFileNameWithoutExtension(runtimeLib);
|
|
try
|
|
{
|
|
_ = Assembly.Load(new AssemblyName(assemblyName));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static List<IEnumerable<string>> ParseRuntimeDeps(string text)
|
|
{
|
|
var runtimeDeps = new List<IEnumerable<string>>();
|
|
try
|
|
{
|
|
var value = JSONParser.FromJson<Dictionary<string, object>>(text);
|
|
if (value?.TryGetValue("targets", out var targetsObj) == true
|
|
&& targetsObj is Dictionary<string, object> targets)
|
|
{
|
|
foreach (var target in targets)
|
|
{
|
|
if (target.Value is Dictionary<string, object> libraries)
|
|
{
|
|
foreach (var library in libraries)
|
|
{
|
|
if ((library.Value as Dictionary<string, object>)?.TryGetValue("runtime", out var runtimeObj) == true
|
|
&& runtimeObj is Dictionary<string, object> runtime)
|
|
{
|
|
runtimeDeps.Add(runtime.Keys);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(".deps.json file parsing failed, it might affect previewer stability.\r\n" + ex);
|
|
}
|
|
return runtimeDeps;
|
|
}
|
|
}
|
|
|