如何在绑定对象属性变更时通知Spring4D的TObjectDataSet
TObjectDataSet 模型属性变更后同步网格显示的解决方案
问题描述
- 直接修改DataSet字段值时,关联网格会自动更新:
ObjectDataSet.FieldByName('Description').AsString:='Bob'; - 但直接修改当前模型的属性值时,网格无更新:
ObjectDataSet.GetCurrentModel<TSaleLine>.Description:='Bob';
原因是TObjectDataSet默认不监控模型对象的属性变更,无法感知值变化,也就不会触发网格刷新逻辑。
你尝试的以下代码无效:
type TL = class(TGridDataLink); begin ObjectDataSet.GetCurrentModel<TSaleLine>.Description:='Bob'; var G:=TGridDataLink.Create(Grid); TL(G).RecordChanged(ObjectDataSet.FieldByName('Description')); G.Free; end;
无效原因是手动创建的TGridDataLink未与DataSet的现有关联绑定,属于无关实例,无法触发网格的现有更新逻辑。
解决方案
方案1:给模型添加属性变更通知,让DataSet感知变化
步骤1:让模型类实现属性变更通知逻辑
type // 定义属性变更回调类型 TPropertyChangedProc = TProc<string>; TSaleLine = class private FDescription: string; FOnPropertyChanged: TPropertyChangedProc; procedure SetDescription(const Value: string); public property Description: string read FDescription write SetDescription; // 暴露属性变更事件 property OnPropertyChanged: TPropertyChangedProc read FOnPropertyChanged write FOnPropertyChanged; end; procedure TSaleLine.SetDescription(const Value: string); begin if FDescription <> Value then begin FDescription := Value; // 属性变更时触发通知 if Assigned(FOnPropertyChanged) then FOnPropertyChanged('Description'); end; end;
步骤2:修改TObjectDataSet订阅模型的变更通知
在TObjectDataSet中,订阅当前模型的属性变更事件,触发字段更新通知:
type TObjectDataSet = class(TDataset) private FCurrentModel: TSaleLine; procedure HandleModelPropertyChanged(const PropertyName: string); procedure UpdateModelSubscription; protected procedure AfterScroll; override; procedure AfterOpen; override; end; procedure TObjectDataSet.UpdateModelSubscription; var NewModel: TSaleLine; begin // 取消旧模型的订阅 if Assigned(FCurrentModel) then FCurrentModel.OnPropertyChanged := nil; // 获取当前模型并订阅事件 NewModel := GetCurrentModel<TSaleLine>; if Assigned(NewModel) then begin FCurrentModel := NewModel; FCurrentModel.OnPropertyChanged := HandleModelPropertyChanged; end else FCurrentModel := nil; end; procedure TObjectDataSet.AfterScroll; begin inherited; // 切换记录时更新订阅 UpdateModelSubscription; end; procedure TObjectDataSet.AfterOpen; begin inherited; // 打开DataSet时初始化订阅 UpdateModelSubscription; end; procedure TObjectDataSet.HandleModelPropertyChanged(const PropertyName: string); var TargetField: TField; begin TargetField := FieldByName(PropertyName); if Assigned(TargetField) then begin // 同步字段值(从模型读取最新值) TargetField.AsString := FCurrentModel.Description; // 触发字段变更事件,通知网格更新 DataEvent(deFieldChange, NativeInt(TargetField)); end; end;
方案2:业务层手动触发更新(无需修改DataSet源码)
如果无法修改TObjectDataSet源码,修改模型属性后直接手动通知刷新:
begin ObjectDataSet.GetCurrentModel<TSaleLine>.Description:='Bob'; // 方法1:刷新指定字段并触发变更事件 with ObjectDataSet.FieldByName('Description') do begin Refresh; ObjectDataSet.DataEvent(deFieldChange, NativeInt(Self)); end; // 方法2:强制刷新网格 Grid.Invalidate; end;
内容的提问来源于stack exchange,提问作者Richard Shuck
相关产品推荐
相关产品推荐

