如果有人想知道,解决方案实施起来相当简单。我们现在有一个工作时间时钟[0:00],在客户端应用程序等待DataSnap服务器处理请求时增加。实质上,这就是我们所做的。 (特别感谢那些谁分享他们的解决方案 - 这帮助指导我的想法)
服务器生成的类(ProxyMethods)必须在VCL线程创建,但在一个单独的线程中执行。要做到这一点,我们创建了一个ProxyMethods包装类和ProxyMehtods线程类(所有这些都是人为的这个例子,但仍说明了流量):
ProxyMethods.pas
...
type
TServerMethodsClient = class(TDSAdminClient)
private
FGetDataCommand: TDBXCommand;
public
...
function GetData(Param1: string; Param2: string): string;
...
end;
ProxyWrapper.pas
...
type
TServerMethodsWrapper = class(TServerMethodsClient)
private
FParam1: string;
FParam2: string;
FResult: string;
public
constructor Create; reintroduce;
procedure GetData(Param1: string; Param2: string);
procedure _Execute;
function GetResult: string;
end;
TServerMethodsThread = class(TThread)
private
FServerMethodsWrapper: TServerMethodsWrapper;
protected
procedure Execute; override;
public
constructor Create(ServerMethodsWrapper: TServerMethodsWrapper);
end;
implementation
constructor TServerMethodsWrapper.Create;
begin
inherited Create(ASQLServerConnection.DBXConnection, True);
end;
procedure TServerMethodsWrapper.GetData(Param1: string; Param2: string);
begin
FParam1 := Param1;
FParam2 := Param2;
end;
procedure TServerMethodsWrapper._Execute;
begin
FResult := inherited GetData(FParam1, FParam2);
end;
function TServerMethodsWrapper.GetResult: string;
begin
Result := FResult;
end;
constructor TServerMethodsThread.Create(ServerMethodsWrapper: TServerMethodsWrapper);
begin
FServerMethodsWrapper := ServerMethodsWrapper;
FreeOnTerminate := False;
inherited Create(False);
end;
procedure TServerMethodsThread.Execute;
begin
FServerMethodsWrapper._Execute;
end;
你可以请参阅我们将ProxyMethod的执行分为两步。第一步是将参数的值存储在私有变量中。这允许_Execute()
方法具有执行实际ProxyMethods方法时需要知道的所有内容,其结果存储在FResult
中供以后检索。
如果ProxyMethods类具有多个函数,那么在调用方法来设置私有变量时,您可以轻松地包装每个方法并设置一个内部变量(例如,FProcID
)。这样_Execute()
方法可以使用FProcID
来知道要执行哪个ProxyMethod ...
您可能想知道为什么线程不能自行释放。原因是当线程自行清理时,我无法消除“线程错误:句柄无效(6)”错误。
调用包装类的代码如下所示:
var
smw: TServerMethodsWrapper;
val: string;
begin
...
smw := TServerMethodsWrapper.Create;
try
smw.GetData('value1', 'value2');
// start timer here
with TServerMethodsThread.Create(smw) do
begin
WaitFor;
Free;
end;
// stop/reset timer here
val := smw.GetResult;
finally
FreeAndNil(smw);
end;
...
end;
的WaitFor
挂起代码执行,直到ProxyMethods线程完成。这是必要的,因为smw.GetResult
将不会返回所需的值,直到线程完成执行。在代理执行线程繁忙时使经过时间的时钟[0:00]递增的关键是使用TJvThreadTimer
来更新UI。即使在单独的线程中执行ProxyMethod,TTimer
也不起作用,因为VCL线程正在等待WaitFor
,所以TTimer.OnTimer()
直到完成WaitFor
才会执行。
信息上的TJvTheadTimer.OnTimer()
代码看起来是这样,这将更新应用程序的状态栏:
var
sec: Integer;
begin
sec := DateUtils.SecondsBetween(Now, FBusyStart);
StatusBar1.Panels[0].Text := Format('%d:%.2d', [sec div 60, sec mod 60]);
StatusBar1.Repaint;
end;
这就是我的想法。你会认为DataSnap已经存在了多长时间,会有内置的东西来处理UI繁忙状态或者什么...... DataSnap也缺少一个回调来提示UI有多少数据已经被传输,所以UI可以为大数据检索/推送实施进度指示器。 – 2012-03-01 21:01:47
(将此标记为'正确答案',因为解决方案可以采用任何形式 - 下面的答案只是可能性而已。太糟糕了,您不能将多于'一个'的答案标记为'正确'。) – 2012-03-05 18:23:47