Browse Source

Added AppBuilder

Use AppBuilder to configure the Application and make sure that
everything is set up in the correct order.
pull/537/head
Steven Kirk 10 years ago
parent
commit
d79fc6bbd8
  1. 13
      samples/BindingTest/App.xaml.cs
  2. 2
      samples/BindingTest/MainWindow.xaml.cs
  3. 20
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  4. 39
      samples/ControlCatalog.Desktop/Program.cs
  5. 8
      samples/ControlCatalog.iOS/AppDelegate.cs
  6. 10
      samples/ControlCatalog/App.xaml.cs
  7. 4
      samples/ControlCatalog/MainWindow.xaml.cs
  8. 23
      samples/TestApplication/Program.cs
  9. 10
      samples/XamlTestApplication/Program.cs
  10. 5
      samples/XamlTestApplicationPcl/XamlTestApp.cs
  11. 80
      src/Avalonia.Controls/AppBuilder.cs
  12. 14
      src/Avalonia.Controls/Application.cs
  13. 1
      src/Avalonia.Controls/Avalonia.Controls.csproj
  14. 7
      src/Gtk/Avalonia.Cairo/CairoPlatform.cs
  15. 7
      src/Gtk/Avalonia.Gtk/GtkPlatform.cs
  16. 12
      src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs
  17. 7
      src/Skia/Avalonia.Skia/SkiaPlatform.cs
  18. 7
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  19. 7
      src/Windows/Avalonia.Win32/Win32Platform.cs
  20. 19
      src/iOS/Avalonia.iOS/iOSPlatform.cs
  21. 9
      src/iOS/Avalonia.iOSTestApplication/AppDelegate.cs
  22. 1
      tests/Avalonia.UnitTests/UnitTestApplication.cs

13
samples/BindingTest/App.xaml.cs

@ -1,7 +1,6 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Diagnostics;
using Avalonia.Logging.Serilog;
using Avalonia.Markup.Xaml;
using Serilog;
@ -15,15 +14,19 @@ namespace BindingTest
RegisterServices();
}
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
private static void Main()
{
InitializeLogging();
new App()
AppBuilder.Configure<App>()
.UseWin32()
.UseDirect2D()
.LoadFromXaml()
.RunWithMainWindow<MainWindow>();
.UseDirect2D1()
.Start<MainWindow>();
}
private static void InitializeLogging()

2
samples/BindingTest/MainWindow.xaml.cs

@ -16,7 +16,7 @@ namespace BindingTest
private void InitializeComponent()
{
this.LoadFromXaml();
AvaloniaXamlLoader.Load(this);
}
}
}

20
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -75,6 +75,10 @@
<Project>{6417E941-21BC-467B-A771-0DE389353CE6}</Project>
<Name>Avalonia.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Avalonia.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Avalonia.Base</Name>
@ -83,10 +87,26 @@
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Avalonia.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Logging.Serilog\Avalonia.Logging.Serilog.csproj">
<Project>{B61B66A3-B82D-4875-8001-89D3394FE0C9}</Project>
<Name>Avalonia.Logging.Serilog</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Avalonia.Styling</Name>

39
samples/ControlCatalog.Desktop/Program.cs

@ -1,10 +1,10 @@
using Avalonia.Logging.Serilog;
using Serilog;
using System;
using System.Linq;
using Avalonia;
using System.Reflection;
using Avalonia.Controls;
using Avalonia.Logging.Serilog;
using Avalonia.Platform;
using Serilog;
namespace ControlCatalog
{
@ -14,10 +14,12 @@ namespace ControlCatalog
{
InitializeLogging();
new App()
.ConfigureRenderSystem(args)
.LoadFromXaml()
.RunWithMainWindow<MainWindow>();
// TODO: Make this work with GTK/Skia/Cairo depending on command-line args
// again.
AppBuilder.Configure<App>()
.UseWin32()
.UseDirect2D1()
.Start<MainWindow>();
}
// This will be made into a runtime configuration extension soon!
@ -31,6 +33,12 @@ namespace ControlCatalog
#endif
}
private static void ConfigureAssetAssembly(AppBuilder builder)
{
AvaloniaLocator.CurrentMutable
.GetService<IAssetLoader>()
.SetDefaultAssembly(typeof(App).Assembly);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -96,33 +104,32 @@ namespace ControlCatalog
/// <summary>
/// Selects the optimal render system for desktop platforms. Supports cmd line overrides
/// </summary>
/// <param name="app"></param>
/// <param name="builder"></param>
/// <param name="args"></param>
public static TApp ConfigureRenderSystem<TApp>(this TApp app, string[] args) where TApp : Application
public static AppBuilder ConfigureRenderSystem(this AppBuilder builder, string[] args)
{
// So this all works great under Windows where it can support
// ALL configurations. But on OSX/Unix we cannot use Direct2D
//
if (args.Contains("--gtk") || DefaultRenderSystem() == RenderSystem.GTK)
{
app.UseGtk();
app.UseCairo();
builder.UseGtk();
builder.UseCairo();
}
else
{
app.UseWin32();
builder.UseWin32();
if (args.Contains("--skia") || DefaultRenderSystem() == RenderSystem.Skia)
{
app.UseSkia();
builder.UseSkia();
}
else
{
app.UseDirect2D();
builder.UseDirect2D1();
}
}
return app;
return builder;
}
}
}

8
samples/ControlCatalog.iOS/AppDelegate.cs

@ -19,17 +19,13 @@ namespace ControlCatalog
//
public override bool FinishedLaunching(UIApplication uiapp, NSDictionary options)
{
new App()
AppBuilder.Configure<App>()
.UseiOS()
.UseSkiaViewHost()
.UseSkia()
.UseAssetAssembly(typeof(App).Assembly)
.LoadFromXaml()
.RunWithMainWindow<MainWindow>();
.Start<MainWindow>();
return true;
}
}
}

10
samples/ControlCatalog/App.xaml.cs

@ -1,16 +1,18 @@
using Avalonia;
using Avalonia.Markup.Xaml;
namespace ControlCatalog
{
// Eventually we should move this into a PCL library so we can access
// from mobile platforms
//
public class App : Application
{
public App()
{
RegisterServices();
}
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
}
}

4
samples/ControlCatalog/MainWindow.xaml.cs

@ -19,9 +19,7 @@ namespace ControlCatalog
// now I am doing that here. But we need a better solution!!
var theme = new Avalonia.Themes.Default.DefaultTheme();
theme.FindResource("Button");
this.LoadFromXaml();
AvaloniaXamlLoader.Load(this);
}
}
}

23
samples/TestApplication/Program.cs

@ -34,25 +34,10 @@ namespace TestApplication
var app = new App();
if (args.Contains("--gtk"))
{
app.UseGtk();
app.UseCairo();
}
else
{
app.UseWin32();
// not available until we do the SkiaSharp merge
//if (args.Contains("--skia"))
//{
// app.UseSkia();
//}
//else
{
app.UseDirect2D();
}
}
AppBuilder.Configure(app)
.UseWin32()
.UseDirect2D1()
.SetupWithoutStarting();
app.Run();
}

10
samples/XamlTestApplication/Program.cs

@ -7,6 +7,7 @@ using System.Windows.Threading;
using Avalonia;
using Serilog;
using Avalonia.Logging.Serilog;
using Avalonia.Controls;
namespace XamlTestApplication
{
@ -19,11 +20,10 @@ namespace XamlTestApplication
InitializeLogging();
new XamlTestApp()
.UseWin32()
.UseDirect2D()
.LoadFromXaml()
.RunWithMainWindow<Views.MainWindow>();
AppBuilder.Configure<XamlTestApp>()
.UseWin32()
.UseDirect2D1()
.Start<Views.MainWindow>();
}
private static void InitializeLogging()

5
samples/XamlTestApplicationPcl/XamlTestApp.cs

@ -10,5 +10,10 @@ namespace XamlTestApplication
{
RegisterServices();
}
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
}
}

80
src/Avalonia.Controls/AppBuilder.cs

@ -0,0 +1,80 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Input;
using System;
namespace Avalonia.Controls
{
public class AppBuilder
{
public Application Instance { get; set; }
public Action WindowingSubsystem { get; set; }
public Action RenderingSubsystem { get; set; }
public Action<AppBuilder> BeforeStartCallback { get; set; }
public static AppBuilder Configure<TApp>()
where TApp : Application, new()
{
return Configure(new TApp());
}
public static AppBuilder Configure(Application app)
{
AvaloniaLocator.CurrentMutable.BindToSelf(app);
return new AppBuilder()
{
Instance = app,
};
}
public AppBuilder BeforeStarting(Action<AppBuilder> callback)
{
BeforeStartCallback = callback;
return this;
}
public void Start<TMainWindow>()
where TMainWindow : Window, new()
{
Setup();
BeforeStartCallback?.Invoke(this);
var window = new TMainWindow();
window.Show();
Instance.Run(window);
}
public AppBuilder SetupWithoutStarting()
{
Setup();
return this;
}
public void Setup()
{
if (Instance == null)
{
throw new InvalidOperationException("No App instance configured.");
}
if (WindowingSubsystem == null)
{
throw new InvalidOperationException("No windowing system configured.");
}
if (RenderingSubsystem == null)
{
throw new InvalidOperationException("No rendering system configured.");
}
WindowingSubsystem();
RenderingSubsystem();
Instance.Initialize();
}
}
}

14
src/Avalonia.Controls/Application.cs

@ -50,12 +50,6 @@ namespace Avalonia
/// </summary>
public Application()
{
if (Current != null)
{
throw new InvalidOperationException("Cannot create more than one Application instance.");
}
AvaloniaLocator.CurrentMutable.BindToSelf(this);
OnExit += OnExiting;
}
@ -132,6 +126,13 @@ namespace Avalonia
_platformInitializationCallback = cb;
}
/// <summary>
/// Initializes the application by loading XAML etc.
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// Runs the application's main loop until the <see cref="ICloseable"/> is closed.
/// </summary>
@ -165,7 +166,6 @@ namespace Avalonia
/// <param name="e"></param>
protected virtual void OnExiting(object sender, EventArgs e)
{
}
/// <summary>

1
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -43,6 +43,7 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AppBuilder.cs" />
<Compile Include="Application.cs" />
<Compile Include="Classes.cs" />
<Compile Include="ContextMenu.cs" />

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

@ -6,15 +6,16 @@ using Avalonia.Cairo.Media;
using Avalonia.Cairo.Media.Imaging;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Controls;
namespace Avalonia
{
public static class GtkApplicationExtensions
{
public static TApp UseCairo<TApp>(this TApp app) where TApp : Application
public static AppBuilder UseCairo(this AppBuilder builder)
{
Avalonia.Cairo.CairoPlatform.Initialize();
return app;
builder.RenderingSubsystem = Avalonia.Cairo.CairoPlatform.Initialize;
return builder;
}
}
}

7
src/Gtk/Avalonia.Gtk/GtkPlatform.cs

@ -9,15 +9,16 @@ using Avalonia.Input.Platform;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Avalonia.Controls;
namespace Avalonia
{
public static class GtkApplicationExtensions
{
public static TApp UseGtk<TApp>(this TApp app) where TApp : Application
public static AppBuilder UseGtk(this AppBuilder builder)
{
Avalonia.Gtk.GtkPlatform.Initialize();
return app;
builder.WindowingSubsystem = Avalonia.Gtk.GtkPlatform.Initialize;
return builder;
}
}
}

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

@ -223,15 +223,3 @@ namespace Avalonia.Markup.Xaml
}
}
}
namespace Avalonia
{
public static class XamlObjectExtensions
{
public static TObject LoadFromXaml<TObject>(this TObject obj)
{
Markup.Xaml.AvaloniaXamlLoader.Load(obj);
return obj;
}
}
}

7
src/Skia/Avalonia.Skia/SkiaPlatform.cs

@ -1,16 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Controls;
using Avalonia.Platform;
namespace Avalonia
{
public static class SkiaApplicationExtensions
{
public static TApp UseSkia<TApp>(this TApp app) where TApp : Application
public static AppBuilder UseSkia(this AppBuilder builder)
{
Avalonia.Skia.SkiaPlatform.Initialize();
return app;
builder.RenderingSubsystem = Avalonia.Skia.SkiaPlatform.Initialize;
return builder;
}
}
}

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

@ -6,15 +6,16 @@ using System.IO;
using Avalonia.Direct2D1.Media;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Controls;
namespace Avalonia
{
public static class Direct2DApplicationExtensions
{
public static TApp UseDirect2D<TApp>(this TApp app) where TApp : Application
public static AppBuilder UseDirect2D1(this AppBuilder builder)
{
Avalonia.Direct2D1.Direct2D1Platform.Initialize();
return app;
builder.RenderingSubsystem = Avalonia.Direct2D1.Direct2D1Platform.Initialize;
return builder;
}
}
}

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

@ -15,15 +15,16 @@ using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using Avalonia.Controls;
namespace Avalonia
{
public static class Win32ApplicationExtensions
{
public static TApp UseWin32<TApp>(this TApp app) where TApp : Application
public static AppBuilder UseWin32(this AppBuilder builder)
{
Avalonia.Win32.Win32Platform.Initialize();
return app;
builder.WindowingSubsystem = Avalonia.Win32.Win32Platform.Initialize;
return builder;
}
}
}

19
src/iOS/Avalonia.iOS/iOSPlatform.cs

@ -7,19 +7,20 @@ using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Avalonia.Skia;
using UIKit;
using Avalonia.Controls;
namespace Avalonia
{
public static class iOSApplicationExtensions
{
public static AppT UseiOS<AppT>(this AppT app) where AppT : Application
public static AppBuilder UseiOS(this AppBuilder builder)
{
Avalonia.iOS.iOSPlatform.Initialize();
return app;
builder.WindowingSubsystem = Avalonia.iOS.iOSPlatform.Initialize;
return builder;
}
// TODO: Can we merge this with UseSkia somehow once HW/platform cleanup is done?
public static AppT UseSkiaViewHost<AppT>(this AppT app) where AppT : Application
public static AppBuilder UseSkiaViewHost(this AppBuilder builder)
{
var window = new UIWindow(UIScreen.MainScreen.Bounds);
var controller = new AvaloniaViewController(window);
@ -31,15 +32,7 @@ namespace Avalonia
SkiaPlatform.Initialize();
return app;
}
public static AppT UseAssetAssembly<AppT>(this AppT app, Assembly assembly) where AppT : Application
{
// Asset loading searches our own assembly?
var loader = new AssetLoader(assembly);
AvaloniaLocator.CurrentMutable.Bind<IAssetLoader>().ToConstant(loader);
return app;
return builder;
}
}
}

9
src/iOS/Avalonia.iOSTestApplication/AppDelegate.cs

@ -27,13 +27,14 @@ namespace Avalonia.iOSTestApplication
//
public override bool FinishedLaunching(UIApplication uiapp, NSDictionary options)
{
var app = new App()
var app = new App();
AppBuilder.Configure(app)
.UseiOS()
.UseSkiaViewHost()
.UseSkia();
.UseSkia()
.SetupWithoutStarting();
var asm = typeof(App).Assembly;
app.UseAssetAssembly(asm);
app.Run();
return true;

1
tests/Avalonia.UnitTests/UnitTestApplication.cs

@ -33,6 +33,7 @@ namespace Avalonia.UnitTests
{
var scope = AvaloniaLocator.EnterScope();
var app = new UnitTestApplication(services);
AvaloniaLocator.CurrentMutable.BindToSelf<Application>(app);
return scope;
}

Loading…
Cancel
Save