Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 7 of 7 total
Thread Wait for event
Tue, Jul 30 2013 10:36 AMPermanent Link

Christian Kaufmann

I use one TDataset object from different consumer classes. The first
time when it is used, I have to load the data -> this causes an async
call.

What is the pattern for this? Since I don't know, which class will be
the first user, who causes the load, I cannot work with the AfterLoad
event of the TDataSet.

I need more a solution like this:

MyDataSet.EnsureLoaded;

while not MyDataSet.IsReady do begin
 // wait ????
end;


I know, this is bad in javascript, because it seems to block
everything.

I could do:

MyDataSet.EnsureLoaded(AfterLoadEvent);

But it could happen, that such calls overlap, when called from
different places. What I would need for this is some kind of multicast
event.

I'm just interested how others solved this problem?

cu Christian
Tue, Jul 30 2013 11:23 AMPermanent Link

Matthew Jones

I can't quite work out if a state-machine is what is needed. But I use state
machines for most things I do which are async. I'd code it a bit like:

procedure RunStateMachine;
begin
case CurrentState do
csWait:
begin
   if UserRequestA then
   begin
     LoadData;
     SetState(csLoading);
   end
   else if UserRequestB then
   begin
     LoadData;
     SetState(csLoading);
   end;
end;

csLoading:
 begin
 end;
 
csLoaded:
   if UserRequestA then
   begin
     ShowDataA;
     SetState(csWait);
   end
   else if UserRequestB then
   begin
     ShowDataB;
     SetState(csWait);
   end;
end;        

procedure LoadDataComplete;
begin
   SetState(csLoaded);
   RunStateMachine;
end;

procedure OnButtonClickA;
begin
   UserRequestA := true;
   RunStateMachine;
end;

I'd normally run the state machine on a timer too, but that isn't necessary. All
that is quite crude, but I hope it gives the idea of what I mean. These things
grow!

/Matthew Jones/
Wed, Jul 31 2013 1:08 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Christian,

<< I use one TDataset object from different consumer classes. The first time
when it is used, I have to load the data -> this causes an async call.

What is the pattern for this? Since I don't know, which class will be the
first user, who causes the load, I cannot work with the AfterLoad event of
the TDataSet. >>

Matthew's solution is pretty much the only way to deal with such scenarios
since you have to have an "outer" set of code that is controlling the flow
because the flow is no longer implicit in the calling order with asynch
requests.

Tim Young
Elevate Software
www.elevatesoft.com
Wed, Jul 31 2013 1:23 PMPermanent Link

Christian Kaufmann

Here is my solution for the problem:


 TBSDataSet = class(TDataSet)
 private
   // TODO : Only needed because problem with compiler???
   fdummy : TNotifyEvent;
   FAfterLoads  : array of TNotifyEvent;
 protected
   procedure DoAfterLoad; override;
 public
   procedure EnsureLoaded(AAfterLoad: TNotifyEvent);
 end;


procedure TBSDataSet.DoAfterLoad;
var
 ix : Integer;       
 e  : TNotifyEvent;
begin
 inherited DoAfterLoad;
 for ix := 0 to Length(FAfterLoads) - 1 do begin
   fdummy := FAfterLoads[ix];
   fdummy(Self);
 end;
end;

procedure TBSDataSet.EnsureLoaded(AAfterLoad: TNotifyEvent);
var
 n : Integer;
begin      
 if State <> dsClosed then begin
   // Data is already loaded. Call the event immediately
   fdummy := AAfterLoad;
   fdummy(Self);
   Exit;
 end;  
 // Add the event to the list of events      
 n := Length(FAfterLoads);
 SetLength(FAfterLoads, n + 1);
 FAfterLoads[n] := AAfterLoad;
 // If this is the first event, then start a server request to load
 // the data
 if n = 0
   // this is my own implementation. Basically it's a TServerRequest
   // and in the OnComplete event I load columns and rows
   then BSServer.ExecuteDataSetOld(FRequestName, Self, FParams);
end;


cu Christian
Tue, Aug 6 2013 11:58 AMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Christian,

<< Here is my solution for the problem: >>

Nice job.

What's this comment about in the code ?

"   // TODO : Only needed because problem with compiler???"

Is there an issue with calling an event handler when it's in an array ?

Thanks,

Tim Young
Elevate Software
www.elevatesoft.com
Wed, Aug 7 2013 1:31 AMPermanent Link

Christian Kaufmann

>Is there an issue with calling an event handler when it's in an array ?

Yes. Here is a sample. Both calls to the event method give a compiler
error:

procedure TMyDataSet.EnsureLoaded(AAfterLoad: TNotifyEvent);
var
 tmp : array of TNotifyEvent;
begin                       
 if Assigned(AAfterLoad) then begin
   SetLength(tmp, 1);
   tmp[0] := AAfterLoad;
   tmp[0](Self);     <<<<<<<<<<<<<<<
   AAfterLoad(Self);   <<<<<<<<<<<<<
 end;
end;


cu Christian
Wed, Aug 14 2013 1:37 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Christian,

<< Yes. Here is a sample. Both calls to the event method give a compiler
error: >>

Got it, thanks.  A fix will be in the next build.

Tim Young
Elevate Software
www.elevatesoft.com
Image