π Introduction
As a C# developer living in a world of .NET 8, Blazor, and MAUI, encountering a legacy Uniface application can feel like archaeology π¦. But if you look closely at a Uniface Form, you'll find it's remarkably similar to the WinForms or WPF concepts we knowβjust implemented decades earlier with a different philosophy.
In this article, Iβll break down exactly what a Uniface Form is, how it compares to the .NET ecosystem, and the common pitfalls you'll face when maintaining or modernizing them.
π€ What is a Form in Uniface?
In Uniface, a Form (often called a Form Component) is the primary building block of the presentation tier in a client/server architecture. It is the direct equivalent of a System.Windows.Forms.Form or a WPF Window πͺ.
However, unlike a standard .NET form where you manually wire up data binding, a Uniface Form is inherently model-driven.
- π¨ Visuals: It contains the layout (painted pixel-perfectly, similar to the old Visual Basic 6 or WinForms designer).
- πΎ Data Binding: It is tightly coupled to the Application Model. You don't write SQL to fill it; you define which tables (Entities) it uses, and the runtime handles the CRUD operations automatically.
ποΈ The Architecture: "Inheritance on Steroids"
When you drop an entity (e.g., CUSTOMER) onto a Uniface Form, it inherits everything from the central model:
- Data types and formatting π’
- Labels and prompts π·οΈ
- Validation rules (Syntax definitions) β
If you change a field definition in the Application Model and recompile, every Form using that field updates automatically. In C#, this would require updating your DTOs, your ViewModel, and your XAML binding definitions.
β‘ Triggers vs. Events
Instead of C# Events (OnLoad, Click, TextChanged), Uniface uses Triggers written in ProcScript.
| Uniface Trigger | C# Equivalent | Purpose |
|---|---|---|
exec |
Constructor / Form_Load
|
Runs when the form starts π. Used to prepare initial data. |
detail |
DataTemplate / Row binding | Executed for every occurrence (row) displayed. |
value_changed |
PropertyChanged |
Fires when a user modifies a field βοΈ. |
leave |
LostFocus |
Fires when exiting a field. |
π Lifecycle: How Forms are Called
Understanding how a form is invoked is critical for flow control. Uniface distinguishes between modal and non-modal much like .NET:
-
run/editπ: The standard modal call.
run "MY_FORM" ; Waits here until MY_FORM is closedAnalogy:
var f = new MyForm(); f.ShowDialog(); -
showπ: Modeless (Asynchronous).
show "STATUS_WINDOW" ; Code continues immediatelyAnalogy:
var f = new StatusWindow(); f.Show();
β οΈ Common Pitfalls for Modern Developers
If you are coming from a stateless web background or clean architecture in .NET, here are the things that will trip you up:
1. The "Fat Client" Trap π
In many legacy Uniface applications, business logic is buried directly inside Form Triggers (e.g., calculating a total price inside the leave trigger of a quantity field).
- β The Problem: This logic is hard to test and impossible to reuse in a web API.
- β The Fix: When refactoring, move this logic into Global Procs or Services so it can be called from both the Form and potentially a future web endpoint.
2. Stateful Connections π
Uniface Forms maintain a persistent database connection. If a user opens a form and walks away for lunch, that database session (and potentially record locks) stays open. This is very different from the stateless HTTP request/response cycle of ASP.NET Core.
3. Thread Blocking β³
Old Uniface versions run on a single thread. A heavy database query in the exec trigger will freeze the UI completely until it returns. Modern async/await patterns don't exist here in the same way.
π Summary
A Uniface Form is a powerful, data-aware container that combines UI and data access into one package. While it lacks the separation of concerns we prize in modern software architecture (MVVM/MVC), its productivity for building data-entry applications is undeniable.
If you are tasked with maintaining one:
- Respect the Trigger lifecycle π.
- Don't fight the Model-Driven natureβfix data issues in the model, not the form π οΈ.
- Start extracting logic out of the GUI to prepare for the future π.
π¬ Discussion: Has anyone else here had to maintain 20-year-old 4GL languages? What was your experience? Let me know in the comments! π
Top comments (0)