Absent Member.
Absent Member.
4270 views

Using databound controls in Windows forms, based on ISAM files

Jump to solution

[Migrated content. Thread originally posted on 21 January 2011]

Can someone tell me how to bind data from ISAM files to windows controls in Visual Cobol? (not with the help of a third-party component).
At the launch of Visual Cobol R3 I asked this and I was told that I can not directly bind isam data to a user control. Now I'm looking for the best alternative/solution.
At this moment we (Centric) use COBOL (NetExpress 4) and Visual Basic 6 (Front End) for developing payroll software. We use COBjects (a third party component that is not supported anymore) for getting data from ISAM files and bind it to user controls with the help of ADO records. The batch processes (calculating) are written in COBOL.
For the future we want to use Visual Cobol replacing Visual Basic 6. We see so much advantages in using Visual Cobol!
0 Likes
1 Solution

Accepted Solutions
Micro Focus Expert
Micro Focus Expert
Here is a better example.
This is a complete COBOL Winform program that has a single DataViewGrid control on the form.


      $set SQL(DBMAN=ADO)
       class-id TestDataBind.Form1 is partial
                 inherits type System.Windows.Forms.Form.
       
       working-storage section.
       EXEC SQL include sqlca END-EXEC.
       EXEC ADO declare customers datatable
       (
       CustName           string(30) not null,
       CustCompany        string(30) not null,
       CustPhone          string(20) not null
       )
       End-Exec       
       EXEC ADO declare cust_info dataset for customers
           save schema to "cust_info.xsd"
       END-EXEC
       .
       01 CustomerDataset type System.Data.DataSet.
       01 tmpDataset      object reference.
       method-id NEW.
       procedure division.
           invoke self::InitializeComponent
           invoke self::fillGrid()
           set dataGridView1::DataSource to CustomerDataset::Tables::Item("Customers")
           goback.
       end method.
       method-id fillGrid.
       local-storage section.
       01 lsCustName      pic x(30).
       01 lsCustCompany   pic x(30).
       01 lsCustPhone     pic x(20).
       procedure division.
           EXEC ADO Initialize dataset
              returning :tmpDataset
           END-EXEC
           set CustomerDataset to tmpDataset as type System.Data.DataSet.
           
          *> The following could be a read from an ISAM file to get data instead of a move

           move "Chris Glazier" to lsCustName
           move "Micro Focus" to lsCustCompany
           move "(800) 555-1212" to lsCustPhone
           
           EXEC ADO
              insert into customers
                 values (:lsCustName,
                         :lsCustCompany,
                         :lsCustPhone)
           END-EXEC     
       
           move "John Smith" to lsCustName
           move "Smith Plumbing" to lsCustCompany
           move "(603) 555-9999" to lsCustPhone
           
           EXEC ADO
              insert into customers
                 values (:lsCustName,
                         :lsCustCompany,
                         :lsCustPhone)
           END-EXEC     
       
           move "Sue Jackson" to lsCustName
           move "Jackson Software" to lsCustCompany
           move "(203) 555-7777" to lsCustPhone
           
           EXEC ADO
              insert into customers
                 values (:lsCustName,
                         :lsCustCompany,
                         :lsCustPhone)
           END-EXEC     
       
           EXEC ADO
               Accept changes for all datatables
           END-EXEC
           
           EXEC ADO
              unbind
           END-EXEC
       
           exit method.
           
       end method.
             
       end class.

View solution in original post

0 Likes
6 Replies
Micro Focus Expert
Micro Focus Expert
You need to get the ISAM data into a .NET bindable object such as an ADO.NET dataset or an array.

Visual COBOL provides for ADO.NET syntax directly allowing you to define and manipulate dataset objects using COBOL syntax. Look in the documentation under Database Access->EXEC ADO syntax.

Example:

    EXEC SQL include sqlca END-EXEC     
      *>  Declare the table that will be used
      *>  to represent the patron data
      EXEC ADO declare patrons datatable
      (
       patron_number      int16 default 0,
       first_name         string(10) not null,
       last_name          string(12) not null,
       street_address     string(20) not null,
      )
      End-Exec       
 
      *> Define all tables in dataset and save
      *> the schema to an XML file
       EXEC ADO declare patron_info dataset for patrons
           save schema to "patron_info.xsd"
       END-EXEC
       .
       01 Patron-Dataset object reference DataSet.
       01 tmp-DataSet    object reference.
    Procedure Division returning Patron-Dataset.
      *>    Create the dataset
     
      EXEC ADO
        Initialize dataset returning :tmp-Dataset
      END-EXEC
      set Patron-Dataset to  tmp-Dataset as DataSet

      *> Read thru ISAM file pulling outrecords and add them to the dataset as follows:

      EXEC ADO
         insert into patrons
            values (:ls-patron-number,
                    :ls-first-name,
                    :ls-last-name,
                    :ls-street-address,
      END-EXEC     
     
      *> Once you have added all records commit changes

      EXEC ADO
          Accept changes for all datatables
      END-EXEC

      *> Unbind from the dataset.
      EXEC ADO
          unbind
      END-EXEC
0 Likes
Micro Focus Expert
Micro Focus Expert
Here is a better example.
This is a complete COBOL Winform program that has a single DataViewGrid control on the form.


      $set SQL(DBMAN=ADO)
       class-id TestDataBind.Form1 is partial
                 inherits type System.Windows.Forms.Form.
       
       working-storage section.
       EXEC SQL include sqlca END-EXEC.
       EXEC ADO declare customers datatable
       (
       CustName           string(30) not null,
       CustCompany        string(30) not null,
       CustPhone          string(20) not null
       )
       End-Exec       
       EXEC ADO declare cust_info dataset for customers
           save schema to "cust_info.xsd"
       END-EXEC
       .
       01 CustomerDataset type System.Data.DataSet.
       01 tmpDataset      object reference.
       method-id NEW.
       procedure division.
           invoke self::InitializeComponent
           invoke self::fillGrid()
           set dataGridView1::DataSource to CustomerDataset::Tables::Item("Customers")
           goback.
       end method.
       method-id fillGrid.
       local-storage section.
       01 lsCustName      pic x(30).
       01 lsCustCompany   pic x(30).
       01 lsCustPhone     pic x(20).
       procedure division.
           EXEC ADO Initialize dataset
              returning :tmpDataset
           END-EXEC
           set CustomerDataset to tmpDataset as type System.Data.DataSet.
           
          *> The following could be a read from an ISAM file to get data instead of a move

           move "Chris Glazier" to lsCustName
           move "Micro Focus" to lsCustCompany
           move "(800) 555-1212" to lsCustPhone
           
           EXEC ADO
              insert into customers
                 values (:lsCustName,
                         :lsCustCompany,
                         :lsCustPhone)
           END-EXEC     
       
           move "John Smith" to lsCustName
           move "Smith Plumbing" to lsCustCompany
           move "(603) 555-9999" to lsCustPhone
           
           EXEC ADO
              insert into customers
                 values (:lsCustName,
                         :lsCustCompany,
                         :lsCustPhone)
           END-EXEC     
       
           move "Sue Jackson" to lsCustName
           move "Jackson Software" to lsCustCompany
           move "(203) 555-7777" to lsCustPhone
           
           EXEC ADO
              insert into customers
                 values (:lsCustName,
                         :lsCustCompany,
                         :lsCustPhone)
           END-EXEC     
       
           EXEC ADO
               Accept changes for all datatables
           END-EXEC
           
           EXEC ADO
              unbind
           END-EXEC
       
           exit method.
           
       end method.
             
       end class.

View solution in original post

0 Likes
Micro Focus Expert
Micro Focus Expert
An alternative approach is to populate the DataTable yourself, which
can be done relatively easy, for example:


       class-id DataBoundGrid.Form1 is partial
                 inherits type System.Windows.Forms.Form.
       
       working-storage section.
       
       method-id NEW.
       procedure division.
           invoke self::InitializeComponent
           goback.
       end method.

       method-id Form1_Load final private.
       procedure division using by value sender as object e as type System.EventArgs.
           set self::dataGridView1::DataSource to self::GetDataSet()
       end method.
     
       method-id GetDataSet.
       local-storage section.
       01 dataColumn type System.Data.DataColumn.
       01 dataRow    type System.Data.DataRow.
       procedure division returning dataset as type System.Data.DataTable.
          set dataset to new type System.Data.DataTable()
       
          set dataColumn to new type System.Data.DataColumn()
          set dataColumn::DataType to type of System.String
          set dataColumn::ColumnName to "CustName"
          invoke dataset::Columns::Add(dataColumn)
       
          set dataColumn to new type System.Data.DataColumn()
          set dataColumn::DataType to type of System.String
          set dataColumn::ColumnName to "CustCompany"
          invoke dataset::Columns::Add(dataColumn)
           
          set dataColumn to new type System.Data.DataColumn()
          set dataColumn::DataType to type of System.String
          set dataColumn::ColumnName to "CustPhone"
          invoke dataset::Columns::Add(dataColumn)

          *> populate the grid..
       
          set dataRow to dataset::NewRow()
          set dataRow::Item("CustName") to "Chris Glazier"
          set dataRow::Item("CustCompany") to "Micro Focus"
          set dataRow::Item("CustPhone")  to "(800) 555-1212"
          invoke dataset::Rows::Add(dataRow)
       
          set dataRow to dataset::NewRow()
          set dataRow::Item("CustName") to "John Smith"
          set dataRow::Item("CustCompany") to "Smith Plumbing"
          set dataRow::Item("CustPhone")  to "(603) 555-9999"
          invoke dataset::Rows::Add(dataRow)

          set dataRow to dataset::NewRow()
          set dataRow::Item("CustName") to "Sue Jackson"
          set dataRow::Item("CustCompany") to "Jackson Software"
          set dataRow::Item("CustPhone")  to "(203) 555-7777"
          invoke dataset::Rows::Add(dataRow)
       end method.

   end class.

0 Likes
Micro Focus Frequent Contributor
Micro Focus Frequent Contributor
One other alternative is to use the property all clause and define a class that can be used to create a Data Transfer Object (DTO). You then combine this with the .NET Generic List/Collection capability to create a Collection.

Assuming this is a simple record layout for the file:

01 original-file-rec.
      05 fld1 pic x(10).
      05 fld2 pic x(10).
      05 fld3 pic s9(4) comp.


Define a class with the same record layout as such using the PROPERTY ALL clause.

class-id FileRecDTO.
       
working-storage section.
01 FileRec property all.
    05 fld1 pic x(10).
    05 fld2 pic x(10).
    05 fld3 pic s9(4) comp.
             
end class.


In your application (after adding a reference to the Class you created and built):


working-storage section.
01 FileDTOObj type FileRecDTO.
01 FileList   type List[type FileRecDTO].
01 original-file-rec.
      05 fld1 pic x(10).
      05 fld2 pic x(10).
      05 fld3 pic s9(4) comp.
             
01 idx binary-long.     
01 FileRecDTOObject type FileRecDTO.
01 FileList         type List[type FileRecDTO]. *> Create a Collection/List of FileRecDTO objects
Procedure division.

    set FileList to new List[type FileRecDTO]

  *> Process Records...these  are just sample move/set statements to create some test data

    perform varying idx from 1 by 1 until idx > 8
        set fld1 to "String1 "  & idx
        set fld2 to "String2 " & idx
        set fld3 to idx
        set FileDTOObj to new FileRecDTO()
        set FileDTOObj::FileRec to original-file-rec
        invoke FileList::Add(FileDTOObj)               
    end-perform

    set dataGridView1::AutoGenerateColumns to false  *> This example assumes you've created the columns in advance or you could create them at runtime
    set dataGridView1::DataSource to FileList





You use the FileList Collection you've created for the data binding. The property all clause exposes all the items including the group level as properties which allows you to selectively expose them to columns in a grid or other controls.

Here is a little video of it working

Notes:
- Don't forget to add your DTO class and System.Collections.Generic to your namespaces in your references (References tab in Project Properties).
- Also...when creating your DTO it is simple to just copy the original record layout but make sure you remove the hyphens or replace them with _ in the data names if you plan to use the DTO class with other .NET languages like C#...the hyphens don't mix well with C#. Visual COBOL will accept both hyphens and underscores in data names if using the default or Micro Focus dialect.

Hope this helps...please feel free to ask questions....
0 Likes
Absent Member.
Absent Member.
And another alternative 🙂 this one implements IEnumerable which moves through a file which we can then set to the ItemsSource property of a WPF listbox.

email me if you want the full project for this (scot.nielsen@microfocus.com).





       class-id WPFApplication1.Window1 is partial
                 inherits type System.Windows.Window.

       working-storage section.
       method-id NEW.
       procedure division.
           invoke self::InitializeComponent()
           goback.
       end method.

       method-id Window_Loaded final private.
       procedure division using by value sender as object e as type System.Windows.RoutedEventArgs.
           set listBox1::ItemsSource to new FileDataSource                     
       end method.

       end class.
       
       
       class-id FileDataSource implements type System.Collections.IEnumerator,                                         
                                          type System.Collections.IEnumerable
                                          .
                                                                                   
                     
       select optional a-file assign "indexed.dat"
       organization indexed
       record key is the-key
       access is dynamic
       .
       
       fd a-file.
       01 the-record.
       03 the-key pic x(10).
       
       
       working-storage section.
       01 at-end condition-value value false.
       
       
       method-id New.
       local-storage section.
       procedure division.
          delete file a-file
          open i-o a-file
         
          move "banana" to the-key
          write the-record
         
          move "orange" to the-key         
          write the-record
                   
          move "kiwi" to the-key         
          write the-record       
         
          move "apple" to the-key         
          write the-record
         
          move "tomato" to the-key         
          write the-record
         
          move "apple" to the-key         
          write the-record
         
          move "passion" to the-key         
          write the-record
         
          move "grape" to the-key         
          write the-record
         
          move "mango" to the-key         
          write the-record
         
          move "pineapple" to the-key         
          write the-record
       
          move spaces to the-key
          start a-file key > the-key
         
          goback.           
       end method.
             
           
      *> Automatically inserted Methods from System.Collections.IEnumerable
       
       method-id GetEnumerator for type System.Collections.IEnumerable.
       procedure division returning return-item as type System.Collections.IEnumerator.
         set return-item to self
       end method.     
       
      *> End Methods from System.Collections.IEnumerable


      *> Automatically inserted Methods from System.Collections.IEnumerator
       
       method-id MoveNext.       
       procedure division returning return-item as condition-value.                     
           
           if not at-end                             
           
              read a-file next record
               at end             
                  set at-end to true               
               end-read
                         
           end-if
                 
           set return-item to not at-end
           
       end method.

       method-id Reset.
       procedure division.
          move spaces to the-key
          start a-file key > the-key
       end method.

       method-id get property Current.
       
       procedure division returning return-item as object.           
           set return-item to the-key
       end method.
     
      *> End Methods from System.Collections.IEnumerator

       end class.
       
       



0 Likes
Absent Member.
Absent Member.
On behalf of my colleague, thanks a lot!

I am currently trying this out. Goal is to read / write a native ISAM file, after reading turn it into an ADO recordset, bind a few controls, alter values and afterwards write from ADO to ISAM.

I am a native VB developer for over ten years so I'll have to learn some COBOL while trying to get this to work.
0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.