Browse Source

Updated AppBuilder and added a documentation block about Avalonia Modules.

pull/707/head
Jeremy Koritzinsky 10 years ago
parent
commit
1ae9b07764
  1. 28
      src/Avalonia.Controls/AppBuilderBase.cs
  2. 42
      src/Avalonia.Controls/Platform/ExportAvaloniaModuleAttribute.cs
  3. 8
      src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
  4. 3
      src/Gtk/Avalonia.Cairo/CairoPlatform.cs
  5. 3
      src/Gtk/Avalonia.Gtk/GtkPlatform.cs
  6. 3
      src/Skia/Avalonia.Skia/SkiaPlatform.cs
  7. 3
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  8. 3
      src/Windows/Avalonia.Win32/Win32Platform.cs
  9. 3
      src/iOS/Avalonia.iOS/iOSPlatform.cs
  10. 13
      tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs

28
src/Avalonia.Controls/AppBuilderBase.cs

@ -35,9 +35,9 @@ namespace Avalonia.Controls
public Action WindowingSubsystemInitializer { get; private set; } public Action WindowingSubsystemInitializer { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the name of the windowing subsystem to use. /// Gets the name of the currently selected windowing subsystem.
/// </summary> /// </summary>
public string WindowingSubsystemName { get; set; } public string WindowingSubsystemName { get; private set; }
/// <summary> /// <summary>
/// Gets or sets a method to call the initialize the windowing subsystem. /// Gets or sets a method to call the initialize the windowing subsystem.
@ -45,9 +45,9 @@ namespace Avalonia.Controls
public Action RenderingSubsystemInitializer { get; private set; } public Action RenderingSubsystemInitializer { get; private set; }
/// <summary> /// <summary>
/// Gets or sets the name of the rendering subsystem to use. /// Gets the name of the currently selected rendering subsystem.
/// </summary> /// </summary>
public string RenderingSubsystemName { get; set; } public string RenderingSubsystemName { get; private set; }
/// <summary> /// <summary>
/// Gets or sets a method to call after the <see cref="Application"/> is setup. /// Gets or sets a method to call after the <see cref="Application"/> is setup.
@ -141,9 +141,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="initializer">The method to call to initialize the windowing subsystem.</param> /// <param name="initializer">The method to call to initialize the windowing subsystem.</param>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns> /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseWindowingSubsystem(Action initializer) public TAppBuilder UseWindowingSubsystem(Action initializer, string name = "")
{ {
WindowingSubsystemInitializer = initializer; WindowingSubsystemInitializer = initializer;
WindowingSubsystemName = name;
return Self; return Self;
} }
@ -152,16 +153,17 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="dll">The dll in which to look for subsystem.</param> /// <param name="dll">The dll in which to look for subsystem.</param>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns> /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseWindowingSubsystem(string dll) => UseWindowingSubsystem(GetInitializer(dll)); public TAppBuilder UseWindowingSubsystem(string dll) => UseWindowingSubsystem(GetInitializer(dll), dll.Replace("Avalonia.", string.Empty));
/// <summary> /// <summary>
/// Specifies a rendering subsystem to use. /// Specifies a rendering subsystem to use.
/// </summary> /// </summary>
/// <param name="initializer">The method to call to initialize the rendering subsystem.</param> /// <param name="initializer">The method to call to initialize the rendering subsystem.</param>
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns> /// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseRenderingSubsystem(Action initializer) public TAppBuilder UseRenderingSubsystem(Action initializer, string name = "")
{ {
RenderingSubsystemInitializer = initializer; RenderingSubsystemInitializer = initializer;
RenderingSubsystemName = name;
return Self; return Self;
} }
@ -188,14 +190,14 @@ namespace Avalonia.Controls
{ {
var moduleInitializers = from assembly in AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetLoadedAssemblies() var moduleInitializers = from assembly in AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetLoadedAssemblies()
from attribute in assembly.GetCustomAttributes<ExportAvaloniaModuleAttribute>() from attribute in assembly.GetCustomAttributes<ExportAvaloniaModuleAttribute>()
where attribute.RequiredWindowingSubsystem == "" where attribute.ForWindowingSubsystem == ""
|| attribute.RequiredWindowingSubsystem == WindowingSubsystemName || attribute.ForWindowingSubsystem == WindowingSubsystemName
where attribute.RequiredRenderingSubsystem == "" where attribute.ForRenderingSubsystem == ""
|| attribute.RequiredRenderingSubsystem == RenderingSubsystemName || attribute.ForRenderingSubsystem == RenderingSubsystemName
group attribute by attribute.Name into exports group attribute by attribute.Name into exports
select (from export in exports select (from export in exports
orderby export.RequiredWindowingSubsystem.Length descending orderby export.ForWindowingSubsystem.Length descending
orderby export.RequiredRenderingSubsystem.Length descending orderby export.ForRenderingSubsystem.Length descending
select export).First().ModuleType into moduleType select export).First().ModuleType into moduleType
select (from constructor in moduleType.GetTypeInfo().DeclaredConstructors select (from constructor in moduleType.GetTypeInfo().DeclaredConstructors
where constructor.GetParameters().Length == 0 && !constructor.IsStatic where constructor.GetParameters().Length == 0 && !constructor.IsStatic

42
src/Avalonia.Controls/Platform/ExportAvaloniaModuleAttribute.cs

@ -2,6 +2,44 @@
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
/// <summary>
/// Defines an "Avalonia Module", a 3rd party extension to Avalonia that can be automatically initialized by an AppBuilder instance.
/// </summary>
/// <remarks>
/// Avalonia Modules can either be platform independent (ex default control styles provider) or dependent on a
/// specific windowing or rendering subsystem being used (ex native rendering speedup, subsystem-specific interop backends).
/// In the case of a subsystem-specific module, you can specify multiple module implementations, and also a fallback
/// platform-independent module if you so choose. Additionally, these different implementations can be in different assemblies.
/// They just need to all share the same module name.
///
/// For example, if I had a module Foo that has a special back-end for Skia and a less performant/less user friendly back-end for
/// any other rendering subsystem, I would do the following:
/// <code>
/// // In assembly FooModuleSkia.dll
/// [assembly:ExportAvaloniaModule("Foo", typeof(FooModuleSkia), ForRenderingSubsystem="Skia")]
///
/// class FooModuleSkia
/// {
/// public FooModuleSkia()
/// {
/// InitializeModule();
/// }
/// }
///
/// // In assembly FooModuleFallback.dll
/// [assembly:ExportAvaloniaModule("Foo", typeof(FooModuleFallback))]
///
/// class FooModuleFallback
/// {
/// public FooModuleFallback()
/// {
/// InitializeModule();
/// }
/// }
///
/// </code>
/// The fallback module will only be initialized if the Skia-specific module is not applicable.
/// </remarks>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class ExportAvaloniaModuleAttribute : Attribute public class ExportAvaloniaModuleAttribute : Attribute
{ {
@ -14,7 +52,7 @@ namespace Avalonia.Platform
public string Name { get; private set; } public string Name { get; private set; }
public Type ModuleType { get; private set; } public Type ModuleType { get; private set; }
public string RequiredWindowingSubsystem { get; set; } = ""; public string ForWindowingSubsystem { get; set; } = "";
public string RequiredRenderingSubsystem { get; set; } = ""; public string ForRenderingSubsystem { get; set; } = "";
} }
} }

8
src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs

@ -43,12 +43,12 @@ namespace Avalonia
select attribute).First(); select attribute).First();
UseWindowingSubsystem(() => windowingSubsystemAttribute.InitializationType UseWindowingSubsystem(() => windowingSubsystemAttribute.InitializationType
.GetRuntimeMethod(windowingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null)); .GetRuntimeMethod(windowingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null),
WindowingSubsystemName = windowingSubsystemAttribute.Name; windowingSubsystemAttribute.Name);
UseRenderingSubsystem(() => renderingSubsystemAttribute.InitializationType UseRenderingSubsystem(() => renderingSubsystemAttribute.InitializationType
.GetRuntimeMethod(renderingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null)); .GetRuntimeMethod(renderingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null),
RenderingSubsystemName = renderingSubsystemAttribute.Name; renderingSubsystemAttribute.Name);
return this; return this;
} }

3
src/Gtk/Avalonia.Cairo/CairoPlatform.cs

@ -14,8 +14,7 @@ namespace Avalonia
{ {
public static T UseCairo<T>(this T builder) where T : AppBuilderBase<T>, new() public static T UseCairo<T>(this T builder) where T : AppBuilderBase<T>, new()
{ {
builder.UseRenderingSubsystem(Cairo.CairoPlatform.Initialize); builder.UseRenderingSubsystem(Cairo.CairoPlatform.Initialize, "Cairo");
builder.RenderingSubsystemName = "Cairo";
return builder; return builder;
} }
} }

3
src/Gtk/Avalonia.Gtk/GtkPlatform.cs

@ -16,8 +16,7 @@ namespace Avalonia
{ {
public static T UseGtk<T>(this T builder) where T : AppBuilderBase<T>, new() public static T UseGtk<T>(this T builder) where T : AppBuilderBase<T>, new()
{ {
builder.UseWindowingSubsystem(Gtk.GtkPlatform.Initialize); builder.UseWindowingSubsystem(Gtk.GtkPlatform.Initialize, "Gtk");
builder.WindowingSubsystemName = "Gtk";
return builder; return builder;
} }
} }

3
src/Skia/Avalonia.Skia/SkiaPlatform.cs

@ -10,8 +10,7 @@ namespace Avalonia
{ {
public static T UseSkia<T>(this T builder) where T : AppBuilderBase<T>, new() public static T UseSkia<T>(this T builder) where T : AppBuilderBase<T>, new()
{ {
builder.UseRenderingSubsystem(Skia.SkiaPlatform.Initialize); builder.UseRenderingSubsystem(Skia.SkiaPlatform.Initialize, "Skia");
builder.RenderingSubsystemName = "Skia";
return builder; return builder;
} }
} }

3
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -14,8 +14,7 @@ namespace Avalonia
{ {
public static T UseDirect2D1<T>(this T builder) where T : AppBuilderBase<T>, new() public static T UseDirect2D1<T>(this T builder) where T : AppBuilderBase<T>, new()
{ {
builder.UseRenderingSubsystem(Direct2D1.Direct2D1Platform.Initialize); builder.UseRenderingSubsystem(Direct2D1.Direct2D1Platform.Initialize, "Direct2D1");
builder.RenderingSubsystemName = "Direct2D1";
return builder; return builder;
} }
} }

3
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -23,8 +23,7 @@ namespace Avalonia
{ {
public static T UseWin32<T>(this T builder) where T : AppBuilderBase<T>, new() public static T UseWin32<T>(this T builder) where T : AppBuilderBase<T>, new()
{ {
builder.UseWindowingSubsystem(Win32.Win32Platform.Initialize); builder.UseWindowingSubsystem(Win32.Win32Platform.Initialize, "Win32");
builder.WindowingSubsystemName = "Win32";
return builder; return builder;
} }
} }

3
src/iOS/Avalonia.iOS/iOSPlatform.cs

@ -15,8 +15,7 @@ namespace Avalonia
{ {
public static T UseiOS<T>(this T builder) where T : AppBuilderBase<T>, new() public static T UseiOS<T>(this T builder) where T : AppBuilderBase<T>, new()
{ {
builder.UseWindowingSubsystem(iOSPlatform.Initialize); builder.UseWindowingSubsystem(iOSPlatform.Initialize, "iOS");
builder.WindowingSubsystemName = "iOS";
return builder; return builder;
} }

13
tests/Avalonia.Controls.UnitTests/AppBuilderTests.cs

@ -8,8 +8,8 @@ using Avalonia.Controls.UnitTests;
using Avalonia.Platform; using Avalonia.Platform;
[assembly: ExportAvaloniaModule("DefaultModule", typeof(AppBuilderTests.DefaultModule))] [assembly: ExportAvaloniaModule("DefaultModule", typeof(AppBuilderTests.DefaultModule))]
[assembly: ExportAvaloniaModule("RenderingModule", typeof(AppBuilderTests.Direct2DModule), RequiredRenderingSubsystem = "Direct2D1")] [assembly: ExportAvaloniaModule("RenderingModule", typeof(AppBuilderTests.Direct2DModule), ForRenderingSubsystem = "Direct2D1")]
[assembly: ExportAvaloniaModule("RenderingModule", typeof(AppBuilderTests.SkiaModule), RequiredRenderingSubsystem = "Skia")] [assembly: ExportAvaloniaModule("RenderingModule", typeof(AppBuilderTests.SkiaModule), ForRenderingSubsystem = "Skia")]
[assembly: ExportAvaloniaModule("RenderingModule", typeof(AppBuilderTests.DefaultRenderingModule))] [assembly: ExportAvaloniaModule("RenderingModule", typeof(AppBuilderTests.DefaultRenderingModule))]
@ -82,8 +82,7 @@ namespace Avalonia.Controls.UnitTests
ResetModuleLoadStates(); ResetModuleLoadStates();
var builder = AppBuilder.Configure<App>() var builder = AppBuilder.Configure<App>()
.UseWindowingSubsystem(() => { }) .UseWindowingSubsystem(() => { })
.UseRenderingSubsystem(() => { }); .UseRenderingSubsystem(() => { }, "Direct2D1");
builder.RenderingSubsystemName = "Direct2D1";
builder.UseAvaloniaModules().SetupWithoutStarting(); builder.UseAvaloniaModules().SetupWithoutStarting();
Assert.False(DefaultRenderingModule.IsLoaded); Assert.False(DefaultRenderingModule.IsLoaded);
Assert.True(Direct2DModule.IsLoaded); Assert.True(Direct2DModule.IsLoaded);
@ -92,8 +91,7 @@ namespace Avalonia.Controls.UnitTests
ResetModuleLoadStates(); ResetModuleLoadStates();
builder = AppBuilder.Configure<App>() builder = AppBuilder.Configure<App>()
.UseWindowingSubsystem(() => { }) .UseWindowingSubsystem(() => { })
.UseRenderingSubsystem(() => { }); .UseRenderingSubsystem(() => { }, "Skia");
builder.RenderingSubsystemName = "Skia";
builder.UseAvaloniaModules().SetupWithoutStarting(); builder.UseAvaloniaModules().SetupWithoutStarting();
Assert.False(DefaultRenderingModule.IsLoaded); Assert.False(DefaultRenderingModule.IsLoaded);
Assert.False(Direct2DModule.IsLoaded); Assert.False(Direct2DModule.IsLoaded);
@ -109,8 +107,7 @@ namespace Avalonia.Controls.UnitTests
ResetModuleLoadStates(); ResetModuleLoadStates();
var builder = AppBuilder.Configure<App>() var builder = AppBuilder.Configure<App>()
.UseWindowingSubsystem(() => { }) .UseWindowingSubsystem(() => { })
.UseRenderingSubsystem(() => { }); .UseRenderingSubsystem(() => { }, "Cairo");
builder.RenderingSubsystemName = "Cairo";
builder.UseAvaloniaModules().SetupWithoutStarting(); builder.UseAvaloniaModules().SetupWithoutStarting();
Assert.True(DefaultRenderingModule.IsLoaded); Assert.True(DefaultRenderingModule.IsLoaded);
Assert.False(Direct2DModule.IsLoaded); Assert.False(Direct2DModule.IsLoaded);

Loading…
Cancel
Save