Cross-platform C SDK logo

Cross-platform C SDK

Data binding

❮ Back
Next ❯
This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.

Data Binding is a technique that allows us to register the program structures or classes in order to automate certain tasks, such as synchronizing the data model with the user interface.


Functions

voiddbind (...)
voiddbind_enum (...)
voiddbind_alias (...)
type*dbind_create (...)
voiddbind_init (...)
voiddbind_remove (...)
voiddbind_destroy (...)
voiddbind_destopt (...)
type*dbind_read (...)
voiddbind_write (...)
voiddbind_default (...)
voiddbind_range (...)
voiddbind_precision (...)
voiddbind_increment (...)
voiddbind_suffix (...)

In a C/C++ application the data model is represented by struct or class types that allow to create objects and access their content in memory (Listing 1).

Listing 1: Simple data model based on struct.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
typedef enum _type_t
{
    ekCPU,
    ekGPU,
    ekHDD,
    ekSCD
} type_t;

typedef struct _product_t
{
    type_t type;
    String *code;
    String *description;
    Image *image64;
    real32_t price;
} Product;

As a previous step, when starting the application, we can register the fields of the different structures using the command dbind (Listing 2). It is only necessary to perform this process once. In this way the application will create internal tables with the description of each data model structure (Listing 2) and will be ready to automate certain tasks when working with objects of those classes.

  • Use dbind to register the fields of a structure.
  • Use dbind_enum to register the different values of enum types.
  • Listing 2: Registering the data model of (Listing 1).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    dbind_enum(type_t, ekCPU);
    dbind_enum(type_t, ekGPU);
    dbind_enum(type_t, ekHDD);
    dbind_enum(type_t, ekSCD);
    dbind(Product, type_t, type);
    dbind(Product, String*, code);
    dbind(Product, String*, description);
    dbind(Product, Image*, image64);
    dbind(Product, real32_t, price);
    
    Scheme showing a data structure and its equivalent table.
    Figure 1: Internal tables created by dbind when registering the data model.

1. MVVM synchronization with GUI

One of the usual uses of the dbind tables will be the synchronization of the data model with the user interface. Normally this task requires capturing the events of the controls to update the data and vice versa, refresh the contents of the controls each time the data changes. This task is tedious and requires a lot of additional code. To avoid this, when we create the view, we will link the different controls with the structure fields by cell_dbind (Listing 3). This paradigm is known as data binding or MVVM (Model-View-ViewModel) (Listing 3) and will keep both parts synchronized automatically.

Listing 3: Binding GUI controls with data fields.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Cell *cell0 = i_code_cell(layout);
Cell *cell1 = i_desc_cell(layout);
Cell *cell2 = i_type_cell(layout);
Cell *cell3 = i_img_cell(layout);
Cell *cell4 = i_price_cell(layout);
cell_dbind(cell0, Product, String*, code);
cell_dbind(cell1, Product, String*, description);
cell_dbind(cell2, Product, type_t, type);
cell_dbind(cell3, Product, Image*, image64);
cell_dbind(cell4, Product, real32_t, price);
layout_dbind(layout, Product);
Connections between a user interface and the data it manipulates.
Figure 2: Automatic synchronization of data and interface.

2. JSON reading

JSON scripting and translation can also be automated thanks to dbind. To illustrate its operation we have the following web service which provides us with a list of Product type objects. In C/C++ JSON Web services you have the complete application.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "code":0,
    "size":80,
    "data":[
    {"id":0,
    "code":"i7-8700K",
    "description":"Intel BX80684I78700K 8th Gen Core i7-8700K Processor",
    type":0,
    "price":374.8899999999999863575794734060764312744140625,
    "image":"cpu_00.jpg",
    "image64":"\/9j\/4AAQSkZJRgABAQ....
    },
    ...
}

We register with dbind an additional structure with the script control fields (Listing 5).

Listing 5: JSON control fields.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
typedef struct _pjson_t
{
    int32_t code;
    uint32_t size;
    ArrPt(Product) *data;
} PJson;

dbind(PJson, int32_t, code);
dbind(PJson, uint32_t, size);
dbind(PJson, ArrPt(Product)*, data);

In this way we can access the service and read the data with very few lines of code (Listing 6). json_read access the internal dbind tables to translate the JSON and create the objects (Figure 3).

Listing 6: JSON data download and processing.
1
2
3
Stream *stm = http_dget("serv.nappgui.com", 80, "/dproducts.php", &error);
PJson *pjson = json_read(stm, PJson);
stm_close(&stm);
Connections between the fields of an object and a JSON script.
Figure 3: Data Binding in the analysis of JSON scripts.

3. Serialization with DBind

As we saw in Serialization and Unify serialization we need to define object reading and writing functions to send or receive them through streams. Fortunately, dbind knows the detailed composition of each registered object, so it's possible access the I/O without having to explicitly program these functions (Listing 7) (Figure 4).

Listing 7: Objects serialization with dbind.
1
2
3
ArrPt(Product) *products = dbind_read(stream, ArrPt(Product));
...
dbind_write(stream, products, ArrPt(Product)*);
Access to dbind tables to serialize objects.
Figure 4: Object reading/writing via dbind.

4. Default constructor

Thanks to dbind we can also create objects initialized with default values without creating specific constructors (Listing 8). They can also be destroyed guaranteeing the correct recursive release of the memory of all their fields.

The default values when initializing object fields are 0 for numbers, FALSE for booleans, "" for Strings and empty containers in the case of arrays or sets. If the object contains nested sub-objects, they will also be created/initialized recursively. These default values can be changed if necessary (Listing 9).


5. Numerical ranges

It is possible to configure the numeric fields uint32_t, int8_t, real64_t, etc to limit the accepted values (Listing 10). dbind will be responsible for validating the data every time it reads values from any data source (GUI, JSON, Streams, etc).


dbind ()

Adds a structure/class field to its internal table within dbind.

void
dbind(type,
      mtype,
      name);
type

Type of structure or class.

mtype

Type of field to register.

name

Name of the field within the structure.

Remarks

Errors will be generated at compile time if the indicated field does not belong to the structure. The method also works for classes in C++.


dbind_enum ()

Register an enum type value.

void
dbind_enum(type,
           value);
type

Enum type.

value

Value.


dbind_alias ()

Create an alias for an enumerated value.

void
dbind_alias(type,
            value,
            const char_t *alias);
type

Enum type.

value

Value.

alias

Text string with the alias.

Remarks

dbind_alias(mode_t, ekIMAGE_ANALISYS, "Image Analisys");. Use the string "Image Analisys" instead of "ekIMAGE_ANALISYS" for those I/O or interface operations that require displaying the enumeration values. For example, to populate the fields of a PopUp linked with a data field.


dbind_create ()

Create an object of registered type, initializing its fields with the default values.

type*
dbind_create(type);
type

Object type.

Return

Newly created object or NULL if dbind does not recognize the data type.


dbind_init ()

Initializes the fields of an object of a registered type with the default values.

void
dbind_init(type *obj,
           type);
obj

Object whose memory has been reserved, but not initialized.

type

Object type.


dbind_remove ()

Destroys the memory reserved by the fields of an object of registered type, but does not destroy the object itself.

void
dbind_remove(type *obj,
             type);
obj

Object.

type

Object type.


dbind_destroy ()

Destroy an object of registered type. The memory allocated to the fields and sub-objects will also be released recursively.

void
dbind_destroy(type **obj,
              type);
obj

Object. Will be set to NULL after destruction.

type

Object type.


dbind_destopt ()

Destructor optional. Like dbind_destroy, but accepting NULL values for the object.

void
dbind_destopt(type **obj,
              type);
obj

Object to destroy.

type

Object type.


dbind_read ()

Creates an object of a registered type from the data read from a stream.

type*
dbind_read(Stream *stm,
           type);
stm

Reading stream.

type

Object type to read.

Return

Newly created object or NULL if there has been an error.


dbind_write ()

Write the content of an object of registered type in a write stream.

void
dbind_write(Stream *stm,
            const type *data,
            type);
stm

Writing stream.

data

Object to write.

type

Type of object to write.


dbind_default ()

Set the default value of a field.

void
dbind_default(type,
              mtype,
              name,
              mtype value);
type

Type of structure or class.

mtype

Field type.

name

Name of the field within the structure.

value

Default value as of now.


dbind_range ()

Set the maximum and minimum value in numeric fields.

void
dbind_range(type,
            mtype,
            name,
            mtype min,
            mtype max);
type

Type of structure or class.

mtype

Field type.

name

Name of the field within the structure.

min

Minimum value.

max

Maximum value.

Remarks

It will fail if used in non-numeric fields.


dbind_precision ()

Set the jump between two consecutive numerical values.

void
dbind_precision(type,
                mtype,
                name,
                mtype prec);
type

Type of structure or class.

mtype

Field type.

name

Name of the field within the structure.

prec

Accuracy (eg .05f in real32_t values).

Remarks

It will fail if used in non-numeric fields.


dbind_increment ()

Sets the increment of a numerical value when clicking on a UpDown control.

void
dbind_increment(type,
                mtype,
                name,
                mtype incr);
type

Type of structure or class.

mtype

Field type.

name

Name of the field within the structure.

incr

Increase.

Remarks

It will fail if used in non-numeric fields.


dbind_suffix ()

Set a suffix that will be added to the numerical value when converted to text.

void
dbind_suffix(type,
             mtype,
             name,
             const char_t *suffix);
type

Type of structure or class.

mtype

Field type.

name

Name of the field within the structure.

suffix

Suffix.

Remarks

It will fail if used in non-numeric fields.

❮ Back
Next ❯