Basics

The following drawing shows the core structure and the basic flow of events in the application. The model is observed by the view models, which interact with the user interface (views). The user input triggers a command, and the commands are executed through the controller that maintains the undo stack. Each command implements the do/undo/redo verbs and encapsulates the logic of some operation and its reversal. The changes are applied to the model (document) when executing the command, and the view models are notified about the resulting changes.

Note the Clockwise Flow of Events

In the above setup, note the clockwise flow of events. The model is observed by various view models, which in turn expose properties that are bound to the user interface in XAML. The view models trigger the execution of commands via the controller. Changes are applied to the document when executing the command, and the view models are notified about the resulting changes, closing the loop.

As a result, the implementation of the model is completely unaware of the user interface details. The deserialization module loads the DOM state from the file, and any change to the elements and their properties triggers notifications. Various view models can subscribe to certain areas of interest in the document. The MVVM principle allows for a clear separation between various interface panels, making it easy to add new components7.
Implementation
The main components of the application are:

  • Model, which resides in Document.dll
  • Modifier commands, which reside in DocumentControl.dll
  • Viewmodels and XAML views in DocumentView.dll
  • The main application, Editor.exe, contains the top-level window layout and initialization code

The model implementation (Document.dll) can be used as an SDK component for creating import and export modules. The model is independent of the Windows Presentation Framework and can be distributed as a .NET Core class library. There is also a separate C++ version of the document model along with XML serialization. This makes the runtime components independent from the desktop tools – even though they can be executed from UI code, there are no linking dependencie.

Integration Example
To access a document in your application, add a reference to the Document.dll to your project.
Code:
WS.Document.Document document;
// load the document from file
document = WS.Document.Library.Load(@"example.shape");
// print top level data items
foreach (WS.Document.DataElement item in document.Data.Children)
{
Console.WriteLine( $"{item.Name} : {item.Content}" );
}
// save the document into file
WS.Document.Library.Save(document, @"modified.shape", false);