FormsManager
Current runtime reference for form orchestration, helper-manager composition, and UnitOfWork integration
DataManagementEngineStandard/Editor/Forms/FormsManager.csand partialsDataManagementEngineStandard/Editor/Forms/Interfacesruntime interface contractsDataManagementEngineStandard/Editor/Forms/README.mdDataManagementEngineStandard/Editor/Forms/MIGRATION-GUIDE.md
- This page reflects the audited FormsManager runtime surface and current public naming.
- FormsManager is the orchestration runtime;
IUnitofWorkremains the persistence and dirty-state authority. - Built-in runtime operations, triggers, LOV orchestration, audit, security, paging, and multi-form flows are implemented in code.
FormsManager owns runtime orchestration and state semantics. Canvases, tab pages, cursor movement, LOV dialog rendering, and message-area rendering remain host-UI responsibilities.
Table of Contents
- Overview
- Runtime Ownership
- Signature Snapshot
- Partial-Class Topology
- Helper Manager Surface
- Form Lifecycle and Mode Transitions
- Block Registration and CRUD Flow
- Key Generation and Record Creation
- Built-in Runtime Operations
- Multi-Form, Globals, and Messaging
- Triggers, Validation, and LOVs
- Audit, Security, and Performance
- Coverage Snapshot
- Known Boundaries and Hardening Areas
- Related Documentation
Overview
FormsManager is the BeepDM form-orchestration runtime in the
TheTechIdea.Beep.Editor.UOWManager namespace. It coordinates block registration,
current-block state, navigation, query-mode and CRUD-mode transitions, master/detail synchronization,
triggers, LOV application, savepoints, locks, audit capture, security enforcement, paging, cache control,
and multi-form communication.
The current public runtime surface is documented here under the FormsManager name.
- Current public runtime surface and partial-class layout
- Caller-facing helper managers and orchestration boundaries
- Mode transitions, CRUD flows, and built-in runtime operations
- Examples for explicit keys, sequences, identity keys, defaults, audit, security, and paging
Runtime Ownership
| Concern | FormsManager | IUnitofWork |
|---|---|---|
| Block orchestration | Registers blocks, tracks current form and block, manages relationships | No |
| Navigation and modes | Owns query mode, CRUD mode, record navigation, history, and block switching | No |
| Persistence | Coordinates when to save, rollback, validate, or fire triggers | Executes insert, update, delete, commit, rollback, and query operations |
| Dirty-state truth | Aggregates state across blocks and relationships | Owns per-block dirty tracking |
| Identity and sequence refresh | Coordinates key strategy during create and insert flows | Owns datasource-backed identity refresh and real sequence interaction |
| UI responsibilities | Provides runtime state and semantics | Not applicable |
Signature Snapshot
Representative public surface
public partial class FormsManager
{
public IDMEEditor DMEEditor { get; }
public string CurrentFormName { get; set; }
public string CurrentBlockName { get; set; }
public IReadOnlyDictionary<string, DataBlockInfo> Blocks { get; }
public bool IsDirty { get; }
public int BlockCount { get; }
public IDirtyStateManager DirtyStateManager { get; }
public IPerformanceManager PerformanceManager { get; }
public ISystemVariablesManager SystemVariables { get; }
public IValidationManager Validation { get; }
public ILOVManager LOV { get; }
public IItemPropertyManager ItemProperties { get; }
public ITriggerManager Triggers { get; }
public ISavepointManager Savepoints { get; }
public ILockManager Locking { get; }
public IQueryBuilderManager QueryBuilder { get; }
public IMessageQueueManager Messages { get; }
public IBlockPropertyManager BlockProperties { get; }
public ISequenceProvider Sequences { get; }
public ITimerManager Timers { get; }
public IFormRegistry Registry { get; }
public IFormMessageBus MessageBus { get; }
public ISharedBlockManager SharedBlocks { get; }
public IAuditManager AuditManager { get; }
public ISecurityManager Security { get; }
public IPagingManager Paging { get; }
public FormsManager(IDMEEditor dmeEditor, ...);
public void RegisterBlock<T>(...);
public DataBlockInfo GetBlock<T>(string blockName);
public Task<bool> InsertRecordAsync<T>(string blockName, T record = default);
public Task<LOVResult> ShowLOVAsync(...);
public Task<bool> OpenFormAsync(string formName);
public Task<IErrorsInfo> CommitFormAsync();
public Task<IErrorsInfo> RollbackFormAsync();
public Task<IErrorsInfo> EnterQueryModeAsync(string blockName);
public Task<IErrorsInfo> ExecuteQueryAndEnterCrudModeAsync(string blockName, List<AppFilter> filters = null);
public Task<bool> FirstRecordAsync(string blockName);
public Task<bool> NextRecordAsync(string blockName);
public Task<bool> PreviousRecordAsync(string blockName);
public Task<bool> LastRecordAsync(string blockName);
public Task<bool> NavigateToRecordAsync(string blockName, int recordIndex);
}
Partial-Class Topology
| File | Responsibility |
|---|---|
FormsManager.cs | Core registration, DI wiring, properties, relationship ownership, and block metadata |
FormsManager.FormOperations.cs | Open, close, commit, rollback, clear-form, and clear-block orchestration |
FormsManager.Navigation.cs | Record navigation, block switching, history, and GO_BLOCK-style behavior |
FormsManager.ModeTransitions.cs | ENTER_QUERY, EXECUTE_QUERY, and CRUD-mode transitions |
FormsManager.EnhancedOperations.cs | Insert, update, delete, audit defaults, and enhanced CRUD orchestration |
FormsManager.DataOperations.cs | Undo/redo, duplicate record, batch commit, export/import, aggregates, and state persistence |
FormsManager.GenericOperations.cs | Typed block registration, typed insert, typed block access, and ShowLOVAsync |
FormsManager.BlockProperties.cs | SET_BLOCK_PROPERTY and GET_BLOCK_PROPERTY wrappers |
FormsManager.Alerts.cs | MESSAGE, alert, confirm, and info-dialog orchestration |
FormsManager.Sequences.cs | Sequences, item defaults, copy-field behavior, and record-group helpers |
FormsManager.Timers.cs | CREATE_TIMER, DELETE_TIMER, timer inspection, and trigger integration |
FormsManager.MultiFormNavigation.cs | CALL_FORM, modeless OPEN_FORM, NEW_FORM, and return-to-caller |
FormsManager.InterFormComm.cs | :GLOBAL.*, parameter handoff, message bus, and shared blocks |
FormsManager.KeyTriggers.cs | KEY-* trigger registration and default key-action helpers |
FormsManager.TriggerChaining.cs | Trigger dependency graph, chain mode, and execution logging |
FormsManager.DmlTriggers.cs | ON-INSERT, ON-UPDATE, ON-DELETE, and programmatic trigger raising |
FormsManager.Audit.cs | Audit configuration, audit querying, export, and purge behavior |
FormsManager.Security.cs | Security context, block security, field security, and masking |
FormsManager.Performance.cs | Paging, fetch-ahead, cache invalidation, cache stats, and performance wiring |
Helper Manager Surface
FormsManager exposes most subsystem capabilities through helper properties so callers can use low-level behavior without re-implementing orchestration. In normal application code, start with FormsManager entry points and reach for helper managers only when you need custom registration or inspection behavior.
| Property | Interface | Purpose |
|---|---|---|
DirtyStateManager | IDirtyStateManager | Aggregates unsaved changes, related dirty blocks, and save or rollback decisions |
PerformanceManager | IPerformanceManager | Cache and performance metrics infrastructure |
SystemVariables | ISystemVariablesManager | :SYSTEM.* runtime variables |
Validation | IValidationManager | Item, record, block, and form validation rules |
LOV | ILOVManager | LOV registration, datasource loading, caching, filtering, and value validation |
ItemProperties | IItemPropertyManager | Enabled, visible, read-only, tab order, and field metadata behavior |
Triggers | ITriggerManager | Trigger registration, ordering, scope resolution, and async execution |
Savepoints | ISavepointManager | Named snapshots and rollback targets |
Locking | ILockManager | Client-side record locking and auto-lock behavior |
QueryBuilder | IQueryBuilderManager | Reusable filter and query templates for blocks |
ErrorLog | IBlockErrorLog | Per-block runtime error tracking without UI coupling |
Messages | IMessageQueueManager | Status and informational message queue for host UI consumption |
BlockFactory | IBlockFactory | Builds UnitOfWork and entity metadata pairs from configured connections |
BlockProperties | IBlockPropertyManager | Backs SET_BLOCK_PROPERTY and GET_BLOCK_PROPERTY |
AlertProvider | IAlertProvider | Host-UI alert bridge for ShowAlertAsync, ConfirmAsync, and info prompts |
Sequences | ISequenceProvider | In-memory sequence support and deterministic test flows |
Timers | ITimerManager | Named timer lifecycle and WHEN-TIMER-EXPIRED integration |
Registry | IFormRegistry | Active-form registry for modal and modeless multi-form flows |
MessageBus | IFormMessageBus | Publish, subscribe, and broadcast form messages |
SharedBlocks | ISharedBlockManager | Cross-form shared UnitOfWork-backed blocks |
AuditManager | IAuditManager | Audit capture, history queries, grouped flush, and storage integration |
Security | ISecurityManager | Block security, field security, masking, and violation logging |
Paging | IPagingManager | Page size, total-record count, current page, and fetch-ahead tracking |
Use FormsManager methods for orchestration entry points like commit, rollback, query, navigation, and LOV application. Use helper managers for registration, inspection, custom rule wiring, or host-specific integration.
Form Lifecycle and Mode Transitions
The normal lifecycle is open form, register blocks, enter query mode when needed, execute a query, navigate, edit, and commit or rollback through a single form-level orchestration point.
Lifecycle example
var manager = new FormsManager(dmeEditor)
{
CurrentFormName = "CUSTOMER_ORDERS"
};
await manager.OpenFormAsync("CUSTOMER_ORDERS");
await manager.EnterQueryModeAsync("CUSTOMERS");
var filters = new List<AppFilter>
{
new AppFilter { FieldName = "Country", Operator = "=", FilterValue = "USA" }
};
await manager.ExecuteQueryAndEnterCrudModeAsync("CUSTOMERS", filters);
await manager.FirstRecordAsync("CUSTOMERS");
await manager.NextRecordAsync("CUSTOMERS");
var result = await manager.CommitFormAsync();
if (result.Flag != Errors.Ok)
{
await manager.RollbackFormAsync();
}
| Operation | Method | Notes |
|---|---|---|
| Open current form runtime | OpenFormAsync(string formName) | Initializes the current form lifecycle and state |
| Close current form | CloseFormAsync() | Performs shutdown orchestration and cleanup |
| Enter query mode | EnterQueryModeAsync(string blockName) | Switches the target block into query mode |
| Execute query and return to CRUD mode | ExecuteQueryAndEnterCrudModeAsync(...) | Runs filters, reloads block data, then restores normal editing mode |
| Navigate records | FirstRecordAsync, NextRecordAsync, PreviousRecordAsync, LastRecordAsync, NavigateToRecordAsync, GoRecordAsync | Validation and history are part of the orchestration path |
| Switch blocks and items | SwitchToBlockAsync, GoBlockAsync, NextBlockAsync, PreviousBlockAsync, GoItemAsync, NextItemAsync, PreviousItemAsync | Updates current block context, item focus metadata, and block-instance behavior |
| Commit form | CommitFormAsync() | Runs validation, trigger wiring, dirty-state save, audit flush, and lock cleanup |
| Rollback form | RollbackFormAsync() | Restores dirty blocks and clears transient state |
Block Registration and CRUD Flow
Prefer typed registration so FormsManager can create records with the correct CLR type, use typed accessors, and keep new-record flows compatible with validation, LOVs, audit, and key generation.
Typed block registration and master-detail wiring
manager.RegisterBlock<CustomerDto>(
blockName: "CUSTOMERS",
unitOfWork: customerUow,
entityStructure: customerEntity,
dataSourceName: "Northwind",
isMasterBlock: true);
manager.RegisterBlock<OrderDto>(
blockName: "ORDERS",
unitOfWork: orderUow,
entityStructure: orderEntity,
dataSourceName: "Northwind");
manager.CreateMasterDetailRelation(
masterBlockName: "CUSTOMERS",
detailBlockName: "ORDERS",
masterKeyField: "CustomerId",
detailForeignKeyField: "CustomerId");
var orderBlock = manager.GetBlock<OrderDto>("ORDERS");
await manager.InsertRecordAsync<OrderDto>("ORDERS", new OrderDto { Status = "Draft" });
Duplicate, export, and import
await manager.DuplicateCurrentRecordAsync("ORDERS");
using var jsonStream = new MemoryStream();
await manager.ExportBlockToJsonAsync("ORDERS", jsonStream);
jsonStream.Position = 0;
await manager.ImportBlockFromJsonAsync("ORDERS_ARCHIVE", jsonStream, clearFirst: true);
Relationship registration, key resolution, and detail synchronization are FormsManager concerns. Keep UnitOfWork focused on entity persistence rather than relationship orchestration.
Key Generation and Record Creation
Key handling is part of the new-record and insert pipeline. FormsManager coordinates the strategy, but the datasource-backed UnitOfWork remains the authority for persisted identities and real sequence refresh.
- Preserve explicit keys supplied by caller, default factory, or trigger.
- Leave datasource-managed identity keys unset until insert or commit refresh completes.
- Prefer datasource or UnitOfWork sequence generation before the in-memory FormsManager sequence provider.
- Use FormsManager sequences for deterministic tests or non-database-backed flows.
- Handle composite keys field by field.
- Do not allocate keys during query, paging, navigation, or cache prefetch.
Explicit key preserved
await manager.InsertRecordAsync<CustomerDto>("CUSTOMERS", new CustomerDto
{
CustomerId = "ALFKI",
CompanyName = "Alfreds Futterkiste"
});
Sequence-backed key
manager.SetItemDefault("ORDERS", "Status", () => "Draft");
var nextNumber = manager.GetNextSequence("ORDER_SEQ");
await manager.InsertRecordAsync<OrderDto>("ORDERS", new OrderDto
{
OrderNumber = nextNumber,
CustomerId = "ALFKI"
});
Datasource identity key
await manager.InsertRecordAsync<OrderLineDto>("ORDER_LINES", new OrderLineDto
{
OrderId = existingOrderId,
ProductId = 12,
Quantity = 3
// Leave identity key unset. The datasource refresh path populates it after insert or commit.
});
Default-value factory
manager.SetItemDefault("ORDERS", "CreatedAt", () => DateTime.UtcNow);
manager.SetItemDefault("ORDERS", "CreatedBy", () => Environment.UserName);
await manager.InsertRecordAsync<OrderDto>("ORDERS", new OrderDto());
Built-in Runtime Operations
| Area | FormsManager surface | Notes |
|---|---|---|
| Block properties | SetBlockProperty, GetBlockProperty, SetDefaultWhere, SetOrderBy, SetInsertAllowed, SetUpdateAllowed, SetDeleteAllowed, SetQueryAllowed | Backed by DataBlockInfo and the block-property manager |
| Navigation | SwitchToBlockAsync, GoBlockAsync, NextBlockAsync, PreviousBlockAsync, GoItemAsync, NextItemAsync, PreviousItemAsync, GoRecordAsync, NavigateToRecordAsync, FirstRecordAsync, NextRecordAsync, PreviousRecordAsync, LastRecordAsync | Item focus metadata is runtime-owned; actual cursor rendering remains UI-owned |
| Messages and alerts | SetMessage, ClearMessage, ShowAlertAsync, ConfirmAsync, ShowInfoAsync | Backed by injected IAlertProvider |
| LOV orchestration | ShowLOVAsync, LOV.RegisterLOV | Runtime loads and applies values; visual dialog remains UI-owned |
| Defaults and copy | SetItemDefault, CopyFieldValue | Applied during new-record and field-copy flows |
| Sequences | GetNextSequence, PeekNextSequence, ResetSequence, CreateSequence | Prefer datasource or UnitOfWork sequence generation first |
| Timers | CreateTimer, DeleteTimer, GetTimer, GetAllTimers | Timer expiration feeds WHEN-TIMER-EXPIRED |
| System variables | SystemVariables | Represents :SYSTEM.* runtime state |
Built-in usage example
manager.SetDefaultWhere("ORDERS", "IsDeleted = 0");
manager.SetOrderBy("ORDERS", "OrderDate desc");
manager.SetInsertAllowed("ORDERS", true);
var timer = manager.CreateTimer("REFRESH_ORDERS", TimeSpan.FromSeconds(30), repeating: true);
var confirmed = await manager.ConfirmAsync("Commit", "Save all pending changes?");
if (confirmed)
{
await manager.CommitFormAsync();
}
Multi-Form, Globals, and Messaging
FormsManager implements modal and modeless form flows through the form registry, call stack, globals, parameter handoff, message bus, and shared block manager.
| Concept | Method | Behavior |
|---|---|---|
| Current form open | OpenFormAsync(string formName) | Initializes the current form lifecycle |
| Modal child form | CallFormAsync(..., FormCallMode.Modal) | Suspends caller until child returns |
| Modeless child form | OpenFormAsync(string formName, Dictionary<string, object> parameters) | Independent child runtime tracked by the registry |
| Replace form | NewFormAsync | Replaces the current form in the registry and call flow |
| Return to caller | ReturnToCallerAsync | Can hand return data back to the calling form |
| Global values | SetGlobalVariable, GetGlobalVariable | Represents :GLOBAL.* |
| Parameter handoff | CallFormAsync, OpenFormAsync, GetFormParameter | Caller passes named parameters to target form |
| Inter-form messaging | PostMessage, SubscribeToMessage, UnsubscribeFromMessage | Publish and receive messages through the shared bus |
| Shared UnitOfWork blocks | CreateSharedBlock, SharedBlocks | Expose UoW-backed blocks across form instances |
Modal form, globals, and messaging
manager.SetGlobalVariable("ACTIVE_CUSTOMER_ID", "ALFKI");
manager.SubscribeToMessage("CustomerChanged", message =>
{
Console.WriteLine($"Received {message.MessageType} from {message.SenderForm}");
});
manager.PostMessage("ORDER_FORM", "CustomerChanged", "ALFKI");
await manager.CallFormAsync(
"ORDER_FORM",
new Dictionary<string, object> { ["CustomerId"] = "ALFKI" },
FormCallMode.Modal);
Triggers, Validation, and LOVs
Trigger system
FormsManager wires trigger behavior across insert, update, delete, query, commit, navigation, key events, and timer expiration. Trigger chaining, dependency tracking, and execution logging are part of the runtime.
Key trigger registration
manager.RegisterKeyTrigger(
KeyTriggerType.KEY_COMMIT,
"ORDERS",
args =>
{
Console.WriteLine("Commit key trigger fired");
return Task.CompletedTask;
});
| Capability | Surface | Notes |
|---|---|---|
| Scope-aware trigger registration | Triggers manager | Form, block, item, and global scope |
| Key triggers | RegisterKeyTrigger, RegisterKeyTriggerAsync, FireKeyTriggerAsync | Includes default actions like commit and navigation |
| DML triggers | ON-INSERT, ON-UPDATE, ON-DELETE | Invoked through DML trigger partials |
| Programmatic trigger raising | RaiseFormTriggerAsync | Use when the caller must explicitly invoke a named trigger |
| Trigger libraries | TriggerLibrary | Provides audit stamp, auto-number, cascade delete, and field-format helpers |
| Dependency graph and logging | FormsManager.TriggerChaining.cs | Supports ordered execution and diagnostics |
Validation
Validation rules can run at item, record, block, form, and cross-block scope. FormsManager integrates validation into field changes, query transitions, navigation, and commit flows.
Validation registration example
manager.Validation.RegisterItemRule("ORDERS", "Quantity", value =>
{
return value is int quantity && quantity > 0
? ValidationResult.Success()
: ValidationResult.Failure("Quantity must be greater than zero.");
});
LOV orchestration
Register LOV definitions through the LOV helper, then apply a selected row through
ShowLOVAsync. That keeps data loading, cache reuse, and related-field population inside the
FormsManager orchestration path.
LOV registration and application
var customerLov = LOVDefinition
.CreateLookup("CUSTOMER_LOV", "Northwind", "Customers", "CustomerId", "CompanyName")
.MapField("CompanyName", "CustomerName");
manager.LOV.RegisterLOV("ORDERS", "CustomerId", customerLov);
var lovResult = await manager.ShowLOVAsync("ORDERS", "CustomerId", searchText: "alf");
var selected = lovResult.Records.FirstOrDefault();
if (selected != null)
{
await manager.ShowLOVAsync("ORDERS", "CustomerId", selectedRecord: selected);
}
LOVManager uses an internal __RETURN_VALUE__ sentinel. Callers should prefer
FormsManager.ShowLOVAsync because it translates that sentinel back to the real bound field
name before applying the selected values to the current record.
Audit, Security, and Performance
| Area | Representative methods | Notes |
|---|---|---|
| Audit | SetAuditUser, ConfigureAudit, GetAuditLog, GetFieldHistory, ExportAuditToCsvAsync | Field-change feed plus pluggable audit stores |
| Security | SetSecurityContext, SetBlockSecurity, SetFieldSecurity, GetMaskedFieldValue | UI disabling is not the only protection; runtime CRUD checks still enforce rules |
| Paging | SetBlockPageSize, SetTotalRecordCount, LoadPageAsync, SetFetchAheadDepth | PagingManager tracks state; it does not query the datasource by itself |
| Cache and metrics | InvalidateBlockCache, SetBlockCacheTtl, GetCacheStats, CheckCacheMemoryPressure | Performance manager owns cache statistics and eviction-related behavior |
Audit, security, and paging example
manager.SetAuditUser("fahad");
manager.ConfigureAudit(config =>
{
config.Enabled = true;
config.AuditedBlocks.Add("ORDERS");
});
manager.SetSecurityContext(new SecurityContext
{
UserName = "fahad",
Roles = new List<SecurityRole>
{
new SecurityRole
{
Name = "OrderClerk",
Permissions = SecurityPermission.Query | SecurityPermission.Update
}
}
});
manager.SetBlockPageSize("ORDERS", 50);
manager.SetTotalRecordCount("ORDERS", 1200);
manager.SetFetchAheadDepth("ORDERS", 2);
var page = await manager.LoadPageAsync("ORDERS", 3);
var auditEntries = manager.GetAuditLog("ORDERS");
var cacheStats = manager.GetCacheStats();
Coverage Snapshot
| Forms runtime concept | FormsManager equivalent | Status |
|---|---|---|
ENTER_QUERY | EnterQueryModeAsync | Implemented |
EXECUTE_QUERY | ExecuteQueryAndEnterCrudModeAsync, ExecuteQueryAsync | Implemented |
COMMIT_FORM | CommitFormAsync | Implemented |
ROLLBACK_FORM | RollbackFormAsync | Implemented |
SHOW_LOV | ShowLOVAsync plus LOV.RegisterLOV | Implemented in runtime; visual chooser remains UI-owned |
SET_BLOCK_PROPERTY / GET_BLOCK_PROPERTY | SetBlockProperty, GetBlockProperty | Implemented |
CALL_FORM / OPEN_FORM / NEW_FORM | CallFormAsync, overloads of OpenFormAsync, NewFormAsync | Implemented |
:GLOBAL.* | SetGlobalVariable, GetGlobalVariable | Implemented |
MESSAGE / SHOW_ALERT | SetMessage, ClearMessage, ShowAlertAsync, ConfirmAsync | Implemented |
CREATE_TIMER / DELETE_TIMER | CreateTimer, DeleteTimer | Implemented |
| PRE or POST triggers, DML triggers, KEY-* triggers | Triggers, key-trigger wrappers, DML trigger partials, chaining support | Implemented |
| Audit trail | AuditManager, audit configuration, export, history queries | Implemented |
| Security and masking | Security, block and field security, masking | Implemented |
| Paging and cache control | Paging, PerformanceManager, cache invalidation helpers | Implemented |
Known Boundaries and Hardening Areas
- canvases and tab pages
- focus rendering and cursor movement between visible controls
- LOV dialog presentation and row-selection UI
- keyboard routing from host controls into key-trigger execution
- status-area and message-area rendering
- Some CRUD and update seams still rely on reflection-based fallback paths rather than strongly typed UnitOfWork contracts.
- Programmatic
RaiseFormTriggerAsyncusage should continue to be reviewed where explicit trigger-raise semantics are expected. - Remote cache invalidation remains dependent on the broader host integration and datasource notification model.