<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Generator" CONTENT="MS Exchange Server version 6.5.7638.1">
<TITLE>DataGridView in virtual mode sample.</TITLE>
</HEAD>
<BODY>
<!-- Converted from text/plain format -->

<P><FONT SIZE=2>Hi all,<BR>
<BR>
I have implemented a little example that shows the use of the .net DataGridView control in virtual mode using RDNZL and Lispworks.<BR>
<BR>
The DataGridView control is particularly difficult to get working properly. I can't count the number of times I crashed my environment getting this working but foreign function calls are always hairy.<BR>
<BR>
The only thing you should have to do to get it working is change the location of the RDNZL path.<BR>
<BR>
Enjoy,<BR>
<BR>
Matthew O'Connor<BR>
<BR>
;; ========================================================================<BR>
;; DataGridView Experiment.<BR>
;;<BR>
;; Matthew O'Connor<BR>
;;<BR>
;; This is basically a lisp implementation of the Microsoft &quot;Walkthrough:<BR>
;; Implementing Virtual Mode in the Windows Forms DataGridView Control&quot;.<BR>
;;<BR>
;; The DataGridView is running in Virtual mode continually coming back<BR>
;; to Lisp through the callbacks to get and set data.<BR>
;;<BR>
;; The example is made a little more complex by the use of an object to<BR>
;; store the row that is currently being edited. This allows a cell edit<BR>
;; to be undone with a simple press of the Escape key. A second press<BR>
;; of the same key will undo the changes made to the entire row.<BR>
;;<BR>
;; As usual there is no warranty. Use at your own peril. I am relatively<BR>
;; new to Lisp so you are warned.<BR>
<BR>
;; NOTE: You need to modify this to point to the location of RDNZL on your system.<BR>
(load &quot;../RDNZL/rdnzl-0.12.0/load.lisp&quot;)<BR>
<BR>
;; ------------------------------------------------------------------------<BR>
;; RDNZL setup.<BR>
<BR>
(rdnzl:enable-rdnzl-syntax)<BR>
<BR>
(rdnzl:import-types &quot;System.Windows.Forms&quot;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;Application&quot; &quot;Form&quot; &quot;DockStyle&quot; &quot;DataGridView&quot;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;DataGridViewTextBoxColumn&quot; &quot;DataGridViewCellValueEventHandler&quot;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;DataGridViewRowEventHandler&quot; &quot;QuestionEventHandler&quot;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;DataGridViewCellEventHandler&quot; &quot;DataGridViewRowCancelEventHandler&quot;)<BR>
(rdnzl:use-namespace &quot;System.Windows.Forms&quot;)<BR>
<BR>
;; ------------------------------------------------------------------------<BR>
;; Utilities<BR>
<BR>
(defun filter (lst fn)<BR>
&nbsp; (let ((acc nil))<BR>
&nbsp;&nbsp;&nbsp; (dolist (x lst)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (let ((val (funcall fn x)))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (if val (push x acc))))<BR>
&nbsp;&nbsp;&nbsp; (nreverse acc)))<BR>
<BR>
;; ------------------------------------------------------------------------<BR>
;; Units<BR>
<BR>
;; The items that will be stored in the database. At the moment they are<BR>
;; simply all strings.<BR>
(defclass unit ()<BR>
&nbsp; ((code :accessor code :initarg :code :initform &quot;None&quot;)<BR>
&nbsp;&nbsp; (description :accessor description :initarg :description :initform &quot;None&quot;)<BR>
&nbsp;&nbsp; (name :accessor name :initarg :name :initform &quot;Unknown&quot;)))<BR>
<BR>
;; Create a unit with an optional description.<BR>
(defun make-unit (code name &amp;optional description)<BR>
&nbsp; (if description<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (make-instance 'unit :code code :name name :description description)<BR>
&nbsp;&nbsp;&nbsp; (make-instance 'unit :code code :name name)))<BR>
<BR>
;; Clone a unit this is needed by the datagridview which makes an copy whilst<BR>
;; editing a row.<BR>
(defun clone-unit (unit)<BR>
&nbsp; (make-unit (code unit) (name unit) (description unit)))<BR>
<BR>
;; ------------------------------------------------------------------------<BR>
;; units database<BR>
<BR>
;; A simple database of units.<BR>
(defparameter *database-units* nil)<BR>
<BR>
(defun database-add-unit (unit)<BR>
&nbsp; (setf *database-units* (append *database-units* (list unit))))<BR>
<BR>
(defun database-remove-unit (unit)<BR>
&nbsp; (setf *database-units* (remove unit *database-units*)))<BR>
<BR>
(defun database-remove-unit-at (index)<BR>
&nbsp; (setf *database-units* (remove (nth index *database-units*) *database-units*)))<BR>
<BR>
(defun database-get-unit (code)<BR>
&nbsp; (first (filter *database-units* #'(lambda (unit) (equal code (code unit))))))<BR>
<BR>
(defun database-get-unit-at (index)<BR>
&nbsp; (nth index *database-units*))<BR>
<BR>
(defun database-update-unit-at (index unit)<BR>
&nbsp; (setf (nth index *database-units*) unit))<BR>
<BR>
(defun database-units-count ()<BR>
&nbsp; (length *database-units*))<BR>
<BR>
;; The data grid view that is used to represent the units.<BR>
(defparameter *units-data-grid-view* nil)<BR>
<BR>
;; Keeps track of the row index that we are currently editing. A value<BR>
;; of -1 indicates that we are not editing anything at the moment.<BR>
(defparameter *row-in-edit* -1)<BR>
<BR>
;; This is the unit that will be created to hold edits until they have<BR>
;; been validated. At this point they will be written back to the database.<BR>
(defparameter *unit-in-edit* nil)<BR>
<BR>
;; I'm not sure about this variable. It never seems to be altered anywhere<BR>
;; in the example code.<BR>
(defparameter *row-scope-commit* t)<BR>
<BR>
;; A little utility to get the count of rows.<BR>
(defun data-grid-view-row-count ()<BR>
&nbsp; [%Count [%Rows *units-data-grid-view*]])<BR>
<BR>
;; Are we editing this row already.<BR>
(defun is-row-in-edit (index)<BR>
&nbsp; (= *row-in-edit* index))<BR>
<BR>
(defun is-new-row (index)<BR>
&nbsp; (= index (- (data-grid-view-row-count) 1)))<BR>
<BR>
;; Is the supplied index the new row.<BR>
(defun is-new-row-from-row (row)<BR>
&nbsp; [%IsNewRow row])<BR>
<BR>
<BR>
;; We are no longer editing any row so set the variables back to their<BR>
;; defaults.<BR>
(defun reset-unit-in-edit ()<BR>
&nbsp; (setf *unit-in-edit* nil<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *row-in-edit* -1))<BR>
<BR>
;; ------------------------------------------------------------------------<BR>
;; Implement the DataGridView callbacks.<BR>
;;<BR>
;; These are reasonably complex little calls. I refer you to the &quot;Walkthrough&quot;<BR>
;; mentioned at the start of the file for further information on how they<BR>
;; work.<BR>
<BR>
;; The event occurs whenever the DataGridView requires the value to a cell for<BR>
;; display. It retrieves the value from either the database of units or from the<BR>
;; unit currently being edited.<BR>
;;<BR>
;; DataGridViewCellValueEventArgs<BR>
;;&nbsp;&nbsp; int ColumnIndex - The index of the column.<BR>
;;&nbsp;&nbsp; int RowIndex - The index of the row.<BR>
;;&nbsp;&nbsp; object Value - The value of the row.<BR>
(defun cell-value-needed (object event)<BR>
&nbsp; (let ((row-index [%RowIndex event])<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (column-index [%ColumnIndex event])<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (unit nil))<BR>
&nbsp;&nbsp;&nbsp; (unless (is-new-row row-index)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (if (is-row-in-edit row-index)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;; then<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (setf unit *unit-in-edit*)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;; else<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (setf unit (database-get-unit-at row-index)))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (unless (equal unit nil)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (case column-index<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((0) (setf [%Value event] (code unit)))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((1) (setf [%Value event] (name unit)))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((2) (setf [%Value event] (description unit))))))))<BR>
<BR>
;; This event occurs whenever a cell value has been updated on the DataGridView.<BR>
;; It gives the underlying storage mechanism a chance to update the value.<BR>
;;<BR>
;; If there is no unit currently in edit one is created. The updates do not go<BR>
;; directly to the database. They go via the unit currently in edit first. Once<BR>
;; the changes have been validated they are updated in the database.<BR>
;;<BR>
;; DataGridViewCellValueEventArgs<BR>
;;&nbsp;&nbsp; int ColumnIndex - The index of the column.<BR>
;;&nbsp;&nbsp; int RowIndex - The index of the row.<BR>
;;&nbsp;&nbsp; object Value - The value of the row.<BR>
(defun cell-value-pushed (object event)<BR>
&nbsp; (let ((row-index [%RowIndex event])<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (column-index [%ColumnIndex event])<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (unit-tmp nil))<BR>
&nbsp;&nbsp;&nbsp; (if (&lt; row-index (length *database-units*))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (progn<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (when (equal *unit-in-edit* nil)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (setf *unit-in-edit* (clone-unit (database-get-unit-at row-index))))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (setf unit-tmp *unit-in-edit*<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *row-in-edit* row-index))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;; else<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (setf unit-tmp *unit-in-edit*))<BR>
&nbsp;&nbsp;&nbsp; (unless (equal unit-tmp nil)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (let ((value [%Value event]))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (case column-index<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((0) (setf (code unit-tmp) (rdnzl:unbox (rdnzl:cast value &quot;System.String&quot;))))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((1) (setf (name unit-tmp) (rdnzl:unbox (rdnzl:cast value &quot;System.String&quot;))))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((2) (setf (description unit-tmp) (rdnzl:unbox (rdnzl:cast value &quot;System.String&quot;)))))))))<BR>
<BR>
;; Occurs whenever a new row is needed at the end of a DataGridView. It simply<BR>
;; creates a new empty unit that becomes the current unit in edit.<BR>
;;<BR>
;; DataGridViewRowEventArgs:<BR>
;;&nbsp;&nbsp; DataGridViewRow Row - I'm not sure what the contents of the row are<BR>
;;&nbsp;&nbsp;&nbsp;&nbsp; as I currently don't use them.<BR>
(defun new-row-needed (object event)<BR>
&nbsp; (setf *unit-in-edit* (make-unit &quot;&quot; &quot;&quot; &quot;&quot;)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *row-in-edit* (- (data-grid-view-row-count) 1)))<BR>
<BR>
;; This event occurs after a row has finished validating. At this point the data<BR>
;; can be pushed to the database.<BR>
;;<BR>
;; DataGridViewViewCellEventArgs<BR>
;;&nbsp;&nbsp; int ColumnIndex - The index of the column.<BR>
;;&nbsp;&nbsp; int RowIndex - The index of the row.<BR>
(defun row-validated (object event)<BR>
&nbsp; (let ((row-index [%RowIndex event]))<BR>
&nbsp;&nbsp;&nbsp; (if (and (&gt;= row-index (database-units-count))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (not (= row-index (- (data-grid-view-row-count) 1) )))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (progn<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (database-add-unit *unit-in-edit*)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (reset-unit-in-edit))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (if (and (not (equal *unit-in-edit* nil))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (&lt; row-index (database-units-count)))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (progn<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (database-update-unit-at row-index *unit-in-edit*)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (reset-unit-in-edit))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (if [%ContainsFocus *units-data-grid-view*]<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (reset-unit-in-edit))))))<BR>
<BR>
;; Used by the DataGridView to determine if current row has uncommitted changes.<BR>
;;<BR>
;; Note - I'm not quite sure how this works.<BR>
;;<BR>
;; QuestionEventArgs<BR>
;;&nbsp;&nbsp; Boolean Response - True or False.<BR>
(defun row-dirty-state-needed (object event)<BR>
&nbsp; (unless *row-scope-commit*<BR>
&nbsp;&nbsp;&nbsp; (setf [%Response event] [%IsCurrentCellDirty *units-data-grid-view*])))<BR>
<BR>
;; Give the application the opportunity to cancel the edits in a row.<BR>
;;<BR>
;; A single escape key cancels the cell edit. A double cancels the row edit.<BR>
;;<BR>
;; QuestionEventArgs<BR>
;;&nbsp;&nbsp; Boolean Response - True to cancel the row-edit, False (I assume) to let it<BR>
;;&nbsp;&nbsp;&nbsp; continue.<BR>
(defun cancel-row-edit (object event)<BR>
&nbsp; (if (and (= *row-in-edit* (-&nbsp; (data-grid-view-row-count) 2))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (= *row-in-edit* (database-units-count)))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (setf *unit-in-edit* (make-unit &quot;&quot; &quot;&quot; &quot;&quot;))<BR>
&nbsp;&nbsp;&nbsp; (reset-unit-in-edit)))<BR>
<BR>
;; Remove the row if it is in the database otherwise simply reset the unit in edit.<BR>
;;<BR>
;; DataGridViewRowCancelEventArgs:<BR>
;;&nbsp;&nbsp; DataGridViewRow Row - The row the user is deleting.<BR>
;;&nbsp;&nbsp; Boolean Cancel - Cancel the addition of the row.<BR>
(defun user-deleting-row (object event)<BR>
&nbsp; (let* ((data-grid-row [%Row event])<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (row-index [%Index data-grid-row]))<BR>
&nbsp;&nbsp;&nbsp; (when (&lt; row-index (database-units-count))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (database-remove-unit-at row-index))<BR>
&nbsp;&nbsp;&nbsp; (when (= row-index *row-in-edit*)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (reset-unit-in-edit))))<BR>
<BR>
<BR>
;; ------------------------------------------------------------------------<BR>
;; Main<BR>
<BR>
;; Create a new text box column.<BR>
(defun create-column (index name heading)<BR>
&nbsp; (let ((col (rdnzl:new &quot;DataGridViewTextBoxColumn&quot;)))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (setf [%DisplayIndex col]&nbsp; index<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [%Name col] name<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [%HeaderText col] heading)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; col))<BR>
<BR>
;; Create a DataGridView with three columns; Code, Name and Description.<BR>
;; It is placed in Virtual mode and all of the callbacks are hooked up.<BR>
(defun create-units-editor ()<BR>
&nbsp; (setf *units-data-grid-view* (rdnzl:new &quot;DataGridView&quot;)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *row-in-edit* -1<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *unit-in-edit* nil<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *row-scope-commit* t<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [%VirtualMode *units-data-grid-view*] t&nbsp;&nbsp;&nbsp;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [%Dock *units-data-grid-view*] [$DockStyle.Fill]<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [%Text *units-data-grid-view*] &quot;DataGridView Experiment&quot;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [%RowHeadersVisible *units-data-grid-view*] t)<BR>
&nbsp; [Add [%Columns *units-data-grid-view*] (create-column 0 &quot;code&quot; &quot;Code&quot;)]<BR>
&nbsp; [Add [%Columns *units-data-grid-view*] (create-column 1 &quot;name&quot; &quot;Name&quot;)]<BR>
&nbsp; [Add [%Columns *units-data-grid-view*] (create-column 2 &quot;description&quot; &quot;Description&quot;)]<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>
&nbsp; [+CellValueNeeded *units-data-grid-view* (rdnzl:new &quot;DataGridViewCellValueEventHandler&quot; #'cell-value-needed)]<BR>
&nbsp; [+CellValuePushed *units-data-grid-view* (rdnzl:new &quot;DataGridViewCellValueEventHandler&quot; #'cell-value-pushed)]<BR>
&nbsp; [+NewRowNeeded *units-data-grid-view* (rdnzl:new &quot;DataGridViewRowEventHandler&quot; #'new-row-needed)]<BR>
&nbsp; [+UserDeletingRow *units-data-grid-view* (rdnzl:new &quot;DataGridViewRowCancelEventHandler&quot; #'user-deleting-row)]<BR>
&nbsp; [+CancelRowEdit *units-data-grid-view* (rdnzl:new &quot;QuestionEventHandler&quot; #'cancel-row-edit)]<BR>
&nbsp; [+RowDirtyStateNeeded *units-data-grid-view* (rdnzl:new &quot;QuestionEventHandler&quot; #'row-dirty-state-needed)]<BR>
&nbsp; [+RowValidated *units-data-grid-view* (rdnzl:new &quot;DataGridViewCellEventHandler&quot; #'row-validated)])<BR>
<BR>
;; Call this function to run the application.<BR>
(defun run-datagridview-experiment ()<BR>
&nbsp; (let ((form (rdnzl:new &quot;Form&quot;)))<BR>
&nbsp;&nbsp;&nbsp; (create-units-editor)<BR>
&nbsp;&nbsp;&nbsp; (setf [%Text form] &quot;DataGridView Experiment&quot;)<BR>
&nbsp;&nbsp;&nbsp; [Add [%Controls form] *units-data-grid-view*]<BR>
&nbsp;&nbsp;&nbsp; [BringToFront *units-data-grid-view*]<BR>
&nbsp;&nbsp;&nbsp; [Application.Run form]))<BR>
<BR>
(run-datagridview-experiment)<BR>
<BR>
<BR>
<BR>
</FONT>
</P>

</BODY>
</HTML>