How to add a non-bound column to a DevExpress DB QuantumGrid - delphi

I am using these components:
UniDac for connection to mysql database
DevExpress for QuantumGrid
IDE:
Embarcadero Rad Studio XE2
I have a cxGrid component with one level and a cxGrid1DBTableView specified as the level's View. I can get data from my database and edit it in the grid. I want to add a column that is not in the bound DataSet. When I specify the Column properties value as CheckBox I can see the column but I can't change the value from unchecked to checked by clicking it. The field doesn't have a DataBinding assigned to it. I tried other types of Properties but all are the same I cant change the row value in the grid.
I've been searching for a way to fix this for couple of days, so im hoping you guys can help me.

Are you trying to add a checkbox item that does not have a database field behind it? I have this on one of my forms.
In addition to setting the Properties to "Checkbox" you need to set the DataBinding -> ValueType to "Boolean". The DataBinding->FieldName can be left blank.
To access the values or change their defaults you can use the DataController like this:
View.DataController.Values[i, CheckBoxFieldIndex] := true;
In addition you need to set
DataController.DataModeController.SmartRefresh := true;
To set that option you will also need a KeyField defined for the Controller (DataController.KeyFieldNames)
Setting the SmartRefresh to true will prevent the grid from trying to get an updated value from the underlying dataset. You need to prevent the refresh or the value for the non-bound column will be set back to Null. This comes with some restriction on how you update your dataset. Any changes made to the data in code will not be reflected by the grid unless you explicitly refresh the grid.

You also have to fill the field View.DataController.KeyFieldNames with one of the datasets fields. At least I need it in Delphi 7.

Related

Delphi TDBGrid edit inplace with drop down list

I have to do maintenance to an old Delphi v7 application which uses a TDBGrid allowing inplace editting with drop down lists.
The issue is: the grid will show only the values present at data source. Without editting, this would be no problem at all. But if I change some value, the grid will only show the newly set value after updating the underlying register (until that the "old" value is displayed).
This only applies to drop down lists. Other input types (checkboxes, text edits) work without problems.
The edit itself also works fine: the changed values are actually reflected in the datasource when the register is UPDATE'd. My only problem is displaying this not-yet-UPDATE'd value.
I have no idea how to even debug this, or further inspect this behavior. So even if you don't have a complete answer, please indicate what else can I do to find a solution.
UPDATE
The project originally used TDB3DGrid (whose source I'm not aware of), but to simplify things I've changed it to TDBGrid. To no avail. The only change was that true/false columns are now displayed as text, and edited as text boxes (displaying and accepting "True" and "False" strings); with TDB3DGrid it showed checkboxes.
Other columns (not edited trough drop down list) are fine: after editing the new value is displayed correctly even before updating the underlying register.
I'm still tracking down where does the list of alternatives that fill the drop down list comes from.
Also still trying to come with an MCVE.
UPDATE 2
Apparently the (now) TDBGrid's affected TDBGridColumn has an empty PickList property. Sure for designtime. But I think this is not changed in runtime.
TDBGrid's source is a child of a TQuery, whose affected field has FieldKind equal to fkLookup. Other properties set for the field are FieldName, KeyFields, LookupDataSet, LookupKeyFields and LookupResultField.

Creating readwrite field at runtime in Dataset - provider - clientdatatset

I am trying to create an additional field that is NOT ReadOnly at runtime in Delphi. I have a TADOQuery with SQL on the lines of
SELECT *,CAST(0 AS BIT) AS CheckField FROM MyTable WHERE KeyField = :KeyValue
This links through a TDatasetProvider to a TClientDatset.
My issue is the resulting field in the TClientDataset ends up as ReadOnly.
The TClientDataset is created at design time to link into grids etc. The other components are created at runtime in a separate object.
I have had a similar setup working , but with everything created at design time. I resolve this problem by creating persistent fields on the TADOQuery component and setting the CheckField's ReadOnly property to False prior to opening the TClientDatset. I am unsure as to how to do this at runtime given the field component doesn't exist until I have opened the ClientDatset and by then it's too late to set it's readonly property!
The problem is the CAST().
The dataset doesn't analyze what the underlying field might be that's being CAST; it just knows that it's a function result that is placed into the column, and you can't edit a function result.
You could just SELECT *, 0 AS CheckField, and then set a validation on the resulting field to restrict the values to 0 and 1.

TClientDataSet.Cancel Loses TDBMemo Values

I have a form with the following controls: TDBEdit, TDBMemo, TDataSource, TClientDataSet
If the user edits the fields and then clicks a button on the form that simply calls the MyCDS.Cancel method (to cancel the edits), the TDBEdit fields revert to their original values, but the TDBMemo fields are not reverted (they are set to blank values).
The TClientDataSet is populated from a MSSQLServer 2008 database. The TDBEdit fields are nvarchar(255) in the database, and the TDBMemo are nvarchar(max) or xml fields.
Looking at the values in the Debug Inspector (ctrl+F7, MyCDS.FieldByName('afield'), Inspect) shows the following for one of the nvarchar(max) fields:
DataSize = 0
DataType = ftWideMemo
Size = 1
This is the same for all of the nvarchar(max) and xml fields whether or not the underlying field has data or not.
It appears that there is an incompatibility between the nvarchar(max) (which is treated as a ftWideMemo) and the TDBMemo control.
Has anyone seen issues like this before? Do you have any suggestions how to resolve it?
In case anyone in interested, the problem is a bug in the TClientDataSet component. The problem only occurs when you clone a dataset, don't have a Provider and turn LogChanges off. If you edit a record on the cloned dataset and then cancel the edit, then any memo fields lose their values.
Since you don't necessarily use a Provider in file-based applications, it doesn't always make sense to enable LogChanges. However, to work around the limitation with memo fields, you can leave LogChanges on, and then call MergeChangeLog after operations that change the cloned dataset.
I created a program that demonstrates the issue. See the Embarcadero incident QC#110511.

How to retrieve information from a field that has the property Required set as false?

I have the following DBX structure in my software:
TSQLDataSet -> TDataSetProvider -> TClientDataSet
One of the fields from my TClientDataSet has the property Required set to false, because this field auto increments based on triggers and generators on the database (Firebird).
However, after configuring both TSQLDataSet and TClientDataSet with this field not being required, I'm getting really weird results when I try to read this field from my TClientDataSet. I suspect that I might need to do something extra to force my TClientDataSet to acquire the value of this field in this condition.
What am I missing here?
Thanks in advance.
EDIT
The help file for the Required property says something about this, but I couldn't quite understand what it want me to do.
Description
Specifies whether a nonblank value for a field is
required.
Use Required to find out if a field requires a value or if the field
can be blank.
If a field is created with the Fields editor, this property is set
based on the underlying table. Applications that set Required to true
for fields that must have values (for example, a password or part
number), but for which the underlying table does not require the
field, must write an OnValidate event handler to enforce the property.
When the Required property reflects a property of the underlying
database table, trying to post apply a null value causes an exception
to be raised. Applications that set the Required property to true when
the underlying table does not require the field, should raise an
EDatabaseError exception on null values in the OnValidate event
handler in order to achieve the same result.
EDIT 2
Forgot to mention: between the TDataSetProvider and the TClientDataSet, there is a DataSnap layer (the TClientDataSet connection is made with a DataSnap driver).
EDIT 3
I created a small test case with this DataSnap setup and it worked perfectly. The project is legacy, messy and I guess that either I have an obscure option configured somewhere that is biting me or I have stumbled in a DataSnap bug.
Haole, have you tried TClientDataset.RefreshRecord after inserting? Or even TClientDataset.Refresh?
Having generators, you can even get the generator in advance (before calling ApplyUpdates) in a query like select gen_id(generator,1) from RDB$Database (it's from memory, don't have Firebird here to test) and fill the PK field in advance.
EDIT: seems this is a heisenbug. I would try to remove the components and reconfigure them again from scratch (which means: after you remove, save and close Delphi).
Or even better, create an empty project with just that needed query configuration and try to view that data in a TDBGrid. If this problem still happens, maybe your FB installation have some component corrupted (or even Delphi installation)
Seems that the problem was an outdated field being read as an INTEGER and it was a SMALLINT in the database.
This problem was hard to debug and this question was misleading. Thanks for everyone that helped me debug this.

Add calculated column with checkboxes to datagrid

In my application I have a TcxGrid (devexpress datagrid) that displays the data returned from a stored procedure.
Now I would like to add a column showing checkboxes from which the values cannot come from the database but are calculated internally.
When the checkboxes are clicked, some internal logic needs to be triggered.
Any suggestions?
#boris, I recommend you use the Support Center site of DevExpress for this type of question, there are thousands of articles to DevExpress products.
Anyway I leave here a link to something that might help ;)
How to set up an unbound item in a data-aware View
Are you creating the view at runtime or at designtime?
I sort of cheated when I did this at runtime, and returned a static value as one column from my query:
select false as processed,col1,col2 from table where true
I could then safely attach the dataset, and I had my new column to play with.
You would then perhaps use the properties.onChange or properties.onEditValueChanged for your logic code.

Resources