- Create a presentation layer as a dynamic library. Install the
ImageProcessing.Microkernel.EntryPoint
from Nuget. Add an implementation of theIStartup
interface, create folders for presenters/events/views/viewmodels. - Define a new interface for your main view. It should implement the
IView
interface. - Create a new presenter for your main view. Inherit it from the
BasePresenter<TView>
. Create a new domain event and subscribe it to the main presenter with theISubscriber<TEventArgs>
interface. - Create an executing assembly. Reference the presentation library. It can be a console, WPF or WinForms project. Add an implementation of the
IStartup
interface for the UI Layer components. - In case of WF or WPF, create a base form to handle write/read from another thread or access the aggregator or application controller. Create a property for the application controller. Set it with the
AppController.Controller
. Using theController.IoC
property register theApplicationContext
/Application
as a singleton then resolve it and bind to theContext
property. You can do it once via the null reference check with the private field. Hide theShow
with thenew
syntax then set theMainForm
asthis
. Pass the Context to theApplication.Run
. - Implement the
IMainView
interface for your main form. In case of WF/WPF use theAggregator.Unpublish
inside theDispose
/Close
call. Hide the generated dispose with thenew
syntax then replace if a view is a transient, or remove it in the case of a singleton, delegating the disposing call to a DI-container. - Inject the singleton instance of the
IEventAggregator
into your main form or expose elements to a custom event binder component. Bind the defined domain event. - Register the implemented presentation startup dependecies with the
new Startup().Build(builder)
inside theUIStartup
. Register the main view and its event binder. You can declare the main view as a singleton to inject it to child views and access control properties via the exposer cast. - Inside the Program class use the static state machine to
AppLifecycle.Build<UIStartup>
andAppLifecycle.Run<MainPresenter>
.
- Use
Run<TPresenter>
orRun<TPresenter, TViewModel>
to run a presenter. When aView
accessed for the first time, a DI - container resolve the view by its interface, decoupling a concrete implementation of a gui framework (WF, WPF, Console) component. - Use
PublishFrom<TEventArgs>(object publisher, TEventArgs args)
to unicast a message from a view to its presenter. - Use
PublishFromAll<TEventArgs>(object publisher, TEventArgs args)
to broadcast a message from a view to all presenters subscribed to theTEventArgs
. It can also be used to message from a presenter to a presenter if a target presenter have a unique subscriber during the broadcast. - Use
Unsubscribe(Type subscriber, object publisher)
to unsubcribe a view from its presenter. Can be used during the disposing of a view.
- Generate or create virtual wrappers around the original components. If a component has a composition with another wrapper, expose its interface as a public property. Extend the original forms with NonUIForms, overriding the write/read methods. Inside a form wrapper create a bridge with a NonUIForm.
- Inside a presenter use the original source code, operating with partial substitutes. Expose substitutes as a public property.
- Extend the
SynchronizationContext
, override the Post property. Override the Post inside the aggregator, set the extendedSynchronizationContext
. Replace the original aggregator with its wrapper..Result
the.ConfigureAwait(false)
calls. - Using the fluent interface, build the partial substitutes with the virtual wrappers to operate with the original components by default.
- Create a base test, use the static state machine to
Build
partial substitutes and toDispose
on the[TearDown]
. - Write a synchronous scenario using partial substitutes. Raise an event from a form wrapper. Use
.Receieved()
interface to validate arguments and return values.
Fig. 1 - The main MDI - form and child transient forms and the singleton form. The main menu also shows the message from the singleton form.
Fig. 2 - The main form and child SDI transient forms and the singleton form. The main menu also shows the message from the singleton form.
Fig. 3 - The main form and child TDI transient tabs and the singleton tab. The main menu also shows the message from the singleton tab. To close the tab focus the "Send Message" button and press the Del key.
Fig. 4 - The main window and child transient windows and the singleton window. The main window also shows the message from the singleton window.
Fig. 5 - The console window is started with the main command and then the singleton command is switched to a foreground thread.