• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

進階DataSnap回叫功能(李维)高级delphi回调功能

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
Delphi/C++Builder 2010加入了回叫機制, 我也在2009年的部落格文章中說明了如何使用Delphi/C++Builder 2010的回叫功. 然而Delphi/C++Builder XE又再次強化了回叫機制, 讓這個功能更為強大和完善, 由於XE版的回叫機制提供了眾多新的功能, 因此我想藉由這篇文章說明一下如何使用XE版的回叫機制, 雖然我無法一次把所有的功能寫完, 但起個頭還是很有用的.
DataSnap XE在原有的基礎回叫機制之上加入了許多強大的新功能,從DataSnap XE開始開發人員可以使用下面的回叫功能:
  • 用戶端可向伺服端註冊回叫通道,如此一來伺服器可以一次回叫所有在同回叫通道中所有註冊的用戶端回叫函式
  • 用戶端可以同時註冊多個不同的回叫通道
  • 用戶端可以藉由回叫通道呼叫不同的用戶端
  • 新增回叫元件以幫助開發人員簡化開發回叫機制
DataSnap XE新的回叫功能雖然很多,但使用起來仍然相當的容易,下面說明了如何使用這些DataSnap XE新的回叫功能的基本步驟:
  • 用戶端使用TDSClientCallbackChannelManager向伺服器註冊一個回叫通道
  • 伺服器使用TDSServer元件的BroadcastMessage方法回叫所有註冊的用戶端
當然,開發人員可以更進一步的使用DataSnap XE進階的回叫功能,不過在那之前也許我們應該先說明數個範例讓讀者瞭解如何使用這些基本的步驟。
開發回叫DataSnap伺服器
在Delphi整合發展環境中建立一個DataSnap Server專案:
  • function BroadcastMessage(const ChannelName: String; const Msg: TJSONValue; const ArgType: Integer = TDBXCallback.ArgJson): boolean; overload;



  • function BroadcastMessage(const ChannelName: String; const CallbackId: String; const Msg: TJSONValue; const ArgType: Integer = TDBXCallback.ArgJson): boolean; overload;
  • 复制代码

    這兩個BroadcastMessage方法的差異在於上述第一個BroadcastMessage可以傳遞訊息給它第一個參數ChannelName指定的通道中所有的回叫用戶端,而第二個BroadcastMessage方法則是只傳遞訊息給它第一個參數ChannelName指定的通道中由第二個參數CallbackId指定的回叫用戶端,最後這個兩個BroadcastMessage方法傳遞給用戶端的訊息則由第二個參數Msg封裝。
    瞭解了如何使用BroadcastMessage方法之後,我們就可以看看如何把DataSnap伺服器中於TMemo元件中輸入的訊息傳遞給回叫用戶端。現在為主表單中的TMemo元件實作OnChange事件處理函式如下:

  • 001    procedure TForm17.mmMessageChange(Sender: TObject);

  • 002    var

  • 003      vMessage : TJSONString;

  • 004    begin

  • 005      vMessage := TJSONString.Create(mmMessage.Lines.Text);

  • 006      ServerContainer5.DSServer1.BroadcastMessage(DEMOChannel, vMessage);

  • 007    end;
  • 复制代码


    在005行我們把輸入於TMemo(mmMessage)中的資訊以TJSONString物件封裝,然後在006行藉由呼叫ServerContainer中的TDSServer元件的BroadcastMessage方法傳遞給所有註冊的用戶端。但誰是註冊的用戶端呢?請看BroadcastMessage的第一個參數DEMOChannel,這代表DataSnap伺服器會傳遞資訊給所有在DEMOChannel通道中註冊的用戶端。而DEMOChannel是一個通道的名稱,我們在DataSnap伺服器中定義它如下:
  • const

  • DEMOChannel = ‘DemoChannel’;
  • 复制代码


    因此用戶端只要使用這個名稱向伺服器註冊回叫通道的話,就可以讓DataSnap伺服器回叫用戶端,當然也用戶端可以先向伺服器查詢已經定義在DataSnap伺服器中的回叫通道名稱,或是由用戶端自行在DataSnap伺服器中建立指定名稱的回叫通道。
    由於回叫用戶端是向DataSnap伺服器中指定名稱的回叫通道註冊,而且每一個用戶端都使用一個特定的回叫識別ID來代表,因此我們也可以藉由TDSServer元件來查詢某一個名稱的回叫通道中所有註冊的用戶端回叫識別ID。
    此範例DataSnap伺服器主表單中的『列出所有回叫識別』按鈕的OnClick事件處理函式就可以在主表單上方的TListBox中列出特定回叫通道中所有的用戶端回叫識別ID,下面就是它的OnClick實作程式碼:
  • 001    procedure TForm17.Button1Click(Sender: TObject);

  • 002    var

  • 003      aIdList : TList<String>;

  • 004      sId : String;

  • 005    begin

  • 006      aIdList := ServerContainer5.DSServer1.GetAllChannelCallbackId(DEMOChannel);

  • 007      try

  • 008        for sId in aIdList do

  • 009          ListBox1.Items.Add(sId);

  • 010      finally

  • 011        aIdList.Free;

  • 012      end

  • 013    end;
  • 复制代码




    GetAllChannelCallbackId方法會回傳TList<String>型態的執行結果,其中即包含了所有在此通道名稱中註冊的用戶端回叫識別ID,因此在006行藉由TDSServer元件呼叫GetAllChannelCallbackId之後,就可以取得到在DEMOChannel中註冊的識別ID,接著從008行到012行就把這些識別ID顯示在主表單的TListBox中。
    現在請編譯並且執行此範例DataSnap伺服器,接著我們就可以實作回叫用戶端了,首先讓我們先說明如何建立Windows應用程式型態的用戶端,接著再說明如何建立瀏覽器型態的用戶端。


    開發回叫DataSnap用戶端在專案管理員中再建立一個VCL Form應用程式專案,並且在其中放入TSQLConnection,TDSClientCallbackChannelManager,TMemo,兩個TButton元件,如下圖所示。其中TSQLConnection是連結上一小節的範例DataSnap伺服器,而TDSClientCallbackChannelManager則是使用來向DataSnap伺服器註冊回叫用戶端的元件。




    接著設定TDSClientCallbackChannelManager特性值如下:
    特性名稱 特性值
    ChannelName DemoChannel
    CommunicationProtocol tcp/ip
    DSHostname localhost
    DSPort 211
    Name DemoChannelManager
    設定TDSClientCallbackChannelManager的ChannelName特性值為DemoChannel是因為前面範例DataSnap伺服器使用的通道名稱就是DemoChannel,而且前面範例DataSnap伺服器是支援TCP/IP通訊協定和使用211通信埠,因此我們需要設定TDSClientCallbackChannelManager相對應的特性值,下圖顯示了在物件檢視器中設定TDSClientCallbackChannelManager元件的特性值:
     


    設定好TDSClientCallbackChannelManager元件之後,我們就可以看看用戶端主表單中的『啟動回叫功能』按鈕的實作程式碼了:
  • 001    procedure TfmMainForm.btnStartClick(Sender: TObject);

  • 002    begin

  • 003      SetupTask;

  • 004      EnableDisableButtons(False, True);

  • 005      DemoChannelManager.RegisterCallback(callbackId, TDemoCallback.Create)

  • 006    end;

  • 007

  • 008    procedure TfmMainForm.SetupTask;

  • 009    begin

  • 010      if not scnnCallbackServer.Connected then

  • 011      begin

  • 012        scnnCallbackServer.Connected := True;

  • 013      end;

  • 014      callbackId := DateTimeToStr(Now);

  • 015      Self.Caption := callbackId;

  • 016    end;
  • 复制代码


    在btnStartClick事件處理函式中先於003行呼叫SetupTask方法以開啟TSQLConnection元件連結範例DataSnap伺服器,並且在014行根據目前的時間建立一個獨特的識別ID,callbackId。最後在005行呼叫TDSClientCallbackChannelManager元件的RegisterCallback方法向範例DataSnap伺服器註冊這個回叫用戶端。
    TDSClientCallbackChannelManager元件的RegisterCallback方法原型定義如下:
  • function RegisterCallback(const CallbackId: String; const Callback: TDBXCallback): boolean; overload;
  • 复制代码


    RegisterCallback接受兩個參數,第一個是每一個回叫用戶端的識別ID,第二個參數則是型態為TDBXCallback的物件,在前面的小節中我們已經解釋過TDBXCallback類別,因此在這裡我們需要建立一個從TDBXCallback衍生類別的物件,在這個衍生類別中我們需要複載虛擬方法Execute,如此一來範例DataSnap伺服器就可以藉由呼叫複載虛的擬方法Execute來呼叫到用戶端。
    由於我們在上面的005行是傳遞TDemoCallback物件給RegisterCallback方法,因此我們需要在這個範例用戶端應用程式中定義和實作TDemoCallback類別,它需要從TDBXCallback繼承下來:
  • type

  • TDemoCallback = class(TDBXCallback)

  • public

  • constructor Create;

  • function Execute(const Arg: TJSONValue): TJSONValue; override;

  • end;
  • 复制代码


    TDemoCallback需要實作虛擬方法Execute,當DataSnap伺服器回叫用戶端時就會執行虛擬方法Execute。由於在這個範例中我們希望範例DataSnap伺服器在TMemo中輸入的資訊能夠立刻顯示在用戶端,因此我們實作虛擬方法Execute如下:

  • 001    function TDemoCallback.Execute(const Arg: TJSONValue): TJSONValue;

  • 002    var

  • 003      sDemoMessage : String;

  • 004    begin

  • 005      Result := TJSONTrue.Create;

  • 006

  • 007      if (Arg is TJSONString) then

  • 008      begin

  • 009        sDemoMessage := TJSONString(Arg).Value;

  • 010        TThread.Synchronize(nil,

  • 011                            procedure

  • 012                            begin

  • 013                              fmMainForm.mmDemoMessage.Lines.Text := sDemoMessage;

  • 014                            end

  • 015                            );

  • 016      end;

  • 017    end;
  • 复制代码


    當DataSnap伺服器藉由回叫功能呼叫用戶端複載的Execute時,DataSnap伺服器可以把伺服端傳遞到用戶端的資訊封裝在Execute的參數Arg中。由於在前面的範例DataSnap伺服器是把在伺服端TMemo中的資訊封裝成TJSONString傳遞到用戶端,因此在007行先判斷伺服端傳遞來的是否是TJSONString型態,如果是的話,就00行取出伺服端傳遞來的資訊,接著由於我們需要把這個資訊顯示在用戶端主表單中的TMemo元件中,因此我們藉由呼叫TThread類別的類別方法Synchronize來更新用戶端的使用者介面(這是因為用戶端使用者介面的主執行緒和在背景的回叫執行緒是不同的,因此需要使用Synchronize來讓背景回叫執行緒更新主執行緒中的元件)。由於Synchronize定義了如下的原型:
  • class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);
  • 复制代码

    因此在上面的010行中我們直接使用匿名方法來更新主表單的TMemo元件。
    最後當我們不再需要讓用戶端被回叫時,可以呼叫TDSClientCallbackChannelManager元件的UnregisterCallback方法並且傳遞用戶端識別ID,例如下面的程式碼就是主表單中『停止回叫功能』按鈕OnClick事件處理函式的實作程式碼:
  • procedure TfmMainForm.btnStopClick(Sender: TObject);

  • begin
  • 该文章已有0人参与评论

    请发表评论

    全部评论

    专题导读
    上一篇:
    [导入]专利文献下载源代码(Delphi版本)发布时间:2022-07-18
    下一篇:
    DelphiTstringListStringlist的特殊用法发布时间:2022-07-18
    热门推荐
    阅读排行榜

    扫描微信二维码

    查看手机版网站

    随时了解更新最新资讯

    139-2527-9053

    在线客服(服务时间 9:00~18:00)

    在线QQ客服
    地址:深圳市南山区西丽大学城创智工业园
    电邮:jeky_zhao#qq.com
    移动电话:139-2527-9053

    Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap