I'm in the process of building an open-source tiling window manager applications similar to i3wm/bspwm. Would hopefully look something like this, but for Windows. There's a little bar at the top of the screen that shows your "workspaces" and you can click on a workspace to show its windows.
At the moment, there's 3 projects in my solution: Bar, Window Manager and Common. The Window Manager project holds state of workspaces etc. and has commands that Bar is supposed to trigger. Common just holds infrastructure shared between the 2 projects like a CommandBus
for facilitating communication between projects.
The Bar project consists of something like this:
public LaunchBar()
{
// Launch WPF app.
InitializeComponent();
// Bind current workspaces to template.
workspaces.ItemsSource = workspaceRepository.GetWorkspaces(); // workspaceRepository exists in Window Manager project
}
private void OnWorkspaceClick()
{
commandBus.Invoke(new ChangeWorkspaceCommand()); // ChangeWorkspaceCommand exists in Window Manager project
}
The idea is that LaunchBar
is called programmatically within the Window Manager project when a new monitor is detected. However, this results in a circular reference between the two projects.
How can I go about structuring this project to avoid circular references? Fairly gosh darn stuck here.
You need to decouple WindowManager
from Bar
.
If Bar
needs to access the window manager functionality. Use an event/delegate and let the window manager subscribe so it can action what ever it needs on Bar
. or create an interface that is common between them so you can pass down that contract to bar.
Either way, you will need to refactor this in a way that logical dependent projects only take care of responsibility that makes sense for them at that level.
Think about it, a builder hires a bricklayer. The bricklayer doesn't and shouldn't have any knowledge of the accounting software the builder uses, he just gives back an invoice when the work is done (an event), he doesn't call enter invoice, or pay contractor on the accounts software. The accounts lady does what she needs, and gives a wage to the bricklayer (or what ever).
In short the bricklayer has an event, or they share a predetermined common contract (interface), which is to say, if bar has an IWindowManager
interface it can call GetWorkspaces().
Anyway, only you have the ability to logically split this up without circular references, and what makes sense to you