1
0
Эх сурвалжийг харах

Added AppBuilder

Use AppBuilder to configure the Application and make sure that
everything is set up in the correct order.
Steven Kirk 9 жил өмнө
parent
commit
d79fc6bbd8

+ 8 - 5
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()

+ 1 - 1
samples/BindingTest/MainWindow.xaml.cs

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

+ 20 - 0
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>

+ 23 - 16
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;
         }
     }
 }

+ 2 - 6
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;
         }
     }
-
-
 }

+ 6 - 4
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);
+        }
     }
 }

+ 1 - 3
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);
         }
     }
 }

+ 4 - 19
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();
         }

+ 5 - 5
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 - 0
samples/XamlTestApplicationPcl/XamlTestApp.cs

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

+ 80 - 0
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();
+        }
+    }
+}

+ 7 - 7
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 - 0
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" />

+ 4 - 3
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;
         }
     }
 }

+ 4 - 3
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;
         }
     }
 }

+ 0 - 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;
-        }
-    }
-}

+ 4 - 3
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;
         }
     }
 }

+ 4 - 3
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;
         }
     }
 }

+ 4 - 3
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;
         }
     }
 }

+ 6 - 13
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;
         }
     }
 }

+ 5 - 4
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 - 0
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;
         }