Plato is a MVVM compliant 2D on-canvas graphics framework I've been designing and implementing for developing Windows Store apps.
The major functionalities of the framework have been implemented. But they are yet to go through a more thorough testing and further verification through usage. The library is shared open source on codeplex at https://plato2d.codeplex.com/
The framework is designed to be
The framework is mainly composed of the following components,
The major purpose of the pipeline, which is also that of the whole Plato framework, is to determine which models (data objects) should have their view models and models added to the system and therefore displayed on the screen whereas which shouldn't.
Any model change whether it be
will fire an event to the entity(entites) that eventually implements IModelProvider to get it to update the visible list as well as pass the event on to for instance the view model to update the appearance of the view accordingly.
The Visual department is responsible for
- view world conversion (ISightManager)
- hit and rectangular selection management
- various visual object dimension measuring for the Core Pipeline department and others (like FitAll)
- ...
Now the particular problem I was facing and this article is discussing is how to fit into this framework the case where the visual size of the object cannot be deduced from the model side of the pipeline which is a natural assumption of this framework.
A concrete example is how we deal with text elements. The scenario is like below
To address this is issue now we need to enrich the Visual department with the functionalities other than the sight management listed above which if no such complexity is involved we can live without.
Before integrating this machanism the frame work is like
o IModelProvider
ModelChangedEvent |
Model --------------------> ModelManager ------------ > ViewModelManager ------> ViewManager
| ^ |...| Binding |...|
| | ViewModel -----------> View (on Canvas)
| | -----o ISightManager (Update dimensions etc)
| VisualBounds |
----------------------> VisualTraits
NOTE the events propagation and processing in this framework (except the View/ViewModel interactions) are entirely synchronous and on-stack. Because as far as this can work this is the most efficient. Ensuring this can work means endless recursive calls are avoided and dependencies are resolved.
The whole framework becomes
o IModelProvider
ModelChangedEvent (a) |
Model --------------------> ModelManager ------------ > ViewModelManager ------> ViewManager
^ | ^ |...| Binding |...|
| | | ViewModel <-----------> View (on Canvas)
| | VisualToMeasure | -----o ISightManager | (Update dimensions etc)
| | request | |
| ----------------------> VisualTraits <-----------------------|
| reset VisualToMeasure(c) |
| |
------------------------------------------------------------------
Reinitiate ModelChange for invalid bounds with/without VisualToMeasure(b)
(a) Model initiates VisualToMeasure flagged change event whenever a bounds changing condition happens and bounds become invalid
(b) The view model updates the visual bounds of the model on it; whether or not it should cancel the VisualToMeasure depending on if it's certain that it has got the final results. But it should eventually resets it to give the object the chance to be taken off from the pipeline as appropriate. And it is the only legimitate entity to do so.
(c) One easy and safe way to do so is -
Every time the dimension updater in the view model is invoked normally by either the model update handler or view layout change handler,
Implementation-wise, it's been found that one needs to be cautious with tying up the feedback handler with the LayoutUpdated event of the view as it's easy to create suspicious cyclic calls, which would be detected by the system first.
The only apparent defect is that the view and viewmodel will remain in the pipeline until the next time it's interogated, which happens when the view changes. However this happens quite often and is almost a perfectly justifiable time to decide whether the object should be swapped out of the pipeline. (The major unlikely scenario this could become an issue is when a large number of such objects outside the view scope are changing with view scope not changing at all, which is most likely caused by undo/redo operations, in which case the creation and retention of the unnecessary view/view model objects continue until a view change is made)
Reviews and Criticisms
One of the major downsides/limitations of this framework is that to make the visual adjustment feedback work it still has to have strong coupling between visual/view sections and the model management which potentially restricts or complicates the extension of the archecture to a distributed setting. This will be discussed in the follow up article The design of a distributed variant of Plato framework to support collaborated editing