29 changed files with 3 additions and 1702 deletions
@ -1,6 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<configuration> |
|||
<startup> |
|||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> |
|||
</startup> |
|||
</configuration> |
|||
@ -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> |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
@ -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)); |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
|
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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)); |
|||
} |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -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; } |
|||
} |
|||
} |
|||
@ -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> |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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> |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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 |
|||
} |
|||
} |
|||
@ -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> |
|||
@ -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> |
|||
@ -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 ?? ""); |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -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())); |
|||
} |
|||
} |
|||
} |
|||
@ -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")] |
|||
@ -1,3 +0,0 @@ |
|||
To load data from XamlTestApplication run with: |
|||
|
|||
--exe=..\..\..\..\..\samples\XamlTestApplication\bin\Debug\XamlTestApplication.exe --xaml=..\..\..\..\..\samples\XamlTestApplication\Views\MainWindow.xaml |
|||
@ -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); } |
|||
} |
|||
} |
|||
} |
|||
@ -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
|
|||
} |
|||
} |
|||
} |
|||
@ -1,4 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<packages> |
|||
<package id="JetBrains.Annotations" version="10.0.0" targetFramework="net45" /> |
|||
</packages> |
|||
Binary file not shown.
Loading…
Reference in new issue