티스토리 뷰



스마트클라이언트 프로그래밍을 하다보면, 웹페이지와의 연동이 필요한 부분이 생기기 마련이다.
가령, 스마트클라이언트 UI 의 특정 버튼 클릭에 의해 브라우져의 URL 이 변경된다던가, 특정 팝업창을 띄어야 한다는 등의 경우에 브라우져는 스마트클라이언트의 특정 이벤트를 감지할 필요가 있다.
 
테스트 환경은 Internet Explorer 5.5 이상 버전이면 충분하다.
 
소스를 작성하기 앞서 Delegate 와 Event 에 대한 선수 지식이 필요하므로, 필요하다면 MSDN 에서 Delegate 와 Event 에 대해서 잠시 살펴 보는것도 좋을 것 같다.


2009-06-20 아래의 샘플은 접속할 수 없습니다.
소스의 샘플은 다음의 URL 을 통해서 테스트 해 볼 수 있습니다. ( 단, CAS 권한을 설정해야 합니다 )

 
그럼 이제 구현에 들어가 보도록 하자.
 
 
Interface 를 통한 이벤트 메서드 선언
 
일반적으로 ComVisible(true) 로 설정되어 있다면, 우리는 자바스크립트로 public 으로 된 프로퍼티나 메서드 등에 바로 접근 할 수 있다.
하지만, 이벤트는 그렇지 않다. 이벤트는 Interface 를 통해 COM 에 노출 시킬 방법을 결정해야 합니다.
 
///<summary>
/// COM 에 노출할 이벤트 메서드
///</summary>
[Guid("F9F21A39-FC35-4503-95E1-FBB13E749C3E")]
[InterfaceType( ComInterfaceType.InterfaceIsIDispatch )]
public interface IUmcClick
{
         [DispId(0x60020000)]
         void UmcClick();
 
         [DispId(0x60030000)]
         void UmcParamClick( string param );
}
[코드1] COM 에 노출시킬 Interface 정의
 
[InterfaceType( ComInterfaceType.InterfaceIsIDispatch )] 구문을 통해 COM 에 노출시키는 방법을 결정합니다.
 
[DispId(0x60020000)] 구문을 통해 디스패치 식별자를 각각의 이벤트마다 서로 다르게 지정합니다.
 
아직 저 또한, COM 에 대해 구구절절 설명해 줄만큼 잘 알지 못하고, 위에서 사용된 Attribute 은 공식처럼 사용된다는 것 정도만 알아 두면 될 것 같다.
 
 
UI 에서의 이벤트 발생
 
다음 UserControl 코드는 두개의 버튼을 올려 놓았으며,
각각 버튼은 인자가 없는 버튼과, 인자를 전달하는 이벤트에 대한 소스입니다.
 
[ClassInterface( ClassInterfaceType.AutoDual)]
[ComSourceInterfaces(typeof(IUmcClick))]
public partial class UserControl1 : UserControl
{
         // 인자없는 이벤트
         public delegate void UmcClickHandler();
         public event UmcClickHandler UmcClick;
 
         // 문자열 인자를 넘길 이벤트
         public delegate void UmcParamClickHandler( string param );
         public event UmcParamClickHandler UmcParamClick;
 
         public UserControl1()
         {
                  InitializeComponent();
         }
 
         ///<summary>
         /// Raise Event
         ///</summary>
         private void OnUmcClick()
         {
                  if( UmcClick != null )
                      Invoke( UmcClick, null );
         }
 
         ///<summary>
         /// Raise Event
         ///</summary>
         private void OnParamUmcClick()
         {
                  // 인자값을 넘긴다.
                  if( UmcParamClick != null )
                      Invoke( UmcParamClick, "스마트클라이언트가 전달한 메세지");
         }
 
         private void button1_Click(object sender, EventArgs e)
         {
                  OnUmcClick();
         }
 
         private void button2_Click(object sender, EventArgs e)
         {
                  OnParamUmcClick();
         }
}
[코드2] UserControl 의 두개 버튼에 대한 이벤트 발생
 
public delegate void UmcClickHandler();
public event UmcClickHandler UmcClick;
 
이벤트를 발생시키기 위해 델리게이트와 이벤트를 선언하였다.
 
if( UmcClick != null )
    Invoke( UmcClick, null );
 
이 구문을 통해 이벤트를 발생을 시킵니다.
 
위 두 부분이 잘 이해가 되지 않는다면, 이벤트에 대해 좀 더 학습 해야 할 것 같다.
 
한가지 주의할 것은, Interface 를 통해 선언한 이벤트메서드와 UI부분의 event 의 네이밍을 맞춰주도록 하자. 그렇지 않으면 이벤트를 자바스크립트에서 제대로 받기가 힘들다.
 
[주의] 위 처럼 이벤트와 Interface 메서드의 네이밍을 맞추어주자.
 
 
HTML 에서 이벤트 받기
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>SmartClient 와익스플로러의연동</title>
    `<script event="UmcClick" for="control1">
                  alert('인자없는이벤트전달받음');
    </script>
         <script event="UmcParamClick(a)" for="control1">
                  alert(a);
         </script>
</head>
<body>
    <form id="form1">
    <div>
                  <object id="control1" classid="SmartClient1.DLL#SmartClient1.UserControl1"></object>
    </div>
    </form>
</body>
</html>
[코드3] test.html
 
<object id="control1" classid="SmartClient1.DLL#SmartClient1.UserControl1"></object>
 
Object 태그를 통해 웹에 우리가 만든 UserControl 이 엠베디드 될 것이다.
 
<script event="UmcClick" for="control1">
<script event="UmcParamClick(a)" for="control1">
 
위의 script 태그를 통해 엠베디드 된 스마트클라이언트의 이벤트를 받게 된다.
주목할 것은 두번째 태그이다. 인자가 없는 이벤트는 단지 이벤트 네이밍만 명시하면 되지만, 인자가 있을 경우는 인자로 받을 임의의 변수를 지정해 주도록 하자.
 
그럼 인자를 받는 이벤트의 결과만 보도록 하자.
 
[그림2] 스마트클라이언트가 전달한 이벤트
 
 
UserControl 에서 우리는 다음과 같은 메시지를 전달하였다.
 
Invoke( UmcParamClick, "스마트클라이언트가 전달한 메세지");
 
 
CAS 설정하기
 
브라우져에서 UI 의 이벤트를 전달받기 위해선 CAS 권한 제약을 받는다.
간단한 검색만으로 권한을 추가할 수 있을 거라고 생각한다.
 
 
 
 
재미있는 문제
 
UserControl 의 생성자에 다음과 같은 구문을 추가해 보자.
 
public UserControl1()
{
         InitializeComponent();
 
         button1.Click += new EventHandler(delegate(object sender, EventArgs e) {
                           MessageBox.Show("UI 에서 연결한 이벤트");
                  } );
}
 
신기한 구문이다. 위 구문은 익명 메서드라는 것으로, 메서드 구현하지 않고, 대리자를 통해 메서드의 구현을 위임하는 코드이다.
 
그럼 문제를 내도록 하겠다.
UI 에 브라우져에 엠베디드 될 것이고, HTML 에서 자바스크립트로 이벤트를 구현하는 부분이 있다.
하지만, UI 에 이미 버튼에 대한 이벤트를 연결하였다.
 
그럼 두 이벤트중 누가 먼저 실행될까???
 
처음 나는, 오직 자바스크립트 이벤트만 실행될 거라고 생각했다. 자바스크립트는 C# 코드의 이벤트 등록 연산자(+=) 를 못 알아 먹을거라고 생각했기 때문이다.
 
하지만… 결과는 ㄷ ㅐ 반전이다.
자바스크립트의 이벤트가 먼저 발생되고, C# 코드의 이벤트가 발생한다.
 
결과를 보면 분명, 이벤트라는 것이 마지막에 등록된 이벤트의 꽁무니에 등록이 되어야 당연하다고 생각했는데, 자바스크립트의 script event 구문은 무척이나 당황한 결과를 만들어 내었다.
 
 
마치며
 
점점 스마트클라이언트 프로젝트가 활성화 되고, 언젠가는 스마트클라이언트를 접할 기회가 올 거라고 확신하다. Internet Explorer 에 종속적인 기술이긴 하지만, 점점 사양되는 ActiveX 보다 월등히 닷넷스런(?) 기술이다.
아직까지 이해할 수 없는 배포 관련 이슈들이 남아 있지만, 언젠가는 트러블 슈팅할 날이 올 거라고 생각한다.
댓글