6.2 Linkage Between Model and View

In principle, the Datamodel is designed in a way that the Model is not aware which View objects are using it. The data schema for Model and View is the same: indexed attributes to enable scalars, vectors and matrices.

The .datamodel attribute is used to link a view with a model:

object .datamodel[<View attribute>] <Model ID>

For data transfer from the Model to the View, it also has to be defined which attribute of the Model should be retrieved.

attribute .dataget[<View attribute>] <Model attribute>

To define the data transfer back from the View to the Model, the following attribute is used:

attribute .dataset[<View attribute>] <Model attribute>

This way, it can be exactly determined what in the View object is populated through a Model and what is reassigned to the Model. By indexing the .datamodel attribute, it is also possible to use multiple Data Models for different attributes.

View attributes are typically, but not necessarily, actual attributes of the View object, e.g. .content for an edittext used as a View object. In order to achieve a better distinction between View and Model attributes, it is recommended to use user-defined attributes as Model attributes.

To activate the linkage respectively make it effective, the .datamodel attribute must always be set without index, as well as a linking with .dataget or .dataset (with or without index).

This is an example for the use of multiple Models (Data Models: RecUsers, RecManager, VarValid, LbUsers) by multiple Views (listbox LbUsers, edittext EtName, pushbutton PbKill).

dialog D
record RecUsers
{
  string Name[integer];
  .Name[1] := "miller";
  .Name[2] := "smith";
  .Name[3] := "moreno";
  string Rights[integer];
  .Rights[1] := "guest";
  .Rights[2] := "user";
  .Rights[3] := "root";
}

record RecManager
{
  string CurrUser := "moreno";
  boolean IsAdmin := true;
  rule boolean ChangeUser(string Name)
  {
    variable anyvalue Idx;
    Idx := RecUsers:find(.Name, Name);
    if typeof(Idx) = integer then
      this.CurrUser := Name;
      this.IsAdmin := stringpos(RecUsers.Rights[Idx], "root") > 0;
      return true;
    endif
    return false;
  }
}

color CoError "red";
variable object VarError := true;

window Wi
{
  .title "Datamodel Model-View Coupling";
  .width 200;  .height 200;
  boolean Valid := false;

  listbox LbUsers
  {
    .xauto 0;  .yauto 0;
    .ybottom 60;
    .datamodel RecUsers;
    .datamodel[.activeitem] RecManager;
    .dataget .Name;
    .dataget[.activeitem] .CurrUser;
    on select, .activeitem changed
    {
      EtName.dataindex[.content] := this.activeitem;
      VarError := null;
      RecManager:ChangeUser(EtName.content);
    }

    :represent()
    {
      if Attribute = .activeitem then
        Value := this:find(.content, Value);
      endif
      pass this:super();
    }
  }

  edittext EtName
  {
    .yauto -1;  .xauto 0;
    .ybottom 30;
    .datamodel LbUsers;
    .datamodel[.bgc] VarError;
    .dataget .content;
    .dataget[.bgc] .value;
    .dataindex[.content] 0;
    on deselect_enter
    {
      if not RecManager:ChangeUser(this.content) then
        VarError := CoError;
      endif
    }
  }

  pushbutton PbKill
  {
    .yauto -1;
    .text "Kill All Processes";
    .sensitive false;
    .datamodel RecManager;
    .dataget[.sensitive] .IsAdmin;
  }

  on close { exit(); }
}

To make the definition of common links between View and Model attributes as straightforward as possible, the IDM default linkages may be utilized ( as can be seen in the example for EtName, where .datamodel and .dataget are used without index). These defaults are described in the table below:

Table 16-4: Default linkages of View attributes

Object Class

Default View Attribute
for .dataget

Default View Attribute
for .dataset

pushbutton
statictext
messagebox

.text

checkbox
radiobutton
timer

.active

.active

image
menuitem

.text

.active

filereq

.value

.value

listbox
treeview
tablefield

.content

.activeitem

notepage

.title

edittext

.content

.content

poptext

.text

.activeitem

progressbar

.curvalue

scrollbar
spinbox

.curvalue

.curvalue

menubox
toolbar
window

.title

The above example shows another particular feature. Once a visible object is used as Data Model (the View component EtName is linked to the Model LbUsers).

Basically, the IDM supports all object classes that allow user-defined attributes as Data Model, as well as global variables and functions with the function type datafunc. Linking multiple Models is also possible. For visible (visual) objects, however, one thing should be kept in mind: the user interaction does not trigger changed events for attributes and therefore also no automatic propagation of changes to the Model. This needs to be done explicitly or through the appropriate synchronization setting.

As View objects, as well any object classes that allow user-defined attributes are supported. However, the synchronization automatisms between model and view are designed for view objects to be instances with a visual representation.