把 DataModule 的事件放在 Form 中處理

例如: 把 DataModule 中的某個 DataSource 的 OnStateChange 事件
      指定到 Form1 的自定函數 MyStateChange.
如此做法看似將 DataModule 及 Form 的關係複雜化 (增加藕合度),
但實則將 DataModule 公開出一個彈性的界面, 使得你無須在 DataModule
中存取 Form 的物件

注意事項:
  如果在這些事件中發生了 Exception, 則無法單步追蹤到, 除非你在這
  些事件中設立中斷點, 否則你可能會發生一些很奇怪的狀況, 例如: 資
  料表無法開啟, 程式出現 Access violation...的訊息. 所以請盡量在
  這些事件中事先檢查要使用的物件是否為NULL或者用try...except
  把程式碼包住!!!

請看下面的範例:
  DMod 是一個 TDataModule 的物件, DMod 中有下列物件:
    DataSource1
    Table1  
程式如下:
-----------------
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
  public
    procedure MyStateChange(Sender: TObject);
    procedure MyDataChange(Sender: TObject; Field: TField);
    procedure MyAfterScroll(DataSet: TDataSet);
  end;

var
  Form1: TForm1;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  // 以下的三行敘述也可以放在 FormShow 或 FormActive 事件中
  DMod.DataSource1.OnStateChange := MyStateChange;
  DMod.DataSource1.OnDataChange := MyDateChange;
  DMod.Table1.AfterScroll := MyAfterScroll;
  
  DMod1.Table1.Open;
end;  

procedure TForm1.MyAfterScroll(DataSet: TDataSet);
begin
  if Assigned(DataSet) and DataSet.Active then
  begin
    // 不管怎樣先檢查要用的物件是否已配置好, 安全第一
    if StatusBar1 <> nil then  
      StatusBar.SimpleText := IntToStr(DataSet.RecordCount);
  end;
end;

procedure TForm1.MyStateChange(Sender: TObject);
var
  IsEditing: Boolean;
begin
  // 用一個 try...except 確保 Exception 不會沒人處理而導致
  // 其他更嚴重的錯誤
  try
    if DMod.Table1.Active then
    begin
      IsEditing := (DMod.Table1.State in [dsEdit, dsInsert]);
      edAddress.Enabled := IsEditing;
    end;
  except
    // 忽略錯誤
  end;
end;

procedure TForm1.MyDataChange(Sender: TObject; Field: TField);
begin
  {....}
end;

    Source: geocities.com/huanlin_tsai/faq

               ( geocities.com/huanlin_tsai)