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

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

@ -2,6 +2,44 @@
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)]
public class ExportAvaloniaModuleAttribute : Attribute
{
@ -14,7 +52,7 @@ namespace Avalonia.Platform
public string Name { get; private set; }
public Type ModuleType { get; private set; }
public string RequiredWindowingSubsystem { get; set; } = "";
public string RequiredRenderingSubsystem { get; set; } = "";
public string ForWindowingSubsystem { get; set; } = "";
public string ForRenderingSubsystem { get; set; } = "";
}
}

8
src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs

@ -43,12 +43,12 @@ namespace Avalonia
select attribute).First();
UseWindowingSubsystem(() => windowingSubsystemAttribute.InitializationType
.GetRuntimeMethod(windowingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null));
WindowingSubsystemName = windowingSubsystemAttribute.Name;
.GetRuntimeMethod(windowingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null),
windowingSubsystemAttribute.Name);
UseRenderingSubsystem(() => renderingSubsystemAttribute.InitializationType
.GetRuntimeMethod(renderingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null));
RenderingSubsystemName = renderingSubsystemAttribute.Name;
.GetRuntimeMethod(renderingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null),
renderingSubsystemAttribute.Name);
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()
{
builder.UseRenderingSubsystem(Cairo.CairoPlatform.Initialize);
builder.RenderingSubsystemName = "Cairo";
builder.UseRenderingSubsystem(Cairo.CairoPlatform.Initialize, "Cairo");
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()
{
builder.UseWindowingSubsystem(Gtk.GtkPlatform.Initialize);
builder.WindowingSubsystemName = "Gtk";
builder.UseWindowingSubsystem(Gtk.GtkPlatform.Initialize, "Gtk");
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()
{
builder.UseRenderingSubsystem(Skia.SkiaPlatform.Initialize);
builder.RenderingSubsystemName = "Skia";
builder.UseRenderingSubsystem(Skia.SkiaPlatform.Initialize, "Skia");
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()
{
builder.UseRenderingSubsystem(Direct2D1.Direct2D1Platform.Initialize);
builder.RenderingSubsystemName = "Direct2D1";
builder.UseRenderingSubsystem(Direct2D1.Direct2D1Platform.Initialize, "Direct2D1");
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()
{
builder.UseWindowingSubsystem(Win32.Win32Platform.Initialize);
builder.WindowingSubsystemName = "Win32";
builder.UseWindowingSubsystem(Win32.Win32Platform.Initialize, "Win32");
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()
{
builder.UseWindowingSubsystem(iOSPlatform.Initialize);
builder.WindowingSubsystemName = "iOS";
builder.UseWindowingSubsystem(iOSPlatform.Initialize, "iOS");
return builder;
}

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

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

Loading…
Cancel
Save