* Try fix #13935 * Fix * Fix * add sample * Fix * try load Style by reflection * try * Fixed an error when registering properties when uninstalling assemblies * Allowed to delete the IAssemblyDescriptorResolver StandardAssetLoader _assemblyNameCache * Resolving merge conflicts * Fix * Add exegesis * optimize * fix * Resolving merge conflicts * nuke
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
"samples\\RenderDemo\\RenderDemo.csproj",
|
||||
"samples\\SampleControls\\ControlSamples.csproj",
|
||||
"samples\\Sandbox\\Sandbox.csproj",
|
||||
"samples\\UnloadableAssemblyLoadContext\\UnloadableAssemblyLoadContextPlug\\UnloadableAssemblyLoadContextPlug.csproj",
|
||||
"samples\\UnloadableAssemblyLoadContext\\UnloadableAssemblyLoadContext\\UnloadableAssemblyLoadContext.csproj",
|
||||
"src\\Avalonia.Base\\Avalonia.Base.csproj",
|
||||
"src\\Avalonia.Build.Tasks\\Avalonia.Build.Tasks.csproj",
|
||||
"src\\Avalonia.Controls.ColorPicker\\Avalonia.Controls.ColorPicker.csproj",
|
||||
|
||||
+18
-1
@@ -1,4 +1,3 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
@@ -291,6 +290,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildTasks", "BuildTasks",
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PInvoke", "tests\TestFiles\BuildTasks\PInvoke\PInvoke.csproj", "{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}"
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnloadableAssemblyLoadContext", "UnloadableAssemblyLoadContext", "{9CCA131B-DE95-4D44-8788-C3CAE28574CD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnloadableAssemblyLoadContext", "samples\UnloadableAssemblyLoadContext\UnloadableAssemblyLoadContext\UnloadableAssemblyLoadContext.csproj", "{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnloadableAssemblyLoadContextPlug", "samples\UnloadableAssemblyLoadContext\UnloadableAssemblyLoadContextPlug\UnloadableAssemblyLoadContextPlug.csproj", "{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.RenderTests.WpfCompare", "tests\Avalonia.RenderTests.WpfCompare\Avalonia.RenderTests.WpfCompare.csproj", "{9AE1B827-21AC-4063-AB22-C8804B7F931E}"
|
||||
EndProject
|
||||
Global
|
||||
@@ -677,6 +683,14 @@ Global
|
||||
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9AE1B827-21AC-4063-AB22-C8804B7F931E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9AE1B827-21AC-4063-AB22-C8804B7F931E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9AE1B827-21AC-4063-AB22-C8804B7F931E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -764,6 +778,9 @@ Global
|
||||
{9D6AEF22-221F-4F4B-B335-A4BA510F002C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
{5BF0C3B8-E595-4940-AB30-2DA206C2F085} = {9D6AEF22-221F-4F4B-B335-A4BA510F002C}
|
||||
{0A948D71-99C5-43E9-BACB-B0BA59EA25B4} = {5BF0C3B8-E595-4940-AB30-2DA206C2F085}
|
||||
{9CCA131B-DE95-4D44-8788-C3CAE28574CD} = {9B9E3891-2366-4253-A952-D08BCEB71098}
|
||||
{D7FE3E0F-3FE0-4F87-A2F5-24F1454D84C0} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD}
|
||||
{DA5F1FF9-4259-4C54-B443-85CFA226EE6A} = {9CCA131B-DE95-4D44-8788-C3CAE28574CD}
|
||||
{9AE1B827-21AC-4063-AB22-C8804B7F931E} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
|
||||
@@ -1075,6 +1075,18 @@
|
||||
<Left>baseline/netstandard2.0/Avalonia.Dialogs.dll</Left>
|
||||
<Right>target/netstandard2.0/Avalonia.Dialogs.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0006</DiagnosticId>
|
||||
<Target>M:Avalonia.Platform.IAssetLoader.InvalidateAssemblyCache</Target>
|
||||
<Left>baseline/netstandard2.0/Avalonia.Base.dll</Left>
|
||||
<Right>target/netstandard2.0/Avalonia.Base.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0006</DiagnosticId>
|
||||
<Target>M:Avalonia.Platform.IAssetLoader.InvalidateAssemblyCache(System.String)</Target>
|
||||
<Left>baseline/netstandard2.0/Avalonia.Base.dll</Left>
|
||||
<Right>target/netstandard2.0/Avalonia.Base.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0006</DiagnosticId>
|
||||
<Target>P:Avalonia.Media.IRadialGradientBrush.RadiusX</Target>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="UnloadableAssemblyLoadContext.App"
|
||||
RequestedThemeVariant="Default">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@@ -0,0 +1,23 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace UnloadableAssemblyLoadContext;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow = new MainWindow();
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
#region
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Avalonia;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Styling;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace UnloadableAssemblyLoadContext;
|
||||
|
||||
public class AssemblyLoadContextH : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
|
||||
public AssemblyLoadContextH(string pluginPath, string name) : base(isCollectible: true, name: name)
|
||||
{
|
||||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||
Unloading += (sender) =>
|
||||
{
|
||||
AvaloniaPropertyRegistry.Instance.UnregisterByModule(sender.Assemblies.First().DefinedTypes);
|
||||
Application.Current.Styles.Remove(MainWindow.Style);
|
||||
AssetLoader.InvalidateAssemblyCache(sender.Assemblies.First().GetName().Name);
|
||||
MainWindow.Style= null;
|
||||
};
|
||||
}
|
||||
|
||||
protected override Assembly Load(AssemblyName assemblyName)
|
||||
{
|
||||
var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
|
||||
if (assemblyPath != null)
|
||||
{
|
||||
if (assemblyPath.EndsWith("WinRT.Runtime.dll") || assemblyPath.EndsWith("Microsoft.Windows.SDK.NET.dll")|| assemblyPath.EndsWith("Avalonia.Controls.dll")|| assemblyPath.EndsWith("Avalonia.Base.dll")|| assemblyPath.EndsWith("Avalonia.Markup.Xaml.dll"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return LoadFromAssemblyPath(assemblyPath);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
|
||||
{
|
||||
var libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
|
||||
if (libraryPath != null)
|
||||
{
|
||||
return LoadUnmanagedDllFromPath(libraryPath);
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="UnloadableAssemblyLoadContext.MainWindow"
|
||||
Title="UnloadableAssemblyLoadContext">
|
||||
Welcome to Avalonia!
|
||||
</Window>
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Markup.Xaml.Styling;
|
||||
using Avalonia.Markup.Xaml.XamlIl.Runtime;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Platform.Internal;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
namespace UnloadableAssemblyLoadContext;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
if (Debugger.IsAttached)
|
||||
{
|
||||
this.AttachDevTools();
|
||||
}
|
||||
}
|
||||
private PlugTool _plugTool;
|
||||
protected override void OnOpened(EventArgs e)
|
||||
{
|
||||
base.OnOpened(e);
|
||||
test();
|
||||
//Content = _plugTool.FindControl("UnloadableAssemblyLoadContextPlug.TestControl");
|
||||
|
||||
|
||||
}
|
||||
public T? GetChildOfType<T>(Control control)
|
||||
where T : Control
|
||||
{
|
||||
var queue = new Queue<Control>();
|
||||
queue.Enqueue(control);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var currentControl = queue.Dequeue();
|
||||
foreach (var child in currentControl.GetVisualChildren())
|
||||
{
|
||||
var childControl = child as Control;
|
||||
if (childControl != null)
|
||||
{
|
||||
var childControlStyles = childControl.Styles;
|
||||
if (childControlStyles.Count>1)
|
||||
{
|
||||
|
||||
}
|
||||
queue.Enqueue(childControl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
GetChildOfType<Control>(this);
|
||||
|
||||
|
||||
Thread.CurrentThread.IsBackground = false;
|
||||
var weakReference = _plugTool.Unload();
|
||||
while (weakReference.IsAlive)
|
||||
{
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
Console.WriteLine("Done");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static IStyle Style;
|
||||
public void test(){
|
||||
|
||||
//Notice : 你可以删除UnloadableAssemblyLoadContextPlug.dll所在文件夹中有关Avalonia的所有Dll,但这不是必须的
|
||||
//Notice : You can delete all Dlls about Avalonia in the folder where UnloadableAssemblyLoadContextPlug.dll is located, but this is not necessary
|
||||
FileInfo fileInfo = new FileInfo("..\\..\\..\\..\\UnloadableAssemblyLoadContextPlug\\bin\\Debug\\net7.0\\UnloadableAssemblyLoadContextPlug.dll");
|
||||
var AssemblyLoadContextH = new AssemblyLoadContextH(fileInfo.FullName,"test");
|
||||
|
||||
var assembly = AssemblyLoadContextH.LoadFromAssemblyPath(fileInfo.FullName);
|
||||
var assemblyDescriptorResolver =
|
||||
_plugTool=new PlugTool();
|
||||
_plugTool.AssemblyLoadContextH = AssemblyLoadContextH;
|
||||
|
||||
var styles = new Styles();
|
||||
var styleInclude = new StyleInclude(new Uri("avares://UnloadableAssemblyLoadContextPlug", UriKind.Absolute));
|
||||
styleInclude.Source=new Uri("ControlStyle.axaml", UriKind.Relative);
|
||||
styles.Add(styleInclude);
|
||||
Style = styles;
|
||||
Application.Current.Styles.Add(styles);
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.FullName=="AvaloniaPlug.Window1")
|
||||
{
|
||||
//创建type实例
|
||||
Window instance = (Window)type.GetConstructor( new Type[0]).Invoke(null);
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
instance.Show();
|
||||
instance.Close();
|
||||
|
||||
}).Wait();
|
||||
|
||||
instance = null;
|
||||
|
||||
//instance.Show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace UnloadableAssemblyLoadContext;
|
||||
|
||||
public class PlugTool
|
||||
{
|
||||
public AssemblyLoadContextH AssemblyLoadContextH;
|
||||
public WeakReference Unload()
|
||||
{
|
||||
var weakReference = new WeakReference(AssemblyLoadContextH);
|
||||
AssemblyLoadContextH.Unload();
|
||||
AssemblyLoadContextH = null;
|
||||
return weakReference;
|
||||
}
|
||||
|
||||
public Control? FindControl(string type)
|
||||
{
|
||||
var type1 = AssemblyLoadContextH.Assemblies.
|
||||
FirstOrDefault(x => x.GetName().Name == "UnloadableAssemblyLoadContextPlug")?.
|
||||
GetType(type);
|
||||
if (type1.IsSubclassOf(typeof(Control)))
|
||||
{
|
||||
var constructorInfo = type1.GetConstructor( Type.EmptyTypes).Invoke(null) as Control;
|
||||
return constructorInfo;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
|
||||
namespace UnloadableAssemblyLoadContext;
|
||||
|
||||
class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="20">
|
||||
<!-- Add Controls for Previewer Here -->
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<!-- Add Styles Here -->
|
||||
</Styles>
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
<IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="**\*.xaml.cs">
|
||||
<DependentUpon>%(Filename)</DependentUpon>
|
||||
</Compile>
|
||||
<AvaloniaResource Include="**\*.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</AvaloniaResource>
|
||||
<AvaloniaResource Include="Assets\*" />
|
||||
<AvaloniaResource Include="Assets\Fonts\*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\"/>
|
||||
<AvaloniaResource Include="Assets\**"/>
|
||||
</ItemGroup>
|
||||
<ImportGroup>
|
||||
<Import Project="..\..\..\build\BuildTargets.targets" Condition="Exists('..\..\..\build\BuildTargets.targets')" />
|
||||
<Import Project="..\..\..\build\SourceGenerators.props" />
|
||||
</ImportGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="AvaloniaApplication2.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
>
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="20">
|
||||
<!-- Add Controls for Previewer Here -->
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<StyleInclude Source="TestControl.axaml"></StyleInclude>
|
||||
</Styles>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AvaloniaPlug;
|
||||
|
||||
class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
private static string test = "23";
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:UnloadableAssemblyLoadContextPlug">
|
||||
<Design.PreviewWith>
|
||||
<controls:TestControl />
|
||||
</Design.PreviewWith>
|
||||
|
||||
<Style Selector="controls|TestControl">
|
||||
<!-- Set Defaults -->
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<TextBlock Text="Templated Control" />
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Styles>
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
|
||||
namespace UnloadableAssemblyLoadContextPlug;
|
||||
|
||||
public class TestControl : TemplatedControl
|
||||
{
|
||||
}
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
<AssemblyName>UnloadableAssemblyLoadContextPlug</AssemblyName>
|
||||
<RootNamespace>UnloadableAssemblyLoadContextPlug</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="**\*.xaml.cs">
|
||||
<DependentUpon>%(Filename)</DependentUpon>
|
||||
</Compile>
|
||||
<AvaloniaResource Include="**\*.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</AvaloniaResource>
|
||||
<AvaloniaResource Include="Assets\*" />
|
||||
<AvaloniaResource Include="Assets\Fonts\*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ImportGroup>
|
||||
<Import Project="..\..\..\build\BuildTargets.targets" Condition="Exists('..\..\..\build\BuildTargets.targets')" />
|
||||
<Import Project="..\..\..\build\SourceGenerators.props" />
|
||||
</ImportGroup>
|
||||
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
|
||||
<ProjectReference Condition="'$(Configuration)' == 'Debug'" Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup.Xaml.Loader\Avalonia.Markup.Xaml.Loader.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<UpToDateCheckInput Remove="Views\MainWindow.axaml" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:avaloniaPlug="clr-namespace:AvaloniaPlug"
|
||||
xmlns:unloadableAssemblyLoadContextPlug="clr-namespace:UnloadableAssemblyLoadContextPlug"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="UnloadableAssemblyLoadContextPlug.Window1"
|
||||
x:DataType="unloadableAssemblyLoadContextPlug:Window1ViewModel"
|
||||
Title="Window1">
|
||||
<TextBlock Text="{Binding Text }" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</Window>
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using System.Diagnostics;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using AvaloniaPlug;
|
||||
|
||||
namespace UnloadableAssemblyLoadContextPlug;
|
||||
|
||||
public partial class Window1 : Window
|
||||
{
|
||||
public Window1()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext=new Window1ViewModel();
|
||||
}
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
namespace UnloadableAssemblyLoadContextPlug;
|
||||
|
||||
public partial class Window1ViewModel
|
||||
{
|
||||
public string Text { get; set; } = "12";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<!-- This manifest is used on Windows only.
|
||||
Don't remove it as it might cause problems with window transparency and embedded controls.
|
||||
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||
<assemblyIdentity version="1.0.0.0" name="AvaloniaPlug.Desktop"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
@@ -223,6 +223,11 @@ namespace Avalonia
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public void Unregister(Type type)
|
||||
{
|
||||
_metadata.Remove(type);
|
||||
_metadataCache.Remove(type);
|
||||
}
|
||||
/// <summary>
|
||||
/// Registers a <see cref="AvaloniaProperty"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Avalonia
|
||||
{
|
||||
@@ -38,6 +41,53 @@ namespace Avalonia
|
||||
/// </summary>
|
||||
internal IReadOnlyCollection<AvaloniaProperty> Properties => _properties.Values;
|
||||
|
||||
private object _unregisteringLocker = new object();
|
||||
/// <summary>
|
||||
/// Unregister all<see cref="AvaloniaProperty"/>s registered on types
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public bool UnregisterByModule(IEnumerable<Type> types)
|
||||
{
|
||||
_ = types ?? throw new ArgumentNullException(nameof(types));
|
||||
|
||||
lock (_unregisteringLocker)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var type in types)
|
||||
{
|
||||
Unregister(_registered, type);
|
||||
Unregister(_attached, type);
|
||||
Unregister(_direct, type);
|
||||
Unregister(_registeredCache,type);
|
||||
Unregister(_attachedCache,type);
|
||||
Unregister(_directCache,type);
|
||||
Unregister(_inheritedCache,type);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private void Unregister( Dictionary<Type, List<AvaloniaProperty>> dictionary,Type type)
|
||||
{
|
||||
dictionary.Remove(type);
|
||||
}
|
||||
private void Unregister( Dictionary<Type, Dictionary<int, AvaloniaProperty>> dictionary,Type type)
|
||||
{
|
||||
foreach (var keyValuePair in dictionary)
|
||||
{
|
||||
foreach (var key in keyValuePair.Value)
|
||||
{
|
||||
key.Value.Unregister(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets all non-attached <see cref="AvaloniaProperty"/>s registered on a type.
|
||||
/// </summary>
|
||||
@@ -47,7 +97,6 @@ namespace Avalonia
|
||||
public IReadOnlyList<AvaloniaProperty> GetRegistered(Type type)
|
||||
{
|
||||
_ = type ?? throw new ArgumentNullException(nameof(type));
|
||||
|
||||
if (_registeredCache.TryGetValue(type, out var result))
|
||||
{
|
||||
return result;
|
||||
@@ -55,21 +104,20 @@ namespace Avalonia
|
||||
|
||||
var t = type;
|
||||
result = new List<AvaloniaProperty>();
|
||||
|
||||
while (t != null)
|
||||
lock (_unregisteringLocker)
|
||||
{
|
||||
// Ensure the type's static ctor has been run.
|
||||
RuntimeHelpers.RunClassConstructor(t.TypeHandle);
|
||||
|
||||
if (_registered.TryGetValue(t, out var registered))
|
||||
while (t != null)
|
||||
{
|
||||
result.AddRange(registered.Values);
|
||||
// Ensure the type's static ctor has been run.
|
||||
RuntimeHelpers.RunClassConstructor(t.TypeHandle);
|
||||
if (_registered.TryGetValue(t, out var registered))
|
||||
{
|
||||
result.AddRange(registered.Values);
|
||||
}
|
||||
t = t.BaseType;
|
||||
}
|
||||
|
||||
t = t.BaseType;
|
||||
_registeredCache.Add(type, result);
|
||||
}
|
||||
|
||||
_registeredCache.Add(type, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -81,7 +129,6 @@ namespace Avalonia
|
||||
public IReadOnlyList<AvaloniaProperty> GetRegisteredAttached(Type type)
|
||||
{
|
||||
_ = type ?? throw new ArgumentNullException(nameof(type));
|
||||
|
||||
if (_attachedCache.TryGetValue(type, out var result))
|
||||
{
|
||||
return result;
|
||||
@@ -89,18 +136,18 @@ namespace Avalonia
|
||||
|
||||
var t = type;
|
||||
result = new List<AvaloniaProperty>();
|
||||
|
||||
while (t != null)
|
||||
lock (_unregisteringLocker)
|
||||
{
|
||||
if (_attached.TryGetValue(t, out var attached))
|
||||
while (t != null)
|
||||
{
|
||||
result.AddRange(attached.Values);
|
||||
if (_attached.TryGetValue(t, out var attached))
|
||||
{
|
||||
result.AddRange(attached.Values);
|
||||
}
|
||||
t = t.BaseType;
|
||||
}
|
||||
|
||||
t = t.BaseType;
|
||||
_attachedCache.Add(type, result);
|
||||
}
|
||||
|
||||
_attachedCache.Add(type, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -112,7 +159,6 @@ namespace Avalonia
|
||||
public IReadOnlyList<AvaloniaProperty> GetRegisteredDirect(Type type)
|
||||
{
|
||||
_ = type ?? throw new ArgumentNullException(nameof(type));
|
||||
|
||||
if (_directCache.TryGetValue(type, out var result))
|
||||
{
|
||||
return result;
|
||||
@@ -120,18 +166,18 @@ namespace Avalonia
|
||||
|
||||
var t = type;
|
||||
result = new List<AvaloniaProperty>();
|
||||
|
||||
while (t != null)
|
||||
lock (_unregisteringLocker)
|
||||
{
|
||||
if (_direct.TryGetValue(t, out var direct))
|
||||
while (t != null)
|
||||
{
|
||||
result.AddRange(direct.Values);
|
||||
if (_direct.TryGetValue(t, out var direct))
|
||||
{
|
||||
result.AddRange(direct.Values);
|
||||
}
|
||||
t = t.BaseType;
|
||||
}
|
||||
|
||||
t = t.BaseType;
|
||||
_directCache.Add(type, result);
|
||||
}
|
||||
|
||||
_directCache.Add(type, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -143,7 +189,6 @@ namespace Avalonia
|
||||
public IReadOnlyList<AvaloniaProperty> GetRegisteredInherited(Type type)
|
||||
{
|
||||
_ = type ?? throw new ArgumentNullException(nameof(type));
|
||||
|
||||
if (_inheritedCache.TryGetValue(type, out var result))
|
||||
{
|
||||
return result;
|
||||
@@ -182,7 +227,11 @@ namespace Avalonia
|
||||
}
|
||||
}
|
||||
|
||||
_inheritedCache.Add(type, result);
|
||||
lock (_unregisteringLocker)
|
||||
{
|
||||
_inheritedCache.Add(type, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -211,7 +260,7 @@ namespace Avalonia
|
||||
DirectPropertyBase<T> property)
|
||||
{
|
||||
return FindRegisteredDirect(o, property) ??
|
||||
throw new ArgumentException($"Property '{property.Name} not registered on '{o.GetType()}");
|
||||
throw new ArgumentException($"Property '{property.Name} not registered on '{o.GetType()}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -371,41 +420,44 @@ namespace Avalonia
|
||||
{
|
||||
_ = type ?? throw new ArgumentNullException(nameof(type));
|
||||
_ = property ?? throw new ArgumentNullException(nameof(property));
|
||||
|
||||
if (!_registered.TryGetValue(type, out var inner))
|
||||
lock (_unregisteringLocker)
|
||||
{
|
||||
inner = new Dictionary<int, AvaloniaProperty>();
|
||||
inner.Add(property.Id, property);
|
||||
_registered.Add(type, inner);
|
||||
}
|
||||
else if (!inner.ContainsKey(property.Id))
|
||||
{
|
||||
inner.Add(property.Id, property);
|
||||
}
|
||||
|
||||
if (property.IsDirect)
|
||||
{
|
||||
if (!_direct.TryGetValue(type, out inner))
|
||||
if (!_registered.TryGetValue(type, out var inner))
|
||||
{
|
||||
inner = new Dictionary<int, AvaloniaProperty>();
|
||||
inner.Add(property.Id, property);
|
||||
_direct.Add(type, inner);
|
||||
_registered.Add(type, inner);
|
||||
}
|
||||
else if (!inner.ContainsKey(property.Id))
|
||||
{
|
||||
inner.Add(property.Id, property);
|
||||
}
|
||||
|
||||
_directCache.Clear();
|
||||
}
|
||||
if (property.IsDirect)
|
||||
{
|
||||
if (!_direct.TryGetValue(type, out inner))
|
||||
{
|
||||
inner = new Dictionary<int, AvaloniaProperty>();
|
||||
inner.Add(property.Id, property);
|
||||
_direct.Add(type, inner);
|
||||
}
|
||||
else if (!inner.ContainsKey(property.Id))
|
||||
{
|
||||
inner.Add(property.Id, property);
|
||||
}
|
||||
|
||||
if (!_properties.ContainsKey(property.Id))
|
||||
{
|
||||
_properties.Add(property.Id, property);
|
||||
_directCache.Clear();
|
||||
}
|
||||
|
||||
if (!_properties.ContainsKey(property.Id))
|
||||
{
|
||||
_properties.Add(property.Id, property);
|
||||
}
|
||||
|
||||
_registeredCache.Clear();
|
||||
_inheritedCache.Clear();
|
||||
}
|
||||
|
||||
_registeredCache.Clear();
|
||||
_inheritedCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -422,26 +474,29 @@ namespace Avalonia
|
||||
{
|
||||
_ = type ?? throw new ArgumentNullException(nameof(type));
|
||||
_ = property ?? throw new ArgumentNullException(nameof(property));
|
||||
|
||||
|
||||
if (!property.IsAttached)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Cannot register a non-attached property as attached.");
|
||||
}
|
||||
|
||||
if (!_attached.TryGetValue(type, out var inner))
|
||||
lock (_unregisteringLocker)
|
||||
{
|
||||
inner = new Dictionary<int, AvaloniaProperty>();
|
||||
inner.Add(property.Id, property);
|
||||
_attached.Add(type, inner);
|
||||
}
|
||||
else
|
||||
{
|
||||
inner.Add(property.Id, property);
|
||||
}
|
||||
if (!_attached.TryGetValue(type, out var inner))
|
||||
{
|
||||
inner = new Dictionary<int, AvaloniaProperty>();
|
||||
inner.Add(property.Id, property);
|
||||
_attached.Add(type, inner);
|
||||
}
|
||||
else
|
||||
{
|
||||
inner.Add(property.Id, property);
|
||||
}
|
||||
|
||||
_attachedCache.Clear();
|
||||
_inheritedCache.Clear();
|
||||
_attachedCache.Clear();
|
||||
_inheritedCache.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ public static class AssetLoader
|
||||
/// <inheritdoc cref="IAssetLoader.GetAssets"/>
|
||||
public static IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri)
|
||||
=> GetAssetLoader().GetAssets(uri, baseUri);
|
||||
|
||||
/// <inheritdoc cref="IAssetLoader.InvalidateAssemblyCache()"/>
|
||||
public static void InvalidateAssemblyCache(string name) => GetAssetLoader().InvalidateAssemblyCache(name);
|
||||
/// <inheritdoc cref="IAssetLoader.InvalidateAssemblyCache(string)"/>
|
||||
public static void InvalidateAssemblyCache() => GetAssetLoader().InvalidateAssemblyCache();
|
||||
|
||||
#endif
|
||||
|
||||
internal static void RegisterResUriParsers()
|
||||
|
||||
@@ -77,5 +77,15 @@ namespace Avalonia.Platform
|
||||
/// <param name="baseUri">The base URI.</param>
|
||||
/// <returns>All matching assets as a tuple of the absolute path to the asset and the assembly containing the asset</returns>
|
||||
IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the assembly from the cache.
|
||||
/// </summary>
|
||||
/// <param name="name">The Assemblies.First().GetName().Name</param>
|
||||
void InvalidateAssemblyCache(string name);
|
||||
/// <summary>
|
||||
/// Removes all assemblies from the cache.
|
||||
/// </summary>
|
||||
void InvalidateAssemblyCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ namespace Avalonia.Platform.Internal;
|
||||
internal interface IAssemblyDescriptorResolver
|
||||
{
|
||||
IAssemblyDescriptor GetAssembly(string name);
|
||||
void InvalidateAssemblyCache(string name);
|
||||
void InvalidateAssemblyCache();
|
||||
|
||||
}
|
||||
|
||||
internal class AssemblyDescriptorResolver: IAssemblyDescriptorResolver
|
||||
@@ -44,4 +47,13 @@ internal class AssemblyDescriptorResolver: IAssemblyDescriptorResolver
|
||||
|
||||
return rv;
|
||||
}
|
||||
public void InvalidateAssemblyCache(string name)
|
||||
{
|
||||
_assemblyNameCache.Remove(name);
|
||||
}
|
||||
|
||||
public void InvalidateAssemblyCache()
|
||||
{
|
||||
_assemblyNameCache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,16 @@ public class StandardAssetLoader : IAssetLoader
|
||||
return Enumerable.Empty<Uri>();
|
||||
}
|
||||
|
||||
public void InvalidateAssemblyCache(string name)
|
||||
{
|
||||
_assemblyDescriptorResolver.InvalidateAssemblyCache(name);
|
||||
}
|
||||
|
||||
public void InvalidateAssemblyCache()
|
||||
{
|
||||
_assemblyDescriptorResolver.InvalidateAssemblyCache();
|
||||
}
|
||||
|
||||
public static void RegisterResUriParsers() => AssetLoader.RegisterResUriParsers();
|
||||
|
||||
private bool TryGetAsset(Uri uri, Uri? baseUri, [NotNullWhen(true)] out IAssetDescriptor? assetDescriptor)
|
||||
|
||||
@@ -312,7 +312,6 @@ namespace Avalonia.Controls
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fired when the window is opened.
|
||||
/// </summary>
|
||||
@@ -714,6 +713,7 @@ namespace Avalonia.Controls
|
||||
OnClosed(EventArgs.Empty);
|
||||
|
||||
LayoutManager.Dispose();
|
||||
_platformImplBindings.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -45,6 +45,16 @@ namespace Avalonia.UnitTests
|
||||
x => x.GetUnescapeAbsolutePath().IndexOf(absPath, StringComparison.Ordinal) >= 0);
|
||||
}
|
||||
|
||||
public void InvalidateAssemblyCache(string name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void InvalidateAssemblyCache()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetDefaultAssembly(Assembly asm)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
Reference in New Issue
Block a user