Rich UI ハンドラー間の非 Infobus 通信

ユーザーのアプリケーションを編成する 1 つの方法は、ユーザー相互作用 (1 つの Rich UI ハンドラーで表現される) とビジネス・データのバックエンド・プロセス (2 つ目の Rich UI ハンドラーで表現される) を分離することです。このセクションでは、ハンドラー間で通信できるいくつかのメカニズム (Infobus を除く) を概説します。

組み込むハンドラーからのデータのプッシュ

最も簡単なケースでは、組み込むハンドラーが組み込みハンドラー内の関数を起動することができます。
Handler EmbeddingHandler type RUIHandler 
   { onConstructionFunction = onConstructionFunction }

   embeddedHandler EmbeddedHandler;
   
   function onConstructionFunction()
      myString STRING = "Received from somewhere";
      embeddedHandler.function01(myString);
   end
end 

委譲の使用

別の可能な方法は、組み込みハンドラーによって、組み込むハンドラー内の関数を呼び出す方法です。この場合には、組み込むハンドラーが、組み込みハンドラー内の委譲に割り当てられている値を更新します。委譲とは、特定のタイプ の関数を参照する変数です。つまり、この変数によって、特定の特性セットを持つ関数にアクセスできるようになります。

この関係の理解には、例が役立ちます。次の EGL 委譲パーツについて考えます。ここでは、パラメーターや戻り値のない関数を定義します。
delegate switchPart() end

以下に、2 つの Web ページ間の切り替え方法の例を示します。ここでは、組み込みハンドラーは Page2 で、switch という名前の委譲を宣言します。

handler Page2 type RUIHandler { onConstructionFunction = myFirstFunction, 
                                initialUI = [content] }
	
	content Box{children = [secondLabel, button], columns = 1};
	secondLabel TextLabel{text = "page2!"};
	button Button{text="switch back to first page", onClick ::= switchToFirst};
	
	//declaration of a delegate
	switch switchPart{};
	
	function myFirstFunction()
	end
	
	function switchToFirst(e Event in)
		 switch();  
	end	
end

問題は、switchToFirst 内で switch() が起動されたときにどのロジックが実行されるかです。この答えは組み込むハンドラー Page1 にあります。このハンドラーは、その独自の関数を委譲に割り当てます。

handler Page1 type RUIHandler 
  { onConstructionFunction = myFirstFunction, initialUI = [page] }
	
	 page Box{ columns = 1, children = [firstLabel, button]};
	 firstLabel TextLabel{text = "page1!"};
	 button Button{text = "switch to page 2", onClick ::= switchTo2};	
	
	 page2 Page2{};	
		
	 function myFirstFunction()
	    page2.switch = switchBack;  
	 end
	
	 function switchTo2(e Event in)
		  page.children = [page2.content];
	 end			
	
	 function switchBack()
		   page.children = [firstLabel, button];
   end
end

委譲を使用していくつかのページのいずれかにナビゲートする

前の例の拡張として、いくつかの Web ページのうちのいずれかにユーザーがその後ナビゲートするのを制御するページ・ハンドラー (MainHandler と呼びます) を定義します。また、Web アプリケーションに対する従来の方式に従って、イベントのページごとのフローを作成します。Rich UI によって、実行時イベントに応答して Web ページのパーツを更新できることに留意して、このような方式で開始できます。

次の例では、委譲パーツは文字列を使用し、戻り値はありません。
delegate SwitchToPagePart( TargetPage STRING in) end

ここでは、3 つの Rich UI ハンドラーが関係します。次は、使用可能なオプションを表示する最初の ButtonHandler の出力です。

ButtonHandler の出力

コードを検討する際は、switchFunction が委譲であること、およびこの起動によって、MainHandler (後述します) に存在するロジックが参照されることに注意してください。
handler ButtonHandler type RUIHandler{initialUI = [button1, button2, button3]}
   switchFunction SwitchToPagePart;
   button1 Button{text = "Go To Main Page", onClick::= toMain};
   button2 Button {text = "Stay Here"};
   button3 Button{text = "Go to TextField", oncLick::=toText};
   
   function toMain(e Event in)
		   switchFunction("MainHandler");
   end

   function toText(e Event in)
		   switchFunction("TextFieldHandler");
   end
end

次は、2 番目のハンドラー TextFieldHandler の出力です。

TextFieldHandler の出力

コードを検討する際は、この Rich UI ハンドラーも、SwitchToPagePart をベースとする委譲を宣言し、また、使用可能な Web ページをこのハンドラーが認識していないにもかかわらず、ユーザーは次に提示する Web ページを指定できることに注意してください。
handler TextFieldHandler type RUIHandler
   {initialUI = [instructions, Field1, myButton]}

   // a delegate
   switchFunction SwitchToPagePart;
   instructions TextLabel {text = "Type a page name and click the button."}; 
   Field1 Textfield{width = 200};
   myButton Button{text = "Go to the specified page", onClick ::= handleEvent};

   function handleEvent(e Event in)
      switchFunction(Field1.text);
   end
end
最後に、MainHandler は、テキスト「Click to see your options」を表示するのみですが、スプラッシュ画面を表示できます。次のコードには、他のハンドラーに格納されている内容を表示するロジックが含まれています。
handler MainHandler type RUIHandler{initialUI = [mainBox]}

   mainBox Box{columns = 1, children = [mainLabel]};
   mainLabel TextLabel{
      text = "Click to see your options.", 
      onClick::= mainEvent};
   buttonHandler ButtonHandler{switchFunction = switchTo};
   textFieldHandler TextFieldHandler{switchFunction = switchTo};
	
   function switchTo(target string in)
      case (strlib.upperCase(target))
         when ("TEXTFIELDHANDLER")
            mainBox.children = [textFieldHandler.instructions,
                                textFieldHandler.Field1, 
                                textFieldHandler.myButton];
         when ("BUTTONHANDLER")
            mainBox.children = [buttonHandler.button1, 
                                buttonHandler.button2, 
                                buttonHandler.button3];
         when ("MAINHANDLER")
            mainBox.children = [mainLabel];
      end
   end

   function mainEvent (e Event in)
      switchTo("ButtonHandler");
   end
end

サービスを呼び出し後に、組み込むハンドラーに通知する

組み込みハンドラーにはウィジェットがない場合がありますが、サービスを呼び出すことができます。『Rich UI でのサービスのアクセス』 で説明したように、Rich UI でのサービス呼び出しは常に非同期 です。 つまり、リクエスター (Rich UI ハンドラー) は、サービスから応答を待機することなく処理を続行します。 ユーザーは、Rich UI ハンドラーがサービスからの応答を待機している間も、ユーザー・インターフェースと対話できます。サービスは、起動された後、何らかのタスクを実行し、(ほとんどの場合) Rich UI ハンドラーにユーザーがコーディングした関数を起動することにより、リクエスターに応答します。 その関数は、コールバック関数 と呼ばれます。

組み込みハンドラーは、コールバック関数内から、組み込むハンドラーに通知することができます。次の EGL 委譲パーツについて考えます。ここでは、パラメーターや戻り値のない関数を定義します。
delegate notifyPart() end
以下に、組み込みハンドラーの概略を示します。
handler MyModel type RUIHandler { onConstructionFunction = myFirstFunction }
   //declaration of a delegate
   notify notifyPart{};

   function myFirstFunction()
      call myService.myOperation(12) returning to myCallback;
   end
	
   function myCallback(returnValue STRING)
      notify();
   end	
end
前述のように、組み込みハンドラーはその独自の関数を委譲に割り当てます。
handler MyHandler type RUIHandler { onConstructionFunction = myFirstFunction }

   theModel MyModel;

   function myFirstFunction()
      theModel.notify = myNotification();
   end

   function myNotification()
      // respond, perhaps by accessing details from the embedded handler
   end	
end

フィードバック