/
App.xaml.cs
126 lines (103 loc) · 3.99 KB
/
App.xaml.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using System;
using System.CommandLine;
using System.IO.Pipes;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Connection;
using Microsoft.DotNet.Interactive.CSharp;
namespace WpfConnect
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private CompositeKernel _kernel;
private const string NamedPipeName = "InteractiveWpf";
private bool RunOnDispatcher { get; set; }
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
_kernel = new CompositeKernel();
_kernel.UseLogMagicCommand();
SetUpNamedPipeKernelConnection();
AddDispatcherMagicCommand(_kernel);
CSharpKernel csharpKernel = RegisterCSharpKernel();
var _ = Task.Run(async () =>
{
//Load WPF app assembly
await csharpKernel.SendAsync(new SubmitCode(@$"#r ""{typeof(App).Assembly.Location}""
using {nameof(WpfConnect)};"));
//Add the WPF app as a variable that can be accessed
await csharpKernel.SetValueAsync("App", this);
//Start named pipe
_kernel.AddKernelConnector(new ConnectNamedPipeCommand());
});
}
private void SetUpNamedPipeKernelConnection()
{
var serverStream = new NamedPipeServerStream(
NamedPipeName,
PipeDirection.InOut,
1,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous);
var sender = KernelCommandAndEventSender.FromNamedPipe(
serverStream,
new Uri("kernel://remote-control"));
var receiver = KernelCommandAndEventReceiver.FromNamedPipe(serverStream);
var host = _kernel.UseHost(sender, receiver, new Uri("kernel://my-wpf-app"));
_kernel.RegisterForDisposal(host);
_kernel.RegisterForDisposal(receiver);
_kernel.RegisterForDisposal(serverStream);
var _ = Task.Run(() =>
{
// required as waiting connection on named pipe server will block
serverStream.WaitForConnection();
var _ = host.ConnectAsync();
});
}
private void AddDispatcherMagicCommand(Kernel kernel)
{
var enabledOption = new Option<bool>("--enabled", getDefaultValue: () => true);
var dispatcherCommand = new Command("#!dispatcher", "Enable or disable running code on the Dispatcher")
{
enabledOption
};
dispatcherCommand.SetHandler(
enabled => RunOnDispatcher = enabled,
enabledOption);
kernel.AddDirective(dispatcherCommand);
}
private CSharpKernel RegisterCSharpKernel()
{
var csharpKernel = new CSharpKernel()
.UseNugetDirective()
.UseKernelHelpers()
.UseWho()
.UseValueSharing()
//This is added locally
.UseWpf();
_kernel.Add(csharpKernel);
csharpKernel.AddMiddleware(async (KernelCommand command, KernelInvocationContext context, KernelPipelineContinuation next) =>
{
if (RunOnDispatcher)
{
await Dispatcher.InvokeAsync(async () => await next(command, context));
}
else
{
await next(command, context);
}
});
return csharpKernel;
}
protected override void OnExit(ExitEventArgs e)
{
_kernel?.Dispose();
base.OnExit(e);
}
}
}