Tech/Silverlight2010. 5. 12. 16:28

  이전에 XAP 로딩하는 문제로 MEF를 살펴본 적이 있었는데, 그 때에는 잘 이해하지 못해 포기했었다.
  그러다, 이제와서 다시 살펴 볼 기회가 생겨 MEF에 대해 조사하게 되었다.

  이제사 간신히 예제 하나를 따라잡기 해 본 수준(?)이라고 하겠다.

  다음의 자료에서 굉장히 간단하게 MEF 예제를 놓고 설명한 동영상 자료가 있다.
  Silverlight MEF 자료 동영상

  MEF로 동적으로 .xap 파일을 로딩하는 것만 할 수 있는 것은 아니지만, 이 부분에 대해서만 중점적으로 설명하도록 하겠다.

  우선 MEF는 Silverlight 4에서 포함되어 나올 예정이다. 현재 3버전에는 없기 때문에 따로 파일을 받아야만 쓸 수 있다. 나는 MEF Preview 6 버전을 이용하여 설명하도록 하겠다.
  MEF Preview 6
  위의 사이트에는 MEF Preview 6에 관련된 정보들에 대한 설명이 갖추어져 있다. 파일을 다운 받기 위해서는, 다음과 같이 "the CodePlex site" 링크 주소를 클릭하여 다운받으면 된다.



  파일 다운로드를 다 받은 후, 압축을 해제한다.
  자, 이제 준비는 되었다.

  우선 동영상 예제때로 따라해보도록 하겠다.

  첫 번째로 해야할 일은 .dll을 참조시키는 것이다. 아까 압축 해제한 폴더에서 MEF_Preview_6\bin\SL3 폴더 아래로 이동하면, System.ComponentModel.Composition.dll 파일이 있을 것이다. 이 .dll 파일을 참조시켜야 한다.

  그 다음은 Catalog 객체를 생성해야 하는데, 우선 System.ComponentModel.Composition.dll을 개체 브라우저로 확인해보자. 여러 가지 차암~ 많다. 그 중 Catalog객체만 보면, AggregateCatalog, AssemblyCatalog, TypeCatalog, ComposableCatalog, PackageCatalog들이 있다. (이 이외에도 다른 Catalog들이 있다.) 아직 이 Catalog들의 각각의 역할을 확인하지 못했다.
  나는 이제부터 PackageCatalog를 사용할 것이다.

var catalog = new PackageCatalog();
catalog.AddPackage(Package.Current);

  Package.Current는 현재 실행 중인 어셈블리의 Package이다. 이렇게 PackageCatalog를 생성하여 현재 실행 중인 어셈블리의 Package를 추가한 뒤, CompositionContainer를 생성한다.

var container = new CompositionContainer(catalog);
CompositionBatch batch = new CompositionBatch();
batch.AddPart(this);
container.Compose(batch);

  위와 같이 CompositionContainer를 만들어 이전에 생성한 PackageCatalog를 담는다. 그 후, 지금 내가 사용하고 있는 클래스 객체와 연결하기 위해 CompositionBatch를 생성하여, Compose를 하는 이 세 줄을 container.ComposeParts(this); 한 줄로 축약시킬 수 있다. 그럼 이후부턴 생성한 CompositionContainer를 통해 Export되는 요소들을 접근할 수 있게 된다. 무슨 의미냐 하면,

  MEF 에서는 외부로 노출시켜야 할 요소들에게 태그처럼 [Export]를 명시해준다. 예를 들어, Name이라는 이름의 Property를 외부에 노출시켜야 하는 경우, 다음과 같이 정의한다.

[Export("Name")]
public string Name
{
     get
     {
          return "Incheon";
     }
}

 "Name"이라는 특정 이름으로 Name 속성이 외부로 노출되었다. 이 Name 속성을 접근하고자 하는 경우에는, 아까 생성했던 CompositionContainer를 통해 접근할 수 있다. 예를 들어, CompositionContainer.GetExport<T>()를 사용하면 된다. 하지만 이런 식의 접근보다, 바로 접근할 수 있는 짝꿍을 만들어 주는 것이 더 효율적이다. [Export]의 짝꿍은 [Import]이다. 한 마디로 Export된 속성을 받아서 쓰는 입장 쪽에서 Import로 정의된 속성을 만들어주면 된다.

[Import("Name")]
public string Name { get; set; }

  이렇게 정의한 후에, 프로그램을 실행해보면, CompositionContainer의 Compose가 실행되자마자 Import로 정의된 Name 속성 값으로 Export로 정의된 Name 속성의 value가 들어가는 것을 확인할 수 있다. 그 다음부터는 간단하게 Name 속성을 그대로 사용하면 된다.

  자, 문제는 -_- 얘네들을 어떻게 쪼물딱 해서 .xap를 동적으로 로딩하는가에 대한 문제이다.

  우선 새로운 프로젝트를 생성하여, 클래스를 추가하고, 외부로 노출시킬 요소들을 만들자.

public class NameContainer
{
    [Export("Names")]
    public string name1 = "name1";
    [Export("Names")]
    public string name2 = "name2";
    [Export("Names")]
    public string name3 = "name3";
}

  위와 같이, NameContainer라는 이름의 클래스를 생성한 뒤, "Names"라는 이름으로 외부에 노출시킬 아이들을 몇 놈 만들었다. 나는 Names로 노출된 아이들을 ListBox에 정렬하여 표현할 생각이다. 우선 내가 본래 있던 프로젝트로 돌아와 Import 짝꿍을 만들자. 나는 [Import] 대신 [ImportMany]를 사용할 것이다. [ImportMany]를 사용하는 경우 중엔 Export 되는 상대가 여러놈일 때가 있다. 하지만, 지금의 경우에는 .xap파일을 로드하여 쓰기 때문이라고 생각하는 것이 맞을 것이다.

[ImportMany("Names", AllowRecomposition = true)]
public ObservableCollection<string> Names { get; set; }

  정확한지는 모르지만, AllowRecomposition 속성은 CompositionContainer와 연결되어있는 Export들의 상태가 변경될 때마다 Update 하는 것을 허락하는 지를 나타내는 것 같다. Recomposition에 대한 설명은 다음 싸이트에 있다. 
  Recomposition and Constructors

  ImportMany로 값을 얻는 경우에는 배열이나 Collection 형태 등으로 얻어야 한다. 나는 Names라는 이름의 ObaservableCollection에 "Names"로 Export되는 아이들을 넣을 것이다.
  문제는, Export로 정의된 요소들은 모두 다른 프로젝트에 있다. 내가 원하는 것은 Export 요소들을 담고 있는 프로젝트의 .xap 결과물만을 이용해서 내가 만들어 놓은 ListBox에 출력시키고 싶다. 이런 경우에는, Export 요소들을 담고 있는 프로젝트의 .xap 결과물을 내가 본래 작업하는 프로젝트의 Web 프로젝트 폴더 내에 있는 ClientBin 폴더 아래에 복사한다. 그 후, CompositionContainer 객체를 생성하기 전에,

Package.DownloadPackageAsync(new Uri("NameContainerProject.xap", UriKind.Relative), (s, p) => catalog.AddPackage(p));
  Package.DownloadPackageAsync를 이용하여, 새로이 생성했던 프로젝트의 .xap 결과물이 위치하고 있는 경로파일을 매개변수로 넘겨지면, .xap을 다운로드 하여 Package로 만들어준다. 그 후에 CompositionCatalog에 추가하면 된다.

  이제, Names에 내용물들이 채워졌을 것이다. ListBox에 정렬시켜보자.

NameListBox.ItemsSource = Cities;

  이제 -ㅁ-) 실행시켜 보면, ListBox에 Names에 있던 요소들이 모두 출력되어 있는 것을 확인할 수 있을 것이다.
  여기서 끗!

... 이라고 하고 싶지만, 내가 원하는 형태는 애니메이션이 있는 UserControl을 Export시키고, .xap를 로드하여 UserControl을 Import로 정보를 얻어  애니메이션을 볼 수 있는 것이다. 이에 대해서는, 다음에 포스팅하도록 하겠다.
Posted by 벚꽃손님