
(larger picture)
Contents
The code can be obtained from GitHub, and I've tagged the current code for this article with the tag "FlowSharpCodeComm." Stars are welcome!
FlowSharpCode is a proof of concept of something I've always dreamed of doing -- writing applications as a graphical schematic. In this article, I've put together a simple demonstration of communicating between UI elements on the FlowSharp canvas and an application built with the FlowSharpCode services. The goal here is to introduce the reader to a completely different approach to application development. Think of code as a schematic, complete with annotations, workflows, data pathways, etc. Remember, this is a prototype to inspire the imagination!
In all the articles I've written in the past, I've always had to resort to some diagramming tool (usually Visio) to create a picture of what is going on in the code. No more! Using FlowSharpCode, the diagram is the code. And the UI. Keep that in mind when you read this--that what you are seeing are screenshots of shapes and connectors of code-behind that tell you how the application is wired up.

(from Jesus Christ Superstar)
First off, you have FlowSharp, which is a diagramming tool. On the diagram, you can drop shapes, for example a box with some text:

These shapes can be have code-behind, for example:

The code-behind, using the FlowSharpCode services, gets compiled to (in this case) a console application using Build Compile and Run menu:

And because I write perfect code the first time, all the time, the result is:

Congratulations, you've just written your first FlowSharpCode app!
Using the FlowSharp HTTP and WebSocket services, you can control shape properties on the canvas with your FlowSharpCode application (or any other application.) Here, we use HTTP and this URL:
http:
to change the shape's text:

You can also drop UI elements with one of the FlowSharpCode plug-in shapes:

Very few controls are supported at the moment, but I'm adding more as I go along.
Again using the FlowSharp HTTP or WebSocket services, you can send event messages from the canvas' UI elements to your FlowSharpCode application (or any application, whether it's written with FlowSharpCode or not.) To do this, we need either (or both) a simple HTTP server or WebSocket server, which I'll describe next.

One of the goals of FlowSharpCode is to ensure that you are, as much as possible, not constrained to code in a particular style. This server was something I wrote in FlowSharpCode before I had implemented workflows (more on this later) and is a sort of ugly implementation. I am also leveraging the semantic publisher/subscriber that I wrote about in The Clifton Method - Part IV : The Semantic Publisher / Subscriber.
The code is written in FlowSharpCode since the server has to run as a the FlowSharpCode application. We have the various things you'd expect. These are screenshots, as this is FlowSharpCode and the code is code-behind for the various shapes. In particular, note how partial
classes are leveraged to separate the various code fragments.






Just one in this case:


This is particularly not ideal because typically one would create three separate shapes for this, as well as turn it into a workflow. You'll see this done next for the WebSocket Server! But it does illustrate my point of not being constrained.


This implementation a more "modern" approach, mainly because it uses FlowSharpCode's workflow feature. Here is where you, the developer, are slightly constrained.
Workflows are linear execution of methods, with optional conditions to redirect the execution path. In the above screenshot, there is no "False" execution path, only a "True" one.

All methods in the workflow operate on a packet. The packet contains all the fields that each method in the workflow needs, as well as updates.
Constraints are:
- The workflow name must be
[PacketName]Workflow
- A non-branching workflow always has the signature:
public partial class [PacketName]Workflow
{
protected void [ShapeText]([PacketName] p)
{
... operate on packet p ...
}
}
- A branching workflow always has the signature:
public partial class [PacketName]Workflow
{
protected bool [ShapeText]([PacketName] p)
{
... return true or false based on some state of packet p ...
}
}
OK, I really should have renamed this to WebServerSocketPacket
. Oh well.
Given the above (and the fact that we're using the semantic publisher / subscriber), the web socket server packet is defined like this:

This defines all the fields (as properties) that the workflow requires to handle web socket messages.

When a message is received, the handler fires off the workflow:

So, what does the workflow do?
This is the first step in the workflow. Notice how it complies with the constraints of a workflow step signature, in this case for a decision point:

Here we parse the message, which is in the same format as the parameter portion of an HTTP GET:




The FlowSharpCode service creates this code for you, given your workflow:

Now isn't that just totally cool?

As I described in my article on the semantic publisher / subscriber, there are communication channels (which I call membranes, named after Membrane Computing) and receptors, which is based on my work on Higher Order Programming and Eric Harris-Braun / Arthur Brock's work on Semtrex and Ceptr.
Membranes (or channels, if you prefer) tend to be simple type containers:

The receptor in this case is also simply a placeholder:

The semantic publisher / subscriber invokes handlers for message types. Read more about the concept of semantic types in my article and Matt Perdeck's article. So we need a semantic type for the HTTP and WebSocket messages.


We also need a class that has been registered (more on this later) with the semantic publisher/subscriber that receives these messages:

As the code illustrates, the message is emitted to the console window, and a UI element on the canvas is updated. More on this shortly.
How many times you've clicked (which I haven't shown you yet) on the "send via HTTP" or "send via WebSocket" button is counted in this class.

Now we'll add the final pieces.
Let's glue it all together now. First, there's Main(), which does the startup work:
- Bootstraps the runtime semantic processor module.
- Initializes the servers.
- Registers the receptor.
This could be implemented as a workflow, but again, the programmer is not constrained to code in a particular style, so I decided to just leave this all here in one method:


There are some helper pieces, including the bootstrapper which I wrote about in The Clifton Method - Part III: Bootstrapping with the Module Manager and the Service Manager.
This is a simple class to issue an HTTP request back to FlowSharp.

These two classes put together the data packet that is sent over HTTP or the web socket. They are very similar and could be refactored.


Now here's another really fun part. We put a couple button shapes onto the FlowSharp surface, as well as some plain vanilla text shapes. The button shapes define the semantics and parameters for when they are clicked:

Notice the event name is ButtonClick - this matches the route name!
routes[new Route() {Verb = "GET", Path = "buttonclick"}] =
CreateSemanticObject<AppMembrane, HttpButtonClick>;
Also notice that the send protocol is selected to be "HTTP"

Here notice that the send protocol is "WebSocket." Also notice that the event name is WebSocketButtonClick - this matches directly the semantic type that is instantiated to process this message:

We also have to box shapes, named "cntHttp" and "cntWebSocket":

It should now be clear what this code is doing:

When we run the demo, we get a console app. Clicking on the buttons on the canvas issues HTTP / WebSocket calls to the console application, which in turn issues HTTP/WebSocket calls back to the FlowSharp to update the counter shapes:

If you want to learn more about FlowSharp, please visit FlowSharp article, and particularly the update on the Service Oriented Architecture. For an early prototype of the code compiler services in FlowSharpCode, please visit the FlowSharpCode article.
The WinForm controls are implemented as shapes, for example:
using System.Drawing;
using System.Windows.Forms;
using FlowSharpLib;
namespace FlowSharpWindowsControlShapes
{
public class ButtonShape : ControlShape
{
public ButtonShape(Canvas canvas) : base(canvas)
{
control = new Button();
canvas.Controls.Add(control);
control.Click += OnClick;
}
private void OnClick(object sender, System.EventArgs e)
{
Send(ClickEventName);
}
public override void Draw(Graphics gr)
{
control.Visible = Visible;
if (Visible)
{
base.Draw(gr);
Rectangle r = DisplayRectangle.Grow(-4);
control.Location = r.Location;
control.Size = r.Size;
control.Text = Text;
control.Enabled = Enabled;
}
}
}
}
The Send
method, in the base class, posts the actual HTTP or WebSocket message (hardcoded endpoints!!!):
protected void Send(string cmd)
{
switch (SendProtocol)
{
case SendProtocol.Http:
{
string url = "http://localhost:8002/" + cmd;
string data = "ShapeName=" + Name;
data = AppendData(data);
ServiceManager.Instance.Get<ISemanticProcessor>().ProcessInstance<FlowSharpMembrane, HttpSend>(d =>
{
d.Url = url;
d.Data = data;
}, true);
break;
}
case SendProtocol.WebSocket:
{
string data = "cmd=" + cmd + "&ShapeName=" + Name;
data = AppendData(data);
ServiceManager.Instance.Get<ISemanticProcessor>().ProcessInstance<FlowSharpMembrane, WebSocketSend>(d =>
{
d.Data = data;
}, true);
break;
}
}
}
On the receiver side (here's where the WebSocket messages are processed) we again use the semantic publisher/subscriber to process the message for both HTTP and WebSocket messages:
public class CommandProcessor : IReceptor
{
public void Process(ISemanticProcessor proc, IMembrane membrane, CmdUpdateProperty cmd)
{
BaseController controller = proc.ServiceManager.Get<IFlowSharpCanvasService>().ActiveController;
var els = controller.Elements.Where(e => e.Name == cmd.Name);
els.ForEach(el =>
{
PropertyInfo pi = el.GetType().GetProperty(cmd.PropertyName);
object cval = Converter.Convert(cmd.Value, pi.PropertyType);
el?.Canvas.Invoke(() =>
{
pi.SetValue(el, cval);
controller.Redraw(el);
});
});
}
}

(from Jesus Christ Superstar)
OK, frankly, I think this stuff is the cat's meow. I wish I had tools like this years ago, and I intend to continue developing this concept into a multi-language, multi-platform implementation. But I can't do it without the help of others!