From a4a5df0289537f3d2a732cfc28d02353a7b55951 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 14 Sep 2015 04:08:53 +0300 Subject: [PATCH] Designer: Implemented metadata transfer --- .../AppHost/PerspexAppHost.cs | 85 ++++++++++++++++++- .../Perspex.Designer/Comm/ProcessHost.cs | 6 ++ .../Perspex.Designer/Comm/UpdateMetadata.cs | 20 +++++ .../Metadata/PerspexDesignerMetadata.cs | 51 +++++++++++ .../Perspex.Designer/Perspex.Designer.csproj | 2 + .../Perspex.Designer/PerspexDesigner.xaml.cs | 4 + 6 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 src/Windows/Perspex.Designer/Comm/UpdateMetadata.cs create mode 100644 src/Windows/Perspex.Designer/Metadata/PerspexDesignerMetadata.cs diff --git a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs index 543943a8f6..8e14bb95c2 100644 --- a/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs +++ b/src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs @@ -4,10 +4,13 @@ using System.IO; using System.Linq; using System.Reflection; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Windows.Data; using System.Windows.Forms; using Perspex.Designer.Comm; +using Perspex.Designer.Metadata; +using Timer = System.Windows.Forms.Timer; namespace Perspex.Designer.AppHost { @@ -81,6 +84,84 @@ namespace Perspex.Designer.AppHost UpdateState("Unable to load Perspex:\n\n" + e + "\n\n" + log); } } + + PerspexDesignerMetadata BuildMetadata(List asms) + { + var rv = new PerspexDesignerMetadata() + { + NamespaceAliases = new List + { + new MetadataNamespaceAlias + { + Namespace = "Perspex.Controls", + XmlNamespace = "https://github.com/grokys/Perspex" + } + }, + Types = new List() + }; + foreach (var asm in asms) + { + try + { + foreach (var type in asm.GetTypes()) + { + try + { + if (!type.IsPublic) + continue; + var t = new MetadataType() + { + Name = type.Name, + Namespace = type.Namespace, + Properties = new List() + }; + rv.Types.Add(t); + foreach (var prop in type.GetProperties()) + { + if (prop.GetMethod?.IsPublic != true) + continue; + var p = new MetadataProperty() + { + Name = prop.Name, + Type = + prop.PropertyType == typeof (string) || + (prop.PropertyType.IsValueType && + prop.PropertyType.Assembly == typeof (int).Assembly) + ? MetadataPropertyType.BasicType + : prop.PropertyType.IsEnum + ? MetadataPropertyType.Enum + : MetadataPropertyType.MetadataType + + }; + if (p.Type == MetadataPropertyType.Enum) + p.EnumValues = Enum.GetNames(prop.PropertyType); + if (p.Type == MetadataPropertyType.MetadataType) + p.MetadataFullTypeName = prop.PropertyType.Namespace + "." + prop.PropertyType.Name; + t.Properties.Add(p); + } + } + catch + { + // + } + } + } + catch + { + // + } + } + return rv; + } + + void BuildMetadataAndSendMessageAsync(List asms) + { + new Thread(() => + { + _comm.SendMessage(new UpdateMetadataMessage(BuildMetadata(asms))); + }).Start(); + } + private void DoInit(string targetExe, StringBuilder logger) { _appDir = Path.GetFullPath(Path.GetDirectoryName(targetExe)); @@ -91,16 +172,18 @@ namespace Perspex.Designer.AppHost logger.AppendLine(s); }; log("Loading assemblies from " + _appDir); + var asms = new List(); foreach(var asm in Directory.GetFiles(_appDir).Where(f=>f.ToLower().EndsWith(".dll")||f.ToLower().EndsWith(".exe"))) try { log("Trying to load " + asm); - Assembly.LoadFrom(asm); + asms.Add(Assembly.LoadFrom(asm)); } catch (Exception e) { logger.AppendLine(e.ToString()); } + BuildMetadataAndSendMessageAsync(asms); log("Looking up Perspex types"); var syncContext = LookupType("Perspex.Threading.PerspexSynchronizationContext"); syncContext.GetProperty("AutoInstall", BindingFlags.Public | BindingFlags.Static).SetValue(null, false); diff --git a/src/Windows/Perspex.Designer/Comm/ProcessHost.cs b/src/Windows/Perspex.Designer/Comm/ProcessHost.cs index 0de09a033b..c850521af8 100644 --- a/src/Windows/Perspex.Designer/Comm/ProcessHost.cs +++ b/src/Windows/Perspex.Designer/Comm/ProcessHost.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Threading; +using Perspex.Designer.Metadata; namespace Perspex.Designer.Comm { @@ -28,6 +29,8 @@ namespace Perspex.Designer.Comm } } + public event Action MetadataArrived; + private bool _isAlive; private readonly SynchronizationContext _dispatcher; private Process _proc; @@ -140,6 +143,9 @@ namespace Perspex.Designer.Comm var windowMessage = obj as WindowCreatedMessage; if (windowMessage != null) WindowHandle = windowMessage.Handle; + var metadata = obj as UpdateMetadataMessage; + if (metadata != null) + _dispatcher.Post(_ => MetadataArrived?.Invoke(metadata.Metadata), null); } public void Kill() diff --git a/src/Windows/Perspex.Designer/Comm/UpdateMetadata.cs b/src/Windows/Perspex.Designer/Comm/UpdateMetadata.cs new file mode 100644 index 0000000000..0e1421f154 --- /dev/null +++ b/src/Windows/Perspex.Designer/Comm/UpdateMetadata.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Perspex.Designer.Metadata; + +namespace Perspex.Designer.Comm +{ + [Serializable] + public class UpdateMetadataMessage + { + public UpdateMetadataMessage(PerspexDesignerMetadata metadata) + { + Metadata = metadata; + } + + public PerspexDesignerMetadata Metadata { get; } + } +} diff --git a/src/Windows/Perspex.Designer/Metadata/PerspexDesignerMetadata.cs b/src/Windows/Perspex.Designer/Metadata/PerspexDesignerMetadata.cs new file mode 100644 index 0000000000..653faf01cb --- /dev/null +++ b/src/Windows/Perspex.Designer/Metadata/PerspexDesignerMetadata.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Perspex.Designer.Metadata +{ + [Serializable] + public class PerspexDesignerMetadata + { + public List Types { get; set; } + public List NamespaceAliases { get; set; } + } + + + [Serializable] + public class MetadataType + { + public string Namespace { get; set; } + public string Name { get; set; } + public List Properties { get; set; } + public string FullName => Namespace + "." + Name; + } + + [Serializable] + public class MetadataNamespaceAlias + { + public string Namespace { get; set; } + public string XmlNamespace { get; set; } + } + + [Serializable] + public class MetadataProperty + { + public string Name { get; set; } + public MetadataPropertyType Type { get; set; } + public string MetadataFullTypeName { get; set; } + public string[] EnumValues { get; set; } + } + + + + [Serializable] + public enum MetadataPropertyType + { + BasicType, + MetadataType, + Enum + } +} diff --git a/src/Windows/Perspex.Designer/Perspex.Designer.csproj b/src/Windows/Perspex.Designer/Perspex.Designer.csproj index 61aaa8c901..4cc78fd9be 100644 --- a/src/Windows/Perspex.Designer/Perspex.Designer.csproj +++ b/src/Windows/Perspex.Designer/Perspex.Designer.csproj @@ -74,12 +74,14 @@ + DemoWindow.xaml + PerspexDesigner.xaml diff --git a/src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs b/src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs index 7dbc9c88ac..45ece63e89 100644 --- a/src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs +++ b/src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs @@ -18,6 +18,7 @@ using System.Windows.Navigation; using System.Windows.Shapes; using Perspex.Designer.AppHost; using Perspex.Designer.Comm; +using Perspex.Designer.Metadata; namespace Perspex.Designer { @@ -53,6 +54,8 @@ namespace Perspex.Designer set { SetValue(XamlProperty, value); } } + public PerspexDesignerMetadata Metadata { get; private set; } + private readonly ProcessHost _host = new ProcessHost(); @@ -63,6 +66,7 @@ namespace Perspex.Designer new Binding(nameof(ProcessHost.State)) {Source = _host, Mode = BindingMode.OneWay}); _host.PropertyChanged += _host_PropertyChanged; + _host.MetadataArrived += data => Metadata = data; } private void _host_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)