Browse Source

Merge pull request #456 from Seeker1437/designer-move-patch

Moves Perspex Designer to PerspexVS
issue-457
Steven Kirk 10 years ago
parent
commit
aa87129043
  1. 33
      Perspex.sln
  2. 6
      src/Windows/Perspex.Designer/App.config
  3. 8
      src/Windows/Perspex.Designer/App.xaml
  4. 28
      src/Windows/Perspex.Designer/App.xaml.cs
  5. 100
      src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs
  6. 297
      src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs
  7. 143
      src/Windows/Perspex.Designer/AppHost/WindowHost.cs
  8. 137
      src/Windows/Perspex.Designer/Comm/CommChannel.cs
  9. 18
      src/Windows/Perspex.Designer/Comm/InitMessage.cs
  10. 171
      src/Windows/Perspex.Designer/Comm/ProcessHost.cs
  11. 19
      src/Windows/Perspex.Designer/Comm/StateMessage.cs
  12. 20
      src/Windows/Perspex.Designer/Comm/UpdateMetadata.cs
  13. 19
      src/Windows/Perspex.Designer/Comm/UpdateXamlMessage.cs
  14. 19
      src/Windows/Perspex.Designer/Comm/WindowCreatedMessage.cs
  15. 23
      src/Windows/Perspex.Designer/DemoWindow.xaml
  16. 34
      src/Windows/Perspex.Designer/DemoWindow.xaml.cs
  17. 34
      src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml
  18. 98
      src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml.cs
  19. 51
      src/Windows/Perspex.Designer/Metadata/PerspexDesignerMetadata.cs
  20. 137
      src/Windows/Perspex.Designer/Perspex.Designer.csproj
  21. 17
      src/Windows/Perspex.Designer/PerspexDesigner.xaml
  22. 131
      src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs
  23. 67
      src/Windows/Perspex.Designer/Program.cs
  24. 36
      src/Windows/Perspex.Designer/Properties/AssemblyInfo.cs
  25. 3
      src/Windows/Perspex.Designer/README.txt
  26. 19
      src/Windows/Perspex.Designer/Settings.cs
  27. 33
      src/Windows/Perspex.Designer/WinApi.cs
  28. 4
      src/Windows/Perspex.Designer/packages.config
  29. BIN
      src/Windows/Perspex.Designer/perspex.designer.snk

33
Perspex.sln

@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Win32", "src\Window
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1", "src\Windows\Perspex.Direct2D1\Perspex.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Designer", "src\Windows\Perspex.Designer\Perspex.Designer.csproj", "{EC42600F-049B-43FF-AED1-8314D61B2749}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Input", "src\Perspex.Input\Perspex.Input.csproj", "{62024B2D-53EB-4638-B26B-85EEAA54866E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Interactivity", "src\Perspex.Interactivity\Perspex.Interactivity.csproj", "{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}"
@ -150,20 +148,20 @@ Global
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{78345174-5b52-4a14-b9fd-d5f2428137f0}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{ff69b927-c545-49ae-8e16-3d14d621aa12}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{8c923867-8a8f-4f6b-8b80-47d9e8436166}*SharedItemsImports = 4
samples\TestApplicationShared\TestApplicationShared.projitems*{e3a1060b-50d0-44e8-88b6-f44ef2e5bd72}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
src\Skia\Perspex.Skia\Perspex.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{e1aa3dbf-9056-4530-9376-18119a7a3ffe}*SharedItemsImports = 4
EndGlobalSection
@ -302,30 +300,6 @@ Global
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.Build.0 = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|Any CPU.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhone.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhone.Build.0 = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhone.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhone.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@ -1328,7 +1302,6 @@ Global
GlobalSection(NestedProjects) = preSolution
{811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{EC42600F-049B-43FF-AED1-8314D61B2749} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{47ECDF59-DEF8-4C53-87B1-2098A3429059} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{76716382-3159-460E-BDA6-C5715CF606D7} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}

6
src/Windows/Perspex.Designer/App.config

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
</configuration>

8
src/Windows/Perspex.Designer/App.xaml

@ -1,8 +0,0 @@
<Application x:Class="Perspex.Designer.App" x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" >
</Application>

28
src/Windows/Perspex.Designer/App.xaml.cs

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Perspex.Designer
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
internal partial class App
{
public App()
{
InitializeComponent();
}
}
}

100
src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs

@ -1,100 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using JetBrains.Annotations;
namespace Perspex.Designer.AppHost
{
public class HostedAppModel : INotifyPropertyChanged
{
private readonly PerspexAppHost _host;
private IntPtr _nativeWindowHandle;
private string _error;
private string _errorDetails;
internal HostedAppModel(PerspexAppHost host)
{
_host = host;
Background = Settings.Background;
}
public IntPtr NativeWindowHandle
{
get { return _nativeWindowHandle; }
set
{
if (value.Equals(_nativeWindowHandle)) return;
_nativeWindowHandle = value;
OnPropertyChanged();
}
}
public string Error
{
get { return _error; }
private set
{
if (value == _error) return;
_error = value;
OnPropertyChanged();
}
}
public string ErrorDetails
{
get { return _errorDetails; }
private set
{
if (value == _errorDetails) return;
_errorDetails = value;
OnPropertyChanged();
}
}
public string Background
{
get { return _background; }
set
{
if (value == _background) return;
_background = value;
OnPropertyChanged();
}
}
public IReadOnlyList<double> AvailableScalingFactors => new List<double>() {1, 2, 4, 8};
public double CurrentScalingFactor
{
get { return _currentScalingFactor; }
set
{
_currentScalingFactor = value;
_host.Api.SetScalingFactor(value);
}
}
public void SetError(string error, string details = null)
{
Error = error;
ErrorDetails = details;
}
double _currentScalingFactor = 1;
private string _color;
private string _background;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

297
src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs

@ -1,297 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Xml;
using Perspex.Designer.Comm;
using Perspex.Designer.InProcDesigner;
using Perspex.Designer.Metadata;
using Timer = System.Windows.Forms.Timer;
using Perspex.DesignerSupport;
namespace Perspex.Designer.AppHost
{
class PerspexAppHost
{
private string _appDir;
private readonly CommChannel _comm;
private string _lastXaml;
private string _currentXaml;
private bool _initSuccess;
private readonly HostedAppModel _appModel;
private Control _window;
public PerspexAppHost(CommChannel channel)
{
_comm = channel;
_appModel = new HostedAppModel(this);
}
public void Start()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
_comm.OnMessage += Channel_OnMessage;
_comm.Start();
}
private void Channel_OnMessage(object obj)
{
var init = obj as InitMessage;
if (init != null)
{
Init(init.TargetExe);
}
var updateXaml = obj as UpdateXamlMessage;
if (updateXaml != null)
_currentXaml = updateXaml.Xaml;
}
void UpdateState(string state)
{
_comm.SendMessage(new StateMessage(state));
}
Type LookupType(params string[] names)
{
var asms = AppDomain.CurrentDomain.GetAssemblies();
foreach (var asm in asms)
{
foreach (var name in names)
{
var found = asm.GetType(name, false, true);
if (found != null)
return found;
}
}
throw new TypeLoadException("Unable to find any of types: " + string.Join(",", names));
}
private MethodInfo LookupStaticMethod(string typeName, string method)
{
var type = LookupType(typeName);
var methods = type.GetMethods();
return methods.First(m => m.Name == method);
}
private void Init(string targetExe)
{
var log = new StringBuilder();
try
{
DoInit(targetExe, log);
}
catch (Exception e)
{
UpdateState("Unable to load Perspex:\n\n" + e + "\n\n" + log);
}
}
PerspexDesignerMetadata BuildMetadata(List<Assembly> asms, Type xmlNsAttr)
{
var rv = new PerspexDesignerMetadata()
{
NamespaceAliases = new List<MetadataNamespaceAlias>(),
Types = new List<MetadataType>()
};
foreach (var asm in asms)
{
foreach (dynamic xmlns in asm.GetCustomAttributes().Where(a => a.GetType() == xmlNsAttr))
{
rv.NamespaceAliases.Add(new MetadataNamespaceAlias
{
Namespace = (string)xmlns.ClrNamespace,
XmlNamespace = (string)xmlns.XmlNamespace
});
}
try
{
foreach (var type in asm.GetTypes())
{
try
{
if (!type.IsPublic || type.IsAbstract)
continue;
var t = new MetadataType()
{
Name = type.Name,
Namespace = type.Namespace,
Properties = new List<MetadataProperty>()
};
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<Assembly> asms)
{
var xmlNsAttr = LookupType("Perspex.Metadata.XmlnsDefinitionAttribute");
new Thread(() =>
{
_comm.SendMessage(new UpdateMetadataMessage(BuildMetadata(asms, xmlNsAttr)));
}).Start();
}
private void DoInit(string targetExe, StringBuilder logger)
{
_appDir = Path.GetFullPath(Path.GetDirectoryName(targetExe));
Directory.SetCurrentDirectory(_appDir);
Action<string> log = s =>
{
UpdateState(s);
logger.AppendLine(s);
};
log("Loading assemblies from " + _appDir);
var asms = new List<Assembly>();
foreach(var asm in Directory.GetFiles(_appDir).Where(f=>f.ToLower().EndsWith(".dll")||f.ToLower().EndsWith(".exe")))
try
{
log("Trying to load " + asm);
asms.Add(Assembly.LoadFrom(asm));
}
catch (Exception e)
{
logger.AppendLine(e.ToString());
}
log("Looking up Perspex types");
BuildMetadataAndSendMessageAsync(asms);
log("Initializing built-in designer");
var dic = new Dictionary<string, object>();
Api = new DesignerApi(dic) {OnResize = OnResize, OnWindowCreated = OnWindowCreated};
LookupStaticMethod("Perspex.DesignerSupport.DesignerAssist", "Init").Invoke(null, new object[] {dic});
_window = new Control
{
Controls =
{
new ElementHost()
{
Child = new InProcDesignerView(_appModel),
Dock = DockStyle.Fill
}
}
};
_window.CreateControl();
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)
{
try
{
var rdr = new XmlTextReader(new StringReader(xml));
while (rdr.Read())
{
}
}
catch
{
return false;
}
return true;
}
private void OnResize()
{
}
void XamlUpdater()
{
if (!_initSuccess)
return;
if(_lastXaml == _currentXaml)
return;
_lastXaml = _currentXaml;
if (!ValidateXml(_currentXaml))
{
_appModel.SetError("Invalid markup");
return;
}
try
{
Api.UpdateXaml(_currentXaml);
_appModel.SetError(null);
}
catch (Exception e)
{
_appModel.SetError("XAML load error", e.ToString());
}
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string assemblyPath = Path.Combine(_appDir, new AssemblyName(args.Name).Name + ".dll");
if (File.Exists(assemblyPath) == false) return null;
Assembly assembly = Assembly.LoadFrom(assemblyPath);
return assembly;
}
}
static class Helper
{
public static object Prop(this object obj, string name) => obj.GetType().GetProperty(name).GetValue(obj);
}
}

143
src/Windows/Perspex.Designer/AppHost/WindowHost.cs

@ -1,143 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Perspex.Designer.AppHost
{
class WindowHost : UserControl
{
private readonly bool _supportScroll;
public WindowHost(bool supportScroll)
{
_supportScroll = supportScroll;
if (_supportScroll)
{
AutoScroll = true;
VerticalScroll.Enabled = true;
HorizontalScroll.Enabled = true;
}
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
Controls.Add(_windowHost);
_windowHost.Anchor = AnchorStyles.None;
if (!supportScroll)
_windowHost.Visible = false;
_timer.Tick += delegate
{
ReloadSettings();
FixWindow();
};
}
private void ReloadSettings()
{
var bkg = Settings.Background;
var color = System.Drawing.ColorTranslator.FromHtml(bkg);
if (BackColor != color)
BackColor = color;
}
private readonly Control _windowHost = new Control() {Text = "WindowWrapper"};
private readonly Timer _timer = new Timer {Enabled = true, Interval = 50};
private IntPtr _hWnd;
private int _desiredWidth;
private int _desiredHeight;
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
protected override void WndProc(ref Message m)
{
if ((m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL)
&& (((int) m.WParam & 0xFFFF) == 5))
{
// Change SB_THUMBTRACK to SB_THUMBPOSITION
m.WParam = (IntPtr) (((int) m.WParam & ~0xFFFF) | 4);
}
base.WndProc(ref m);
}
protected override void OnPaint(PaintEventArgs e)
{
using (var b = new SolidBrush(BackColor))
e.Graphics.FillRectangle(b, e.ClipRectangle);
}
void FixPosition()
{
var newScrollSize = new Size(_desiredWidth, _desiredHeight);
if (AutoScrollMinSize != newScrollSize)
AutoScrollMinSize = newScrollSize;
var width = Width - AutoScrollMargin.Width;
var height = Height - AutoScrollMargin.Height;
var x = Math.Max(0, (width - _windowHost.Width)/2);
var y = Math.Max(0, (height - _windowHost.Height)/2);
var newLoc = new Point(x - HorizontalScroll.Value, y - VerticalScroll.Value);
if(_windowHost.Location != newLoc)
_windowHost.Location = newLoc;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_timer.Dispose();
}
base.Dispose(disposing);
}
public void SetWindow(IntPtr hWnd)
{
if (_hWnd != IntPtr.Zero)
WinApi.SendMessage(_hWnd, WinApi.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
_hWnd = hWnd;
if (_hWnd != IntPtr.Zero)
{
WinApi.SetParent(hWnd, _supportScroll ? _windowHost.Handle : Handle);
FixWindow();
}
}
void FixWindow()
{
if (_hWnd != IntPtr.Zero)
{
if (_supportScroll)
{
WinApi.RECT rc;
WinApi.GetWindowRect(_hWnd, out rc);
_desiredWidth = rc.Right - rc.Left;
_desiredHeight = rc.Bottom - rc.Top;
var pt = _windowHost.PointToClient(new Point(rc.Left, rc.Top));
if (
!(pt.Y == 0 && pt.X == 0 && _desiredWidth == _windowHost.Width &&
_desiredHeight == _windowHost.Height))
{
_windowHost.Width = _desiredWidth;
_windowHost.Height = _desiredHeight;
WinApi.MoveWindow(_hWnd, 0, 0, _desiredWidth, _desiredHeight, true);
}
FixPosition();
}
else
{
WinApi.MoveWindow(_hWnd, 0, 0, Width, Height, true);
}
}
}
protected override void OnResize(EventArgs e)
{
FixWindow();
base.OnResize(e);
}
}
}

137
src/Windows/Perspex.Designer/Comm/CommChannel.cs

@ -1,137 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;
namespace Perspex.Designer.Comm
{
class CommChannel : IDisposable
{
private readonly BinaryReader _input;
private readonly BinaryWriter _output;
private readonly SynchronizationContext _dispatcher;
readonly TaskCompletionSource<bool> _terminating = new TaskCompletionSource<bool>();
private readonly BlockingCollection<byte[]> _outputQueue = new BlockingCollection<byte[]>();
public event Action<object> OnMessage;
public event Action Disposed;
public event Action<Exception> Exception;
public CommChannel(Stream input, Stream output)
{
_input = new BinaryReader(input);
_output = new BinaryWriter(output);
_dispatcher = SynchronizationContext.Current;
}
public void Start()
{
new Thread(WriterThread) { IsBackground = true }.Start();
new Thread(ReaderThread) { IsBackground = true }.Start();
}
public void SendMessage(object message)
{
var fmt = GetFormatter();
var ms = new MemoryStream();
fmt.Serialize(ms, message);
_outputQueue.Add(ms.ToArray());
}
void WriterThread()
{
while (!_terminating.Task.IsCompleted)
{
var item = _outputQueue.Take();
if(_terminating.Task.IsCompleted)
return;
try
{
_output.Write(item.Length);
_output.Write(item);
_output.Flush();
}
catch (Exception e)
{
Exception?.Invoke(e);
Dispose();
}
}
}
private async Task<byte[]> ReadAsyncOrNull(int count)
{
var readTask = Task.Factory.StartNew(() => _input.ReadBytes(count));
await Task.WhenAny(readTask, _terminating.Task);
if (_terminating.Task.IsCompleted)
return null;
return await readTask;
}
async void ReaderThread()
{
await Task.Delay(10).ConfigureAwait(false);
var fmt = GetFormatter();
while (!_terminating.Task.IsCompleted)
{
try
{
var lenb = await ReadAsyncOrNull(4);
if (lenb == null)
return;
var data = await ReadAsyncOrNull(BitConverter.ToInt32(lenb, 0));
if (data == null)
return;
var message = fmt.Deserialize(new MemoryStream(data));
_dispatcher.Post(_ => OnMessage?.Invoke(message), null);
}
catch(Exception e)
{
Dispose();
Exception?.Invoke(e);
return;
}
}
}
sealed class BinderFix : SerializationBinder
{
private const string ListNamePrefix = "System.Collections.Generic.List`1[[";
public override Type BindToType(string assemblyName, string typeName)
{
if (typeName.StartsWith(ListNamePrefix))
{
typeName = typeName.Substring(ListNamePrefix.Length);
typeName = typeName.Substring(0, typeName.IndexOf(","));
return typeof (List<>).MakeGenericType(BindToType(assemblyName, typeName));
}
return typeof (CommChannel).Assembly.GetType(typeName, false, true);
}
}
BinaryFormatter GetFormatter()
{
return new BinaryFormatter() {Binder = new BinderFix()};
}
public void Dispose()
{
if(_terminating.Task.IsCompleted)
return;
_terminating.TrySetResult(true);
_outputQueue.Add(null);
Disposed?.Invoke();
}
}
}

18
src/Windows/Perspex.Designer/Comm/InitMessage.cs

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perspex.Designer.Comm
{
[Serializable]
class InitMessage : UpdateXamlMessage
{
public string TargetExe { get; private set; }
public InitMessage(string targetExe, string xaml) : base(xaml)
{
TargetExe = targetExe;
}
}
}

171
src/Windows/Perspex.Designer/Comm/ProcessHost.cs

@ -1,171 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using Perspex.Designer.Metadata;
namespace Perspex.Designer.Comm
{
class ProcessHost : INotifyPropertyChanged
{
private CommChannel _comm;
private string _state;
public string State
{
get { return _state; }
set
{
if (_state == value)
return;
_state = value;
OnPropertyChanged();
}
}
public event Action<PerspexDesignerMetadata> MetadataArrived;
private bool _isAlive;
private readonly SynchronizationContext _dispatcher;
private Process _proc;
public bool IsAlive
{
get { return _isAlive; }
set
{
if (_isAlive == value)
return;
_isAlive = value;
OnPropertyChanged();
}
}
private IntPtr _windowHandle;
public IntPtr WindowHandle
{
get { return _windowHandle; }
set
{
if (_windowHandle == value)
return;
_windowHandle = value;
OnPropertyChanged();
}
}
public ProcessHost()
{
_dispatcher = SynchronizationContext.Current;
}
void OnExited(object sender, EventArgs eventArgs)
{
_proc = null;
_dispatcher.Post(_ =>
{
HandleExited();
}, null);
}
void HandleExited()
{
_comm.Dispose();
IsAlive = false;
WindowHandle = IntPtr.Zero;
State = "Designer process crashed";
}
public void Start(string targetExe, string initialXaml)
{
if (_proc != null)
{
_proc.Exited -= OnExited;
try
{
_proc.Kill();
}
catch { }
HandleExited();
State = "Restarting...";
}
var msg = new InitMessage(Path.GetFullPath(targetExe), initialXaml);
var exe = typeof (ProcessHost).Assembly.GetModules()[0].FullyQualifiedName;
_proc = new Process()
{
StartInfo = new ProcessStartInfo(exe, "--hosted")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
},
EnableRaisingEvents = true
};
_proc.Exited += OnExited;
try
{
_proc.Start();
State = "Launching designer process...";
_comm = new CommChannel(_proc.StandardOutput.BaseStream, _proc.StandardInput.BaseStream);
_comm.OnMessage += OnMessage;
_comm.Start();
_comm.SendMessage(msg);
}
catch (Exception e)
{
State = e.ToString();
HandleExited();
}
IsAlive = true;
}
public void UpdateXaml(string xaml)
{
_comm?.SendMessage(new UpdateXamlMessage(xaml));
}
private void OnMessage(object obj)
{
var stateMessage = obj as StateMessage;
if (stateMessage != null)
State = stateMessage.State;
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()
{
try
{
_proc?.Kill();
_proc = null;
}
catch
{
//
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

19
src/Windows/Perspex.Designer/Comm/StateMessage.cs

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perspex.Designer.Comm
{
[Serializable]
class StateMessage
{
public StateMessage(string state)
{
State = state;
}
public string State { get; private set; }
}
}

20
src/Windows/Perspex.Designer/Comm/UpdateMetadata.cs

@ -1,20 +0,0 @@
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; }
}
}

19
src/Windows/Perspex.Designer/Comm/UpdateXamlMessage.cs

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perspex.Designer.Comm
{
[Serializable]
class UpdateXamlMessage
{
public UpdateXamlMessage(string xaml)
{
Xaml = xaml;
}
public string Xaml { get; private set; }
}
}

19
src/Windows/Perspex.Designer/Comm/WindowCreatedMessage.cs

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perspex.Designer.Comm
{
[Serializable]
class WindowCreatedMessage
{
public WindowCreatedMessage(IntPtr handle)
{
Handle = handle;
}
public IntPtr Handle { get; private set; }
}
}

23
src/Windows/Perspex.Designer/DemoWindow.xaml

@ -1,23 +0,0 @@
<Window x:Class="Perspex.Designer.DemoWindow" x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Perspex.Designer"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<DockPanel LastChildFill="True">
<DockPanel Dock="Bottom" LastChildFill="True">
<TextBlock Margin="5,0">Target Exe: </TextBlock>
<Button DockPanel.Dock="Right">Load XAML</Button>
<Button Margin="5,0" DockPanel.Dock="Right">Select EXE</Button>
<TextBlock x:Name="TargetExe"/>
</DockPanel>
<UniformGrid Columns="1" Rows="2">
<local:PerspexDesigner
TargetExe="{Binding ElementName=TargetExe, Path=Text, Mode=OneWay}"
Xaml="{Binding ElementName=Xaml, Path=Text, Mode=OneWay}"/>
<TextBox x:Name="Xaml"/>
</UniformGrid>
</DockPanel>
</Window>

34
src/Windows/Perspex.Designer/DemoWindow.xaml.cs

@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Perspex.Designer
{
internal partial class DemoWindow
{
public DemoWindow()
{
InitializeComponent();
}
public DemoWindow(string targetExe, string targetPath) : this()
{
TargetExe.Text = targetExe;
if (targetExe != null)
Xaml.Text = File.ReadAllText(targetPath);
}
}
}

34
src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml

@ -1,34 +0,0 @@
<UserControl x:Class="Perspex.Designer.InProcDesigner.InProcDesignerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:appHost="clr-namespace:Perspex.Designer.AppHost"
xmlns:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance appHost:HostedAppModel}">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom">
<ComboBox ItemsSource="{Binding AvailableScalingFactors}" SelectedItem="{Binding CurrentScalingFactor, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type system:Double}">
<TextBlock><Run Text="{Binding .}"/>00%</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Rectangle Cursor="Hand" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}" Fill="{Binding Background}"
Margin="3" MouseDown="ColorPicker_OnClick"/>
<Border x:Name="ErrorPanel" BorderBrush="Red" BorderThickness="3" Padding="3">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Error}" FontSize="16"/>
<TextBlock x:Name="DetailsBlock" FontSize="16">
<Run> (</Run><Hyperlink Click="Hyperlink_OnClick">View details</Hyperlink><Run>)</Run>
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
<WindowsFormsHost x:Name="WindowHostControl"/>
</DockPanel>
</UserControl>

98
src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml.cs

@ -1,98 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Perspex.Designer.AppHost;
using TextBox = System.Windows.Controls.TextBox;
using UserControl = System.Windows.Controls.UserControl;
namespace Perspex.Designer.InProcDesigner
{
/// <summary>
/// Interaction logic for InProcDesignerView.xaml
/// </summary>
public partial class InProcDesignerView : UserControl
{
private readonly HostedAppModel _appModel;
private readonly WindowHost _host;
public InProcDesignerView(HostedAppModel appModel)
{
_appModel = appModel;
InitializeComponent();
DataContext = _appModel;
_appModel.PropertyChanged += ModelPropertyChanged;
WindowHostControl.Child = _host = new WindowHost(true);
HandleVisibility();
HandleWindow();
}
private void ModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(HostedAppModel.Error) || e.PropertyName == nameof(HostedAppModel.ErrorDetails))
HandleVisibility();
if (e.PropertyName == nameof(HostedAppModel.NativeWindowHandle))
HandleWindow();
}
private void HandleWindow()
{
_host.SetWindow(_appModel.NativeWindowHandle);
}
private void HandleVisibility()
{
ErrorPanel.Visibility = string.IsNullOrEmpty(_appModel.Error)
? Visibility.Collapsed
: Visibility.Visible;
DetailsBlock.Visibility = string.IsNullOrWhiteSpace(_appModel.ErrorDetails)
? Visibility.Collapsed
: Visibility.Visible;
}
public InProcDesignerView()
{
}
private void Hyperlink_OnClick(object sender, RoutedEventArgs e)
{
var wnd = new Window()
{
Content = new TextBox()
{
IsReadOnly = true,
AcceptsReturn = true,
TextWrapping = TextWrapping.Wrap,
Text = _appModel.ErrorDetails
}
};
wnd.ShowDialog();
}
private void ColorPicker_OnClick(object sender, MouseButtonEventArgs e)
{
var dlg = new ColorDialog() {Color = ColorTranslator.FromHtml(Settings.Background)};
if (dlg.ShowDialog(_host) == DialogResult.OK)
{
var color = ColorTranslator.ToHtml(dlg.Color);
_appModel.Background = color;
Settings.Background = color;
}
}
}
}

51
src/Windows/Perspex.Designer/Metadata/PerspexDesignerMetadata.cs

@ -1,51 +0,0 @@
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<MetadataType> Types { get; set; }
public List<MetadataNamespaceAlias> NamespaceAliases { get; set; }
}
[Serializable]
public class MetadataType
{
public string Namespace { get; set; }
public string Name { get; set; }
public List<MetadataProperty> 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
}
}

137
src/Windows/Perspex.Designer/Perspex.Designer.csproj

@ -1,137 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EC42600F-049B-43FF-AED1-8314D61B2749}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.Designer</RootNamespace>
<AssemblyName>Perspex.Designer</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>true</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>perspex.designer.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="JetBrains.Annotations, Version=10.0.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\JetBrains.Annotations.10.0.0\lib\net20\JetBrains.Annotations.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
<Reference Include="WindowsFormsIntegration" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Perspex.Application\Designer\DesignerApi.cs">
<Link>AppHost\DesignerApi.cs</Link>
</Compile>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="AppHost\HostedAppModel.cs" />
<Compile Include="AppHost\PerspexAppHost.cs" />
<Compile Include="AppHost\WindowHost.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Comm\CommChannel.cs" />
<Compile Include="Comm\InitMessage.cs" />
<Compile Include="Comm\ProcessHost.cs" />
<Compile Include="Comm\StateMessage.cs" />
<Compile Include="Comm\UpdateMetadata.cs" />
<Compile Include="Comm\UpdateXamlMessage.cs" />
<Compile Include="Comm\WindowCreatedMessage.cs" />
<Compile Include="DemoWindow.xaml.cs">
<DependentUpon>DemoWindow.xaml</DependentUpon>
</Compile>
<Compile Include="InProcDesigner\InProcDesignerView.xaml.cs">
<DependentUpon>InProcDesignerView.xaml</DependentUpon>
</Compile>
<Compile Include="Metadata\PerspexDesignerMetadata.cs" />
<Compile Include="PerspexDesigner.xaml.cs">
<DependentUpon>PerspexDesigner.xaml</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
<Compile Include="WinApi.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="perspex.designer.snk" />
</ItemGroup>
<ItemGroup>
<Page Include="App.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="DemoWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="InProcDesigner\InProcDesignerView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="PerspexDesigner.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Content Include="README.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

17
src/Windows/Perspex.Designer/PerspexDesigner.xaml

@ -1,17 +0,0 @@
<UserControl x:Class="Perspex.Designer.PerspexDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<WindowsFormsHost Background="White" x:Name="NativeContainer" Panel.ZIndex="1"/>
<ScrollViewer VerticalScrollBarVisibility="Auto" Panel.ZIndex="0">
<TextBox IsReadOnly="True" TextWrapping="WrapWithOverflow" x:Name="State"/>
</ScrollViewer>
<StackPanel x:Name="ErrorContainer">
<TextBlock />
</StackPanel>
</Grid>
</UserControl>

131
src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs

@ -1,131 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms.Integration;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Perspex.Designer.AppHost;
using Perspex.Designer.Comm;
using Perspex.Designer.Metadata;
namespace Perspex.Designer
{
/// <summary>
/// Interaction logic for PerpexDesigner.xaml
/// </summary>
public partial class PerspexDesigner
{
public static readonly DependencyProperty TargetExeProperty = DependencyProperty.Register(
"TargetExe", typeof (string), typeof (PerspexDesigner), new FrameworkPropertyMetadata(TargetExeChanged));
private static void TargetExeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((PerspexDesigner) d).RestartProcess();
}
public string TargetExe
{
get { return (string) GetValue(TargetExeProperty); }
set { SetValue(TargetExeProperty, value); }
}
public static readonly DependencyProperty XamlProperty = DependencyProperty.Register(
"Xaml", typeof (string), typeof (PerspexDesigner), new FrameworkPropertyMetadata(XamlChanged));
private static void XamlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((PerspexDesigner) d).OnXamlChanged();
}
public string Xaml
{
get { return (string) GetValue(XamlProperty); }
set { SetValue(XamlProperty, value); }
}
public PerspexDesignerMetadata Metadata { get; private set; }
private readonly ProcessHost _host = new ProcessHost();
public PerspexDesigner()
{
InitializeComponent();
BindingOperations.SetBinding(State, TextBox.TextProperty,
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)
{
if (e.PropertyName == nameof(ProcessHost.WindowHandle))
{
if (NativeContainer.Child != null)
{
var child = NativeContainer.Child;
NativeContainer.Child = null;
child.Dispose();
}
NativeContainer.Child = new WindowHost(false);
var wndHost = ((WindowHost) NativeContainer.Child);
wndHost.SetWindow(_host.WindowHandle);
}
}
public void KillProcess()
{
_host.Kill();
}
bool CheckTargetExeOrSetError()
{
if (string.IsNullOrEmpty(TargetExe))
{
_host.State = "No target exe found";
return false;
}
if (File.Exists(TargetExe ?? ""))
return true;
_host.State = "No target binary found, build your project";
return false;
}
public void RestartProcess()
{
KillProcess();
if(!CheckTargetExeOrSetError())
return;
if(string.IsNullOrEmpty(Xaml))
return;
_host.Start(TargetExe, Xaml);
}
private void OnXamlChanged()
{
if (!CheckTargetExeOrSetError())
return;
if (!_host.IsAlive)
_host.Start(TargetExe, Xaml);
else
_host.UpdateXaml(Xaml ?? "");
}
}
}

67
src/Windows/Perspex.Designer/Program.cs

@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;
using Perspex.Designer.AppHost;
using Perspex.Designer.Comm;
namespace Perspex.Designer
{
class Program
{
[STAThread]
static void Main(string[] args)
{
if (!args.Contains("--hosted"))
DemoMain(args);
else
HostedMain();
}
static void HostedMain()
{
//Initialize sync context
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
var comm = new CommChannel(Console.OpenStandardInput(), Console.OpenStandardOutput());
Console.SetOut(new NullTextWriter());
Console.SetError(new NullTextWriter());
comm.Disposed += () => Process.GetCurrentProcess().Kill();
comm.SendMessage(new StateMessage("Staying awhile and listening..."));
var service = new PerspexAppHost(comm);
service.Start();
Application.Run();
}
class NullTextWriter : TextWriter
{
public override Encoding Encoding => Encoding.UTF8;
public override void Write(char[] buffer, int index, int count)
{
}
public override void Write(char value)
{
}
}
private static void DemoMain(string[] args)
{
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext());
var app = new App();
const string targetExe = "--exe=";
const string xaml = "--xaml=";
app.Run(new DemoWindow(
args.Where(a => a.StartsWith(targetExe)).Select(a => a.Substring(targetExe.Length)).FirstOrDefault(),
args.Where(a => a.StartsWith(xaml)).Select(a => a.Substring(xaml.Length)).FirstOrDefault()));
}
}
}

36
src/Windows/Perspex.Designer/Properties/AssemblyInfo.cs

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Perspex.Designer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.Designer")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ec42600f-049b-43ff-aed1-8314d61b2749")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

3
src/Windows/Perspex.Designer/README.txt

@ -1,3 +0,0 @@
To load data from XamlTestApplication run with:
--exe=..\..\..\..\..\samples\XamlTestApplication\bin\Debug\XamlTestApplication.exe --xaml=..\..\..\..\..\samples\XamlTestApplication\Views\MainWindow.xaml

19
src/Windows/Perspex.Designer/Settings.cs

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace Perspex.Designer
{
static class Settings
{
static readonly string Root = @"HKEY_CURRENT_USER\Software\PerspexUI\Designer";
public static string Background
{
get { return Registry.GetValue(Root, "Background", "#f3f3f3")?.ToString() ?? "#f3f3f3"; }
set { Registry.SetValue(Root, "Background", value); }
}
}
}

33
src/Windows/Perspex.Designer/WinApi.cs

@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Perspex.Designer
{
class WinApi
{
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32.dll")]
public static extern bool SetParent(IntPtr hWnd, IntPtr hWndNewParent);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public const uint WM_CLOSE = 0x0010;
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
}
}

4
src/Windows/Perspex.Designer/packages.config

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="JetBrains.Annotations" version="10.0.0" targetFramework="net45" />
</packages>

BIN
src/Windows/Perspex.Designer/perspex.designer.snk

Binary file not shown.
Loading…
Cancel
Save