From 991e42143783beda359295f39695a16c52fe787d Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 26 Nov 2015 23:31:16 +0300 Subject: [PATCH] Now using built-in designer API instead of dynamic calls --- .../Perspex.Android/AndroidPlatform.cs | 22 +++++- src/Gtk/Perspex.Gtk/GtkPlatform.cs | 19 ++++- .../Perspex.Markup.Xaml.csproj | 4 - src/Perspex.Application/Designer/Designer.cs | 58 ++++++++++++++ .../Designer/DesignerApi.cs | 51 ++++++++++++ .../Perspex.Application.csproj | 19 ++++- src/Perspex.Base/Perspex.Base.csproj | 1 + .../Platform/IAssetLoader.cs | 0 src/Perspex.Controls/Perspex.Controls.csproj | 1 + .../Platform/IWindowingPlatform.cs | 15 ++++ .../Platform/PlatformManager.cs | 14 +++- .../AppHost/PerspexAppHost.cs | 77 ++++++------------- .../Perspex.Designer/Perspex.Designer.csproj | 3 + src/Windows/Perspex.Win32/Win32Platform.cs | 35 +++++---- src/iOS/Perspex.iOS/PerspexAppDelegate.cs | 27 ++++++- 15 files changed, 261 insertions(+), 85 deletions(-) create mode 100644 src/Perspex.Application/Designer/Designer.cs create mode 100644 src/Perspex.Application/Designer/DesignerApi.cs rename src/{Perspex.Application => Perspex.Base}/Platform/IAssetLoader.cs (100%) create mode 100644 src/Perspex.Controls/Platform/IWindowingPlatform.cs diff --git a/src/Android/Perspex.Android/AndroidPlatform.cs b/src/Android/Perspex.Android/AndroidPlatform.cs index b3f4bdaa32..9276cba150 100644 --- a/src/Android/Perspex.Android/AndroidPlatform.cs +++ b/src/Android/Perspex.Android/AndroidPlatform.cs @@ -10,10 +10,11 @@ using Perspex.Shared.PlatformSupport; using Perspex.Skia; using System; using System.Collections.Generic; +using Perspex.Android.Platform.SkiaPlatform; namespace Perspex.Android { - public class AndroidPlatform : IPlatformSettings + public class AndroidPlatform : IPlatformSettings, IWindowingPlatform { public static readonly AndroidPlatform Instance = new AndroidPlatform(); public Size DoubleClickSize => new Size(4, 4); @@ -33,11 +34,11 @@ namespace Perspex.Android .Bind().ToConstant(this) .Bind().ToConstant(new AndroidThreadingInterface()) .Bind().ToTransient() - .Bind().ToTransient(); + .Bind().ToTransient() + .Bind().ToConstant(this); SkiaPlatform.Initialize(); Application.RegisterPlatformCallback(() => { }); - PerspexLocator.CurrentMutable.Bind().ToSingleton(); _scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity; @@ -50,5 +51,20 @@ namespace Perspex.Android { SharedPlatform.Register(applicationType.Assembly); } + + public IWindowImpl CreateWindow() + { + return new WindowImpl(); + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + throw new NotImplementedException(); + } + + public IPopupImpl CreatePopup() + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/Gtk/Perspex.Gtk/GtkPlatform.cs b/src/Gtk/Perspex.Gtk/GtkPlatform.cs index 16ba905589..014048854d 100644 --- a/src/Gtk/Perspex.Gtk/GtkPlatform.cs +++ b/src/Gtk/Perspex.Gtk/GtkPlatform.cs @@ -14,7 +14,7 @@ namespace Perspex.Gtk { using Gtk = global::Gtk; - public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings + public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform { private static readonly GtkPlatform s_instance = new GtkPlatform(); private static Thread _uiThread; @@ -33,8 +33,7 @@ namespace Perspex.Gtk public static void Initialize() { PerspexLocator.CurrentMutable - .Bind().ToTransient() - .Bind().ToTransient() + .Bind().ToConstant(s_instance) .Bind().ToSingleton() .Bind().ToConstant(CursorFactory.Instance) .Bind().ToConstant(GtkKeyboardDevice.Instance) @@ -86,5 +85,19 @@ namespace Perspex.Gtk public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread; public event Action Signaled; + public IWindowImpl CreateWindow() + { + return new WindowImpl(); + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + throw new NotSupportedException(); + } + + public IPopupImpl CreatePopup() + { + return new PopupImpl(); + } } } \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj index 35fde7d0e4..9b8cb35162 100644 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj @@ -272,10 +272,6 @@ {D211E587-D8BC-45B9-95A4-F297C8FA5200} Perspex.Animation - - {799A7BB5-3C2C-48B6-85A7-406A12C420DA} - Perspex.Application - {B09B78D8-9B26-48B0-9149-D64A2F120F3F} Perspex.Base diff --git a/src/Perspex.Application/Designer/Designer.cs b/src/Perspex.Application/Designer/Designer.cs new file mode 100644 index 0000000000..665eb3447f --- /dev/null +++ b/src/Perspex.Application/Designer/Designer.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OmniXaml; +using Perspex.Controls; +using Perspex.Controls.Platform; +using Perspex.Markup.Xaml; +using Perspex.Themes.Default; + +namespace Perspex.Designer +{ + class Designer + { + class DesignerApp : Application + { + public DesignerApp() + { + RegisterServices(); + //For now we only support windows + InitializeSubsystems(2); + Styles = new DefaultTheme(); + } + } + + public static DesignerApi Api { get; set; } + + public static void Init(Dictionary shared) + { + Api = new DesignerApi(shared) {UpdateXaml = UpdateXaml}; + new DesignerApp(); + } + + static Window s_currentWindow; + + private static void UpdateXaml(string xaml) + { + + Window window; + using (PlatformManager.DesignerMode()) + { + var obj = ((XamlXmlLoader)new PerspexXamlLoader()).Load(new MemoryStream(Encoding.UTF8.GetBytes(xaml))); + window = obj as Window; + if (window == null) + { + window = new Window() {Content = obj}; + } + } + s_currentWindow?.Close(); + s_currentWindow = window; + window.Show(); + Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle); + Api.OnResize?.Invoke(); + } + } +} diff --git a/src/Perspex.Application/Designer/DesignerApi.cs b/src/Perspex.Application/Designer/DesignerApi.cs new file mode 100644 index 0000000000..944bd86705 --- /dev/null +++ b/src/Perspex.Application/Designer/DesignerApi.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Designer +{ + class DesignerApi + { + private readonly Dictionary _inner; + + public DesignerApi(Dictionary inner) + { + _inner = inner; + } + + object Get([CallerMemberName] string name = null) + { + object rv; + _inner.TryGetValue(name, out rv); + return rv; + } + + void Set(object value, [CallerMemberName] string name = null) + { + _inner[name] = value; + } + + public Action UpdateXaml + { + get { return (Action) Get(); } + set {Set(value); } + } + + public Action OnResize + { + get { return (Action) Get(); } + set { Set(value);} + } + + public Action OnWindowCreated + { + set { Set(value); } + get { return (Action) Get(); } + } + + + } +} diff --git a/src/Perspex.Application/Perspex.Application.csproj b/src/Perspex.Application/Perspex.Application.csproj index c5fe995636..08ecf9912e 100644 --- a/src/Perspex.Application/Perspex.Application.csproj +++ b/src/Perspex.Application/Perspex.Application.csproj @@ -39,6 +39,18 @@ + + {3e53a01a-b331-47f3-b828-4a5717e77a24} + Perspex.Markup.Xaml + + + {6417e941-21bc-467b-a771-0de389353ce6} + Perspex.Markup + + + {d211e587-d8bc-45b9-95a4-f297c8fa5200} + Perspex.Animation + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} Perspex.Base @@ -67,13 +79,18 @@ {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} Perspex.Styling + + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F} + Perspex.Themes.Default + Properties\SharedAssemblyInfo.cs - + + diff --git a/src/Perspex.Base/Perspex.Base.csproj b/src/Perspex.Base/Perspex.Base.csproj index 890fa666bf..deeb85a600 100644 --- a/src/Perspex.Base/Perspex.Base.csproj +++ b/src/Perspex.Base/Perspex.Base.csproj @@ -53,6 +53,7 @@ + diff --git a/src/Perspex.Application/Platform/IAssetLoader.cs b/src/Perspex.Base/Platform/IAssetLoader.cs similarity index 100% rename from src/Perspex.Application/Platform/IAssetLoader.cs rename to src/Perspex.Base/Platform/IAssetLoader.cs diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj index a99b3fbbfd..80b1aba585 100644 --- a/src/Perspex.Controls/Perspex.Controls.csproj +++ b/src/Perspex.Controls/Perspex.Controls.csproj @@ -44,6 +44,7 @@ + diff --git a/src/Perspex.Controls/Platform/IWindowingPlatform.cs b/src/Perspex.Controls/Platform/IWindowingPlatform.cs new file mode 100644 index 0000000000..99176b720e --- /dev/null +++ b/src/Perspex.Controls/Platform/IWindowingPlatform.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Platform +{ + public interface IWindowingPlatform + { + IWindowImpl CreateWindow(); + IWindowImpl CreateDesignerFriendlyWindow(); + IPopupImpl CreatePopup(); + } +} diff --git a/src/Perspex.Controls/Platform/PlatformManager.cs b/src/Perspex.Controls/Platform/PlatformManager.cs index ba239d1a46..4983fc0483 100644 --- a/src/Perspex.Controls/Platform/PlatformManager.cs +++ b/src/Perspex.Controls/Platform/PlatformManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Disposables; using System.Text; using System.Threading.Tasks; using Perspex.Input; @@ -17,6 +18,8 @@ namespace Perspex.Controls.Platform static IPlatformSettings GetSettings() => PerspexLocator.Current.GetService(); + static bool s_designerMode; + public static IRenderTarget CreateRenderTarget(ITopLevelImpl window) { return @@ -24,6 +27,11 @@ namespace Perspex.Controls.Platform PerspexLocator.Current.GetService().CreateRenderer(window.Handle), window); } + public static IDisposable DesignerMode() + { + s_designerMode = true; + return Disposable.Create(() => s_designerMode = false); + } class RenderTargetDecorator : IRenderTarget { @@ -165,12 +173,14 @@ namespace Perspex.Controls.Platform public static IWindowImpl CreateWindow() { - return new WindowDecorator(PerspexLocator.Current.GetService()); + var platform = PerspexLocator.Current.GetService(); + return + new WindowDecorator(s_designerMode ? platform.CreateDesignerFriendlyWindow() : platform.CreateWindow()); } public static IPopupImpl CreatePopup() { - return new WindowDecorator(PerspexLocator.Current.GetService()); + return new WindowDecorator(PerspexLocator.Current.GetService().CreatePopup()); } } } diff --git a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs index 8cc1dc5096..0def6e0f3e 100644 --- a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs +++ b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs @@ -18,12 +18,11 @@ namespace Perspex.Designer.AppHost class PerspexAppHost { private string _appDir; - private CommChannel _comm; + private readonly CommChannel _comm; private string _lastXaml; private string _currentXaml; - private Func _xamlReader; private bool _initSuccess; - private HostedAppModel _appModel = new HostedAppModel(); + private readonly HostedAppModel _appModel = new HostedAppModel(); private Control _window; public PerspexAppHost(CommChannel channel) @@ -92,8 +91,6 @@ namespace Perspex.Designer.AppHost PerspexDesignerMetadata BuildMetadata(List asms, Type xmlNsAttr) { - - var rv = new PerspexDesignerMetadata() { @@ -200,34 +197,10 @@ namespace Perspex.Designer.AppHost log("Looking up Perspex types"); BuildMetadataAndSendMessageAsync(asms); - var syncContext = LookupType("Perspex.Threading.PerspexSynchronizationContext"); - syncContext.GetProperty("AutoInstall", BindingFlags.Public | BindingFlags.Static).SetValue(null, false); - - var app = Activator.CreateInstance(LookupType("Perspex.Application")); - app.GetType() - .GetMethod("RegisterServices", BindingFlags.NonPublic | BindingFlags.Instance) - .Invoke(app, null); - - LookupStaticMethod("Perspex.Direct2D1.Direct2D1Platform", "Initialize").Invoke(null, null); - LookupStaticMethod("Perspex.Win32.Win32Platform", "InitializeEmbedded").Invoke(null, null); - - app.GetType().GetProperty("Styles").GetSetMethod(true) - .Invoke(app, new[] {Activator.CreateInstance(LookupType("Perspex.Themes.Default.DefaultTheme"))}); - - - dynamic dispatcher = - LookupType("Perspex.Threading.Dispatcher") - .GetProperty("UIThread", BindingFlags.Static | BindingFlags.Public) - .GetValue(null); - - - - var xamlFactory = Activator.CreateInstance(LookupType("Perspex.Markup.Xaml.Context.PerspexParserFactory")); - - dynamic xamlLoader = - LookupType("OmniXaml.XamlLoader", "OmniXaml.XamlXmlLoader").GetConstructors().First().Invoke(new object[] {xamlFactory}); - - _xamlReader = (stream) => xamlLoader.Load(stream); + log("Initializing built-in designer"); + var dic = new Dictionary(); + Api = new DesignerApi(dic) {OnResize = OnResize, OnWindowCreated = OnWindowCreated}; + LookupStaticMethod("Perspex.Designer.Designer", "Init").Invoke(null, new object[] {dic}); _window = new Control { @@ -242,15 +215,19 @@ namespace Perspex.Designer.AppHost }; _window.CreateControl(); - new Timer {Interval = 10, Enabled = true}.Tick += delegate - { - dispatcher.RunJobs(); - }; new Timer {Interval = 200, Enabled = true}.Tick += delegate { XamlUpdater(); }; _comm.SendMessage(new WindowCreatedMessage(_window.Handle)); _initSuccess = true; } + private void OnWindowCreated(IntPtr hWnd) + { + _appModel.NativeWindowHandle = hWnd; + } + + + public DesignerApi Api { get; set; } + bool ValidateXml(string xml) { @@ -269,6 +246,11 @@ namespace Perspex.Designer.AppHost return true; } + private void OnResize() + { + + } + void XamlUpdater() { if (!_initSuccess) @@ -282,27 +264,10 @@ namespace Perspex.Designer.AppHost _appModel.SetError("Invalid markup"); return; } - - try { - const string windowType = "Perspex.Controls.Window"; - - var root = _xamlReader(new MemoryStream(Encoding.UTF8.GetBytes(_currentXaml))); - dynamic window = root; - if (root.GetType().FullName != windowType) - { - window = Activator.CreateInstance(LookupType(windowType)); - window.Content = root; - } + Api.UpdateXaml(_currentXaml); - var w = ((object) (window.PlatformImpl)).Prop("Handle"); - if (!(w is IntPtr)) - w = w.Prop("Handle"); - - var hWnd = (IntPtr) w; - _appModel.NativeWindowHandle = hWnd; - window.Show(); _appModel.SetError(null); } catch (Exception e) @@ -310,6 +275,8 @@ namespace Perspex.Designer.AppHost _appModel.SetError("XAML load error", e.ToString()); } } + + private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { diff --git a/src/Windows/Perspex.Designer/Perspex.Designer.csproj b/src/Windows/Perspex.Designer/Perspex.Designer.csproj index f5dd8bd8ac..abb50a5279 100644 --- a/src/Windows/Perspex.Designer/Perspex.Designer.csproj +++ b/src/Windows/Perspex.Designer/Perspex.Designer.csproj @@ -67,6 +67,9 @@ + + AppHost\DesignerApi.cs + App.xaml diff --git a/src/Windows/Perspex.Win32/Win32Platform.cs b/src/Windows/Perspex.Win32/Win32Platform.cs index e461e95de3..5c8c475f17 100644 --- a/src/Windows/Perspex.Win32/Win32Platform.cs +++ b/src/Windows/Perspex.Win32/Win32Platform.cs @@ -18,7 +18,7 @@ using Perspex.Win32.Interop; namespace Perspex.Win32 { - public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings + public class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform { private static readonly Win32Platform s_instance = new Win32Platform(); private static Thread _uiThread; @@ -42,34 +42,22 @@ namespace Perspex.Win32 public double RenderScalingFactor { get; } = 1; public double LayoutScalingFactor { get; } = 1; - private static void InitializeInternal() + public static void Initialize() { PerspexLocator.CurrentMutable - .Bind().ToTransient() .Bind().ToSingleton() .Bind().ToConstant(CursorFactory.Instance) .Bind().ToConstant(WindowsKeyboardDevice.Instance) .Bind().ToConstant(WindowsMouseDevice.Instance) .Bind().ToConstant(s_instance) .Bind().ToConstant(s_instance) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(s_instance); SharedPlatform.Register(); _uiThread = Thread.CurrentThread; } - public static void Initialize() - { - PerspexLocator.CurrentMutable.Bind().ToTransient(); - InitializeInternal(); - } - - public static void InitializeEmbedded() - { - PerspexLocator.CurrentMutable.Bind().ToTransient(); - InitializeInternal(); - } - public bool HasMessages() { UnmanagedMethods.MSG msg; @@ -169,5 +157,20 @@ namespace Perspex.Win32 throw new Win32Exception(); } } + + public IWindowImpl CreateWindow() + { + return new WindowImpl(); + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + return new EmbeddedWindowImpl(); + } + + public IPopupImpl CreatePopup() + { + return new PopupImpl(); + } } } diff --git a/src/iOS/Perspex.iOS/PerspexAppDelegate.cs b/src/iOS/Perspex.iOS/PerspexAppDelegate.cs index c0296d077c..e526f3a69c 100644 --- a/src/iOS/Perspex.iOS/PerspexAppDelegate.cs +++ b/src/iOS/Perspex.iOS/PerspexAppDelegate.cs @@ -42,9 +42,34 @@ namespace Perspex.iOS .Bind().ToConstant(MouseDevice) .Bind().ToSingleton() .Bind().ToConstant(PlatformThreadingInterface.Instance) - .Bind().ToConstant(controller.PerspexView); + .Bind().ToConstant(new WindowingPlatform(controller.PerspexView)); SkiaPlatform.Initialize(); }); } + + class WindowingPlatform : IWindowingPlatform + { + private readonly IWindowImpl _window; + + public WindowingPlatform(IWindowImpl window) + { + _window = window; + } + + public IWindowImpl CreateWindow() + { + return _window; + } + + public IWindowImpl CreateDesignerFriendlyWindow() + { + throw new NotImplementedException(); + } + + public IPopupImpl CreatePopup() + { + throw new NotImplementedException(); + } + } } }