我正在将应用程序从 Delphi 6 / TdxDBGrid迁移到 Delphi 2009 / TcxGrid,我遇到了以下问题:
我有一个带有网格级OnEdited事件的TdxDBGrid,它将“IS_MODIFIED_BY_USER”属性分配给编辑过的记录:
procedure TSalesOrderForm.LineGridEdited(Sender: TObject;
Node: TdxTreeListNode);
begin
inherited;
if LineGrid.FocusedField<>LineGridIS_MODIFIED_BY_USER.Field then
(Sender as TdxDBGrid).DataSource.
DataSet.FieldByName('IS_MODIFIED_BY_USER').AsInteger:=1;
end;
字符串
这样的实现是非常顺利的。它只处理来自网格(用户)的更新,如果记录被DataModule修改(即被不直接编辑用户的进程修改),IS_MODIFIED_BY_USER保持不变。它适用于网格中任何字段的编辑。
现在,我尝试将此功能移动到TcxGrid/TcxDBTableView,并在网格级别OnEditValueChanged和Column-Editor-Properties. OnEditValueChanged上查找。
这样的事件确实会被触发,但是任何更改另一个字段的尝试(例如,当AMOUNT字段被更改时,将1分配给IS_MODIFIED_BY_USER)都会失败:值被分配(给IS_MODIFIED_BY_USER),但是编辑的值(AMOUNT)被网格忽略,并且在按Enter时(同时保持光标在AMOUNT字段中),AMOUNT的值恢复为初始值。
我尝试过不同的分配策略-通过数据集,通过网格编辑器,但都不起作用。
其他替代方案也不是很好。例如TDataSource.OnUpdateDate不是解决方案,因为它只对Post有效,但我需要在编辑完成后立即将1分配给IS_MODIFIED_BY_USER,并且在整个记录发布之前,同一记录中可能有许多其他编辑。
另一种方法是使用TClientDataSetAMOUNT.OnChange事件处理程序,但它不是解决方案,因为该事件会在数据集记录的任何更改时触发。但我只需要捕获来自网格中用户编辑的更改。另一个改进是使用flat,它可以防止更新并为任何DataModule发起的更改设置此标志:
过程TMainForm.CDSAMOUNTChange(String:TField);开始if(FSystemUpdates)然后退出; if CDSIS_MODIFIED_BY_USER. Asynchronous <>1 then CDSIS_MODIFIED_BY_USER. Asynchronous:=1;结束;
这确实可以工作,但这是非常复杂的方法。
我仍然希望我可以驯服TcxDBTableView来响应用户所做的编辑。
下面是我的测试项目,演示了这个问题:
通过:
unit MainFormU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, DBClient, StdCtrls, cxStyles, dxSkinsCore, dxSkinBlack,
dxSkinBlue, dxSkinCaramel, dxSkinCoffee, dxSkinDarkSide, dxSkinGlassOceans,
dxSkiniMaginary, dxSkinLilian, dxSkinLiquidSky, dxSkinLondonLiquidSky,
dxSkinMcSkin, dxSkinMoneyTwins, dxSkinOffice2007Black, dxSkinOffice2007Blue,
dxSkinOffice2007Green, dxSkinOffice2007Pink, dxSkinOffice2007Silver,
dxSkinPumpkin, dxSkinSilver, dxSkinSpringTime, dxSkinStardust,
dxSkinSummer2008, dxSkinsDefaultPainters, dxSkinValentine, dxSkinXmas2008Blue,
dxSkinscxPCPainter, cxCustomData, cxGraphics, cxFilter, cxData, cxDataStorage,
cxEdit, cxDBData, cxGridCustomTableView, cxGridTableView, cxGridDBTableView,
cxGridLevel, cxClasses, cxControls, cxGridCustomView, cxGrid, cxMaskEdit;
type
TMainForm = class(TForm)
SetupBtn: TButton;
CDS: TClientDataSet;
DS: TDataSource;
CDSID: TIntegerField;
CDSAMOUNT: TFloatField;
CDSAMOUNT_2: TFloatField;
DataGridDBTableView: TcxGridDBTableView;
DataGridLevel: TcxGridLevel;
DataGrid: TcxGrid;
DataGridDBTableViewID: TcxGridDBColumn;
DataGridDBTableViewAMOUNT: TcxGridDBColumn;
DataGridDBTableViewAMOUNT_2: TcxGridDBColumn;
procedure SetupBtnClick(Sender: TObject);
procedure DataGridDBTableViewAMOUNTPropertiesEditValueChanged(
Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.DataGridDBTableViewAMOUNTPropertiesEditValueChanged(
Sender: TObject);
begin
CDSAMOUNT_2.AsFloat:=500;
//DataGridDBTableViewAMOUNT_2.EditValue:=2.0*DataGridDBTableViewAMOUNT.EditValue;
end;
procedure TMainForm.SetupBtnClick(Sender: TObject);
var i: Integer;
begin
if CDS.Active then
CDS.EmptyDataSet
else
CDS.CreateDataSet;
DataGridDBTableView.BeginUpdate;
try
for i := 0 to 100 do begin
CDS.Append;
CDSID.AsInteger:=i;
CDSAMOUNT.AsFloat:=i*100.11;
CDSAMOUNT_2.AsFloat:=i*1000.11;
CDS.Post;
end;
finally
DataGridDBTableView.EndUpdate;
end;
end;
end.
型
和dfm:
object MainForm: TMainForm
Left = 0
Top = 0
Caption = 'MainForm'
ClientHeight = 400
ClientWidth = 784
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object SetupBtn: TButton
Left = 288
Top = 351
Width = 75
Height = 25
Caption = 'SetupBtn'
TabOrder = 0
OnClick = SetupBtnClick
end
object DataGrid: TcxGrid
Left = 8
Top = 8
Width = 761
Height = 266
TabOrder = 1
object DataGridDBTableView: TcxGridDBTableView
NavigatorButtons.ConfirmDelete = False
DataController.DataSource = DS
DataController.Summary.DefaultGroupSummaryItems = <>
DataController.Summary.FooterSummaryItems = <>
DataController.Summary.SummaryGroups = <>
object DataGridDBTableViewID: TcxGridDBColumn
DataBinding.FieldName = 'ID'
PropertiesClassName = 'TcxMaskEditProperties'
Width = 154
end
object DataGridDBTableViewAMOUNT: TcxGridDBColumn
DataBinding.FieldName = 'AMOUNT'
PropertiesClassName = 'TcxMaskEditProperties'
Properties.OnEditValueChanged = DataGridDBTableViewAMOUNTPropertiesEditValueChanged
Width = 220
end
object DataGridDBTableViewAMOUNT_2: TcxGridDBColumn
DataBinding.FieldName = 'AMOUNT_2'
PropertiesClassName = 'TcxMaskEditProperties'
Width = 156
end
end
object DataGridLevel: TcxGridLevel
GridView = DataGridDBTableView
end
end
object CDS: TClientDataSet
Aggregates = <>
Params = <>
Left = 512
Top = 336
object CDSID: TIntegerField
FieldName = 'ID'
end
object CDSAMOUNT: TFloatField
FieldName = 'AMOUNT'
end
object CDSAMOUNT_2: TFloatField
FieldName = 'AMOUNT_2'
end
end
object DS: TDataSource
DataSet = CDS
Left = 424
Top = 344
end
end
型
1条答案
按热度按时间t98cgbkg1#
我将我的问题缩小到要求“在更改一个TcxDBTableView列的同时更改另一个TcxDBTableView列值”,并且它有DevExpress https://supportcenter.devexpress.com/ticket/details/a343/how-to-set-a-value-of-another-grid-column-during-editing-of-a-cell的解决方案
在OP提供的代码的特定情况下,有2种变体:
如果为列处理EditValueChanged,则代码为:
字符串
但如果EditValueChanged是为DBTableView处理的,则代码为:
型
cxDataUtils应该被添加到使用中。
有两个关键点:1)当前列的值应该通过查找编辑器并调用
PostEditValue
发布; 2)直接赋值给DataSet或DataController.Values[...]
不起作用,应该通过SetEditValue(...)
设置值。