delphi 使用EditValueChanged(TcxGrid的)捕获和处理用户执行的编辑?

agxfikkp  于 2023-11-18  发布在  其他
关注(0)|答案(1)|浏览(268)

我正在将应用程序从 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

t98cgbkg

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,则代码为:

procedure TMainForm.DataGridDBTableViewAMOUNTPropertiesEditValueChanged(
  Sender: TObject);
begin
  (Sender as TcxCustomEdit).PostEditValue;
  DataGridDBTableView.DataController.SetEditValue(
    DataGridDBTableViewAMOUNT_2.Index,
    1, evsValue);
end;

字符串
但如果EditValueChanged是为DBTableView处理的,则代码为:

procedure TMainForm.DataGridDBTableViewEditValueChanged(
  Sender: TcxCustomGridTableView; AItem: TcxCustomGridTableItem);
begin
  if AItem.Index = DataGridDBTableViewAMOUNT_2.Index then Exit;

  if DataGridDBTableView.Controller.EditingController.IsEditing then begin
    if DataGridDBTableView.Controller.EditingController.EditingItem=AItem then begin
      DataGridDBTableView.Controller.EditingController.Edit.PostEditValue;
    end;
  end;

  DataGridDBTableView.DataController.SetEditValue(
    DataGridDBTableViewAMOUNT_2.Index,
    1, evsValue);
end;


cxDataUtils应该被添加到使用中。
有两个关键点:1)当前列的值应该通过查找编辑器并调用PostEditValue发布; 2)直接赋值给DataSet或DataController.Values[...]不起作用,应该通过SetEditValue(...)设置值。

相关问题