WCF 서비스를 이용한 Silverlight 구현 소스 참고

ü  Sharepoint 서버에 구현하였던 WCF서비스 파일 배포

1.     WCF 서비스 가상 디렉토리 생성하여 해당 디렉토리에 WCF 서비스 전담으로 만들었던 웹사이트 프로젝트의 파일을 아래 그림과 같이 배포합니다.


 -   Bin 폴더에 dll파일 배포 하지 않고, GAC에 등록하여 svc파일 상단에 아래에 음영 부분을 추가시켜 주시면 됩니다.

Code

Service.svc

<%@ Assembly Name="WCFServiceLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f1a7a4b23352b442"%>

<%@ ServiceHost Debug="true" Language="C#" Service="WCFServiceLibrary.ProductService" %>


2.     생성한 가상디렉토리는 익명 액세스 가능하게 체크합니다.

 

3.     Service.svc 파일을 선택한 후, 마우스 오른쪽 버튼을 클릭하여 웹 페이지로 보기항목을 선택하여 웹 페이지를 보면 Sharepoint 웹사이트에서는 VirtualPath에 관련된 아래와 같은 에러 화면을 볼 수 있습니다.

4.     VirtualPath 해결 방안 (관련 링크)

-     클래스 라이브러리 프로젝트를 만듭니다.

-   자동으로 생성된 Class1.cs파일은 삭제하고 System.Web.dll을 참조시킵니다.

  아래 두 클래스를 추가하여 줍니다.

Code

WCFPatchupModule.cs

public class WCFPatchupModule : IHttpModule

{

    private static bool virtualPathProviderInitialized;

    private static readonly object virtualPathProviderInitializedSyncLock = new object();

 

    public void Dispose()

    {

    }

 

    public void Init(HttpApplication context)

    {

        if (!virtualPathProviderInitialized)

        {

            lock (virtualPathProviderInitializedSyncLock)

            {

                if (!virtualPathProviderInitialized)

                {

                    WCFVirtualPathProvider virtualPathProvider = new WCFVirtualPathProvider();

                    HostingEnvironment.RegisterVirtualPathProvider(virtualPathProvider);

                    virtualPathProviderInitialized = true;

                }

            }

        }

    }

}

 

WCFVirtualPathProvider.cs

public class WCFVirtualPathProvider : System.Web.Hosting.VirtualPathProvider

{

    public override string CombineVirtualPaths(string basePath, string relativePath)

    {

        return base.Previous.CombineVirtualPaths(basePath, relativePath);

    }

 

    public override ObjRef CreateObjRef(Type requestedType)

    {

        return base.Previous.CreateObjRef(requestedType);

    }

 

    public override bool FileExists(string virtualPath)

    {

        string str = virtualPath;

        if (virtualPath.StartsWith("~", StringComparison.Ordinal) && virtualPath.EndsWith(".svc", StringComparison.InvariantCultureIgnoreCase))

        {

            str = virtualPath.Remove(0, 1);

        }

        return base.Previous.FileExists(str);

    }

 

    public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)

    {

        return base.Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);

    }

 

    public override string GetCacheKey(string virtualPath)

    {

        return base.Previous.GetCacheKey(virtualPath);

    }

 

    public override VirtualDirectory GetDirectory(string virtualDir)

    {

        return base.Previous.GetDirectory(virtualDir);

    }

 

    public override VirtualFile GetFile(string virtualPath)

    {

        return base.Previous.GetFile(virtualPath);

    }

 

    public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)

    {

        return base.Previous.GetFileHash(virtualPath, virtualPathDependencies);

    }

}

-     어셈블리 서명을 추가해주고, 해당 어셈블리 파일을 GAC에 등록합니다.

-     해당 웹사이트의 Web.Config 파일을 보면, <httpModules>세션에 음영된 부분을 추가합니다

Code

Web.Confing

<httpModules>

  <clear />

  <add name="SPRequest" type="Microsoft.SharePoint.ApplicationRuntime.SPRequestModule, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

  <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />

  <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />

  <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />

  <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />

  <add name="RoleManager" type="System.Web.Security.RoleManagerModule" />

  <!-- <add name="Session" type="System.Web.SessionState.SessionStateModule"/> -->

  <add name="PublishingHttpModule" type="Microsoft.SharePoint.Publishing.PublishingHttpModule, Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

  <!-- Ajax & SIlverlight -->

  <add name="Session" type="System.Web.SessionState.SessionStateModule" />

  <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

  <add name="WCFVirtualPathProvider" type="WCFVirtualPathProvider.WCFPatchupModule, WCFVirtualPathProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2bea20c5375d001d"/>

</httpModules>

-   Service.svc 파일을 웹 브라우저로 열어 서비스가 정상 작동하지는 확인합니다.

ü  Silverlight 응용 프로그램 프로젝트 수정하기

1.     기존에 만든 Silverlight 프로젝트를 열어 참조된 서비스를 클릭하고 서비스 참조 구성이라는 항목을 선택합니다.

2.    클라이언트 주소가 나오는데 배포한 WCF 서비스 URL로 변경합니다. 업데이트 진행 상태가 나타나며, 문제가 없으면 업데이트가 완료됩니다.

ü  Sharepoint Silverlight WebPart 만들기

1.  Sharepoint 웹파트 추가 하는 종류

-   IIS Silverlight 전담 웹사이트를 만들고 배포한 후 Sharepoint의 기본 웹파트 중에 하나인 페이지 뷰어 웹파트를 이용하여 실버라이트를 보여주는 방법이 있습니다.

-   System.Web.UI.SilverlightControls.Silverlight 컨트롤을 사용하여 웹파트 클래스를 만드는 방법이 있습니다.

2.  우선 여기서는 Silverlight 컨트롤을 이용하여 웹파트를 추가하도록 하겠습니다. 새 프로젝트 추가합니다. (프로젝트 형식은 클래스 라이브러리을 선택합니다.)

-   실버라이트 응용 프로그램 빌드 후, xap 파일을 _layouts의 특정 폴더 배포합니다. )다른 방법으로는 문서 라이브러리 등에 배포 하셔도 상관없습니다.)

-  Silverlight 웹파트 클래스 만들기

Code

DemoSilverlight.cs

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using Microsoft.SharePoint;

 

namespace SilverlightWebParts

{

    public class DemoSilverlight : Microsoft.SharePoint.WebPartPages.WebPart

    {

        protected override void OnLoad(EventArgs e)

        {

            base.OnLoad(e);

 

            ScriptManager sm = ScriptManager.GetCurrent(this.Page);

            if (sm == null)

            {

                sm = new ScriptManager();

                Controls.AddAt(0, sm);

            }

        }

 

        protected override void CreateChildControls()

        {

            base.CreateChildControls();

 

            System.Web.UI.SilverlightControls.Silverlight ctrlSilverlight = new System.Web.UI.SilverlightControls.Silverlight();

            ctrlSilverlight.ID = "SilverlightControl";

            ctrlSilverlight.Source = SPContext.Current.Web.Url + "/_layouts/Silverlight/SilverlightApplication.xap";

            ctrlSilverlight.Width = new Unit(600);

            ctrlSilverlight.Height = new Unit(400);

 

            this.Controls.Add(ctrlSilverlight);

        }

    }

}

Description

ð  로드 이벤트(OnLoad 이벤트)에 보시면 ScriptManager 라는 컨트롤이 추가되어 있는데, 반드시 추가하여야 합니다. 클래스 안에 추가하는 방법 말고, 마스터 페이지 상단에 <asp:ScriptManager ID=”ScriptManager1” ></asp:ScriptManager>라고 추가하셔도 됩니다.

ð Silverlight 컨트롤에 많은 속성들이 있는데 그 중에 Source를 보시면 xap파일(Silverlight 패키지 파일)을 배포한 URL 주소가 들어 있습니다.

3.    해당 dll 파일을 GAC에 등록하시고, Sharepoint 웹파트 갤러리에 추가한 후, 원하는 화면에 웹파트를 추가하시면 아래와 같은 Silverlight 웹파트가 완성됩니다.

ü  Install .NET 3.5 Framework SP1 in Sharepoint Server

ü  Windows Sharepoint Service 3.0 SP1 & MOSS 2007 SP1

ü  GAC System.Web.Silverlight.dll 등록

1.    저장 폴더 위치

-       Microsoft Silverlight Tools for Visual Studio 2008 SP1 개발 환경이 구성되어 있거나 Silverlight 2 SDK 설치(링크)하면, C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Server 폴더 안에 System.Web.Silverlight.dll이 존재합니다.

ü  IIS MIME Type 정의

1.     인터넷 정보 서비스 관리 창을 뜨웁니다.

-       시작 실행에서 inetmgr 명령어를 입력하여 실행하여 Silverlight 적용시킬 Sharepoint 웹사이트의 속성 창을 엽니다.

-       HTTP 헤더 탭을 선택한 후, MIME 형식 버튼을 클릭합니다.

-       MIME 형식 창이 나타나며, 새 형식 버튼을 클릭하여 확장명에 .xap, MIME 형식에 application/x-silverligth-app을 등록합니다.

=>

ü  Sharepoint 웹사이트 해당 포트에 대한 Web.Config 수정

-       Web.config (C:\Inetpub\wwwroot\wss\VirtualDirectories\포트번호)에 아래와 같이 음영 처리된 부분을 추가합니다.

1.     WCF 서비스를 구동시키기

-       서비스를 담당할 전담 웹사이트 프로젝트를 만듭니다.


-       저장 위치를 지정하고, WCF 서비스 항목을 선택합니다.


-       App_Code폴더와 그 안에 IService.cs, Service.cs 파일 그리고, Service.svc 파일이 자동 생성된 것을 볼 수 있는데, 서비스 구현은 이미 했기 때문에 Service.svc파일을 제외한 두 개의 파일들을 과감하게 삭제 해버립니다.


-       참조 추가 항목을 선택하고, WCF서비스 라이브러리 프로젝트 항목을 선택합니다. 그리고, Bin 폴더에 dll이 잘 추가된 것을 볼 수 있습니다.

 

-       Service.svc 파일을 수정합니다.

자동 생성되었던 Service.svc

<%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %>

 

수정된 Service.svc

<%@ ServiceHost Debug="true" Language="C#" Service="WCFServiceLibrary.ProductService" %>

ð  기존 파일에는 Service태그에 클래스명을 지정되어 있고, CodeBehind에 해당 코드 주소를 입력하였으나, 별도의 컴포넌트로 구현하였기에, 컴포넌트 이름에 해당 서비스 클래스명을 지정해 주면 됩니다.

-       Web.config 수정하여야 하는데, 전에 app.config 파일을 WCF 구성 편집 항목을 통해 수정해 본 적이 있습니다. 그 방식과 같이 WCF서비스 구성을 편집합니다. (9번 항목)

-       Web.config 파일을 열어 보면 <system.serviceModel>부분을 제외하고 나머지는 과감하게 삭제해버립니다.

Web.config

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <system.serviceModel>

    <behaviors>

      <serviceBehaviors>

        <behavior name="ServiceBehavior">

          <serviceMetadata httpGetEnabled="true" />

          <serviceDebug includeExceptionDetailInFaults="false" />

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <services>

      <service behaviorConfiguration="ServiceBehavior" name="WCFServiceLibrary.ProductService">

        <endpoint address="" binding="basicHttpBinding" bindingConfiguration=""

          contract="WCFServiceLibrary.IProductService">

          <identity>

            <dns value="localhost" />

          </identity>

        </endpoint>

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

      </service>

    </services>

  </system.serviceModel>

</configuration>

-       WCFServiceWebSite 웹사이트의 속성에 가상 경로가 “/”가 아닌 다른 경로가 지정된 경우가 있는데, “/”로 수정합니다. 조금 있다 알게 되겠지만, 정책 파일을 찾는 경로는 웹사이트 최상위 루트이기 때문에 바꿔주어야 합니다.

 

-       Service.svc브라우저에서 보기 항목을 선택하여 잘 구동되는지를 확인합니다.


-       WCF 테스트 브라우저 창을 통해 WCF 서비스 역할이 잘 작동하는지 확인한 적이 있습니다. 웹사이트에서도 잘 되는지 확인하겠습니다. Visual Studio 2008 명령 프롬프트를 선택하고, cmd창이 나타나는 것을 볼 수 있습니다. (cmd창에서 Visual Studio 2008 설치 경로\VC로 들어가시면 됩니다. 기본 설치시 C:\Program Files\Microsoft Visual Studio 9.0\VC 입니다.)


-       좀 전에 svc 파일을 브라우저에서 봤었는데, cmd창에 명령어를 “wcfTestClient + 브라우저에서 봤던 url”를 입력하시면 WCF 테스트 브라우저 창이 나타나며, 전에 했던 방식으로 서비스 역할 테스트를 해보시면 됩니다. (부가 설명은 하지 않겠습니다.)


2.     Silverlight 응용 프로그램 만들기 (위에서 설명한 바가 있어, 자세한 설명은 하지 않겠습니다)

-       솔루션에 새 프로젝트 추가 한 후, 프로젝트명과 저장 경로를 지정하고, Silverlight 응용 프로그램을 선택합니다.

-       Silverlight를 호스팅할 웹 사이트 지정하는 브라우저 창이 나타나며, WCFServiceWebSite WCF 서비스 전담으로 만든 프로젝트이므로, “솔루션에 Silverlight를 호스팅할 새 ASP.NET 웹 프로젝트 추가항목을 선택하여 웹 사이트를 추가합니다.

-       Silverlight 영역에 DataGrid 컨트롤 및 각 이벤트의 버튼을 추가하여 UI을 구상합니다. Microsoft Blend2를 실행시켜 디자인 작업하면 손쉽게 진행할 수 있습니다.

Code

Page.xaml

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="SilverlightApplication.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >

    <Grid x:Name="LayoutRoot" Background="White">

        <Grid.RowDefinitions>

            <RowDefinition Height="60"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

        </Grid.RowDefinitions>

       

<StackPanel Orientation="Horizontal" Grid.Row="0">

            <Button x:Name="btnSelect" Width="60"  Height="35" Margin="5" Content="보기"></Button>

            <Button x:Name="btnInsert" Width="60"  Height="35" Margin="5" Content="추가"></Button>

            <Button x:Name="btnUpdate" Width="60"  Height="35" Margin="5" Content="수정"></Button>

            <Button x:Name="btnDelete" Width="60"  Height="35" Margin="5" Content="삭제"></Button>

        </StackPanel>

<data:DataGrid Grid.Row="1"></data:DataGrid>

    </Grid>

</UserControl>

-       Silverlight 응용 프로젝트에 WCF 서비스를 참조합니다. 좀전에 WCF 서비스 전담 웹사이트에서의 svc 파일 URL을 주소에 입력하고 이동하면, 문제가 없다면 인터페이스 목록이 나타납니다. 그리고 서비스 참조 네임스페이스를 입력하고 추가합니다.


-       UI 구성 및 서비스 참조가 완료한 후, 모든 버튼의 이벤트 함수를 구현하기에 앞 서, “보기 버튼에 대한 이벤트를 구현해보겠습니다.

Code

Page.xaml

<!-- 생략 -->

<StackPanel Orientation="Horizontal" Grid.Row="0">

    <Button x:Name="btnSelect" Width="60"  Height="35" Margin="5" Content="보기" Click="btnSelect_Click"></Button>

    <Button x:Name="btnInsert" Width="60"  Height="35" Margin="5" Content="추가" Click="btnInsert_Click"></Button>

    <Button x:Name="btnUpdate" Width="60"  Height="35" Margin="5" Content="수정" Click="btnUpdate_Click"></Button>

    <Button x:Name="btnDelete" Width="60"  Height="35" Margin="5" Content="삭제" Click="btnDelete_Click"></Button>

</StackPanel>

<data:DataGrid Grid.Row="1" x:Name="dlResult" Background="Beige"></data:DataGrid>

<!-- 생략 -->

 

Page.xaml.cs

public partial class Page : UserControl

{

    ProductDBService.ProductServiceClient serivce = new ProductDBService.ProductServiceClient();

 

    public Page()

    {

        InitializeComponent();

    }

 

    private void btnSelect_Click(object sender, RoutedEventArgs e)

    {

        serivce.SelectProductAsync();

        serivce.SelectProductCompleted += new EventHandler<SelectProductCompletedEventArgs>(serivce_SelectProductCompleted);

    }

 

    void serivce_SelectProductCompleted(object sender, SelectProductCompletedEventArgs e)

    {

        dlResult.ItemsSource = e.Result;

    }

 

    private void btnInsert_Click(object sender, RoutedEventArgs e) {  }

 

    private void btnUpdate_Click(object sender, RoutedEventArgs e) {  }

 

    private void btnDelete_Click(object sender, RoutedEventArgs e) {  }

}

Description

ð  WCF 서비스에 노출된 서비스를 보면, Async 함수와 Completed 이벤트를 가지게 되는 것을 볼 수 있습니다. 간단히 설명드리면, Async 함수로 필요한 인자를 넣고 실행시키면, Completed 이벤트 함수에서 Result(WCF 서비스 호출한 데이터)를 보내주는 방식입니다.


ð  DataList 컨트롤에 서비스 호출하여 Select한 데이터를 바인딩한 후, 잘 동작하는 지 실행(F5)합니다. 하지만, 아래와 같은 오류가 발생하는 것을 볼 수 있으며, IE 개발 툴인 HttpWatch, Fidder, WebDevHelper 등을 이용하여 조회하여 보면, 2개의 파일에서 404. 파일이 없다는 결과를 볼 수 있습니다.


ð  Silverlight는 크로스 도메인에 대해서 제약이 되어 있다고 설명한 바가 있습니다. 크로스 도메인 접근을 위해서는 웹사이트의 최상위 루트 디렉토리에 보안 정책 파일인 clientaccesspolicy.xml 파일과 crossdomain.xml 파일을 배포하여야 합니다.

(참고 : Silverlight 2.0 Tutorial)

-       보안 정책 파일을 WCF 서비스 웹사이트의 최상위 루트에 배포한 후, 다시 실행하면, 잘 작동하는 것을 볼 수 있습니다.


-       마지막으로 남은 버튼의 이벤트도 구현하겠습니다.

Code

public partial class Page : UserControl

{

    ProductDBService.ProductServiceClient serivce = new ProductDBService.ProductServiceClient();

 

    public Page()

    {

        InitializeComponent();

    }

 

    private void btnSelect_Click(object sender, RoutedEventArgs e)

    {

        serivce.SelectProductAsync();

        serivce.SelectProductCompleted += new EventHandler<SelectProductCompletedEventArgs>(serivce_SelectProductCompleted);

    }

 

    void serivce_SelectProductCompleted(object sender, SelectProductCompletedEventArgs e)

    {

        dlResult.ItemsSource = e.Result;

    }

 

    private void btnInsert_Click(object sender, RoutedEventArgs e)

    {

        Products product = new Products();

        product.ProductName = "TEST";

 

        serivce.InsertProductAsync(product);

        serivce.InsertProductCompleted += new EventHandler<InsertProductCompletedEventArgs>(serivce_InsertProductCompleted);

    }

 

    void serivce_InsertProductCompleted(object sender, InsertProductCompletedEventArgs e)

    {

        Refresh(e.Result);

    }

 

    private void btnUpdate_Click(object sender, RoutedEventArgs e)

    {

        serivce.UpdateProductAsync(dlResult.SelectedItem as Products);

        serivce.UpdateProductCompleted += new EventHandler<UpdateProductCompletedEventArgs>(serivce_UpdateProductCompleted);

    }

 

    void serivce_UpdateProductCompleted(object sender, UpdateProductCompletedEventArgs e)

    {

        Refresh(e.Result);

    }

 

    private void btnDelete_Click(object sender, RoutedEventArgs e)

    {

        serivce.DeleteProductAsync((dlResult.SelectedItem as Products).ProductName);

        serivce.DeleteProductCompleted += new EventHandler<DeleteProductCompletedEventArgs>(serivce_DeleteProductCompleted);

    }

 

    void serivce_DeleteProductCompleted(object sender, DeleteProductCompletedEventArgs e)

    {

        Refresh(e.Result);

    }

 

    private void Refresh(bool result)

    {

        if (result)

        {

            MessageBox.Show("작업 완료 되었습니다.");

            serivce.SelectProductAsync();

        }

        else

        {

            MessageBox.Show("작업 실패하였습니다.");

        }

    }

}

Description

ð  각 버튼의 이벤트를 구현하였으며, 추가, 수정, 삭제 시 리플래시하였습니다.

 

 

l  참고 사이트

-       MSDN Library (WCF)

http://msdn.microsoft.com/ko-kr/library/ms735119.aspx

 

1.     WCF 서비스 구현하기

-      이름을 넣고 WCF 서비스 항목을 선택하여 추가하면 App.config, ProductService.cs 그리고 인터페이스 IProductService.cs 파일이 자동 생성되어 있으며, 샘플 코드는 삭제합니다.

-       CRUD 기능 구현을 위해 인터페이스에 메서드 재정의를 선언합니다.

Code

IProductService.cs

[ServiceContract]
public interface IProductService
{
    [OperationContract]
    bool InsertProduct(Products product);

    [OperationContract]
    bool UpdateProduct(Products product);

    [OperationContract]
    bool DeleteProduct(string name);

    [OperationContract]
    List<Products> SelectProduct();
}

ð  인터페이스 IProductService.cs 상단 부분에 보면 [ServiceContract]이라는 속성이 명시되어 있습니다. WCF 응용 프로그램의 서비스 계약을 정의하는 것으로, 반드시 선언하여야 합니다.

ð  메서드 재정의 부분에 [OperationContract]이라는 속성이 명시되어 있으며, WCF 응용 프로그램의 서비스 계약의 일부인 작업을 정의합니다.

-       CRUD(Insert, Update, Delete, Select) 로직을 구현합니다.

Code

ProductService.cs

namespace WCFServiceLibrary

{

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

    public class ProductService : IProductService

    {

        NorthwindDBDataContext dc = new NorthwindDBDataContext();

 

        public bool InsertProduct(Products product)

        {

            try

            {

                dc.Products.InsertOnSubmit(product);

                dc.SubmitChanges();

 

                return true;

            }

            catch { return false; }

        }

 

        public bool UpdateProduct(Products product)

        {

            try

            {

                var target = (from tmp in dc.Products

                              where tmp.ProductID == product.ProductID

                              select tmp).Single();

               

                target.ProductID = product.ProductID;

                target.ProductName = product.ProductName;

                target.SupplierID = product.SupplierID;

                target.CategoryID = product.CategoryID;

                target.QuantityPerUnit = product.QuantityPerUnit;

                target.UnitPrice = product.UnitPrice;

                target.UnitsInStock = product.UnitsInStock;

                target.UnitsOnOrder = product.UnitsOnOrder;

                target.ReorderLevel = product.ReorderLevel;

                target.Discontinued = product.Discontinued;

                dc.SubmitChanges();

 

                return true;

            }

            catch { return false; }

        }

 

        public bool DeleteProduct(string name)

        {

            try

            {

                var target = (from tmp in dc.Products

                              where tmp.ProductName.Equals(name)

                              select tmp).ToList();

 

                dc.Products.DeleteOnSubmit(target[0]);

                dc.SubmitChanges();

 

                return true;

            }

            catch { return false; }

        }

 

        public List<Products> SelectProduct()

        {

            var target = (from tmp in dc.Products

                          select tmp).ToList();

 

            return target;

        }

    }

}

ð  클래스 상단 부분에 [ServiceBehavior]이라는 속성이 명시되어 있으며, 서비스 계약 구현의 내부 실행 동작을 지정합니다. InstanceContextMode는 들어오는 메시지에 포함된 호출을 처리할 수 있는 서비스 인스턴스 수를 지정합니다. WCF 서비스 구현에 중요한 요소이므로 자세히 알아보겠습니다.

모드

설명

Single

개체가 들어오는 모든 호출에 대해 사용되며 호출 후에는 재활용되지 않습니다. 서비스 개체가 없는 경우 새로 만들어집니다. (공유개념)

PerCall

매번 호출하기 전에 만들어지고 매번 호출한 후에 재활용됩니다. 채널에서 세션을 만들지 않으면 이 값은 PerCall인 것처럼 동작합니다. (비동기인 Silverlight에서는 의미없는 모드라고 볼 수 있습니다.)

PerSession

각 세션마다 개체가 만들어집니다. (클라이언트가 더 이상 필요로 하지 않을 때까지 인스턴스가 존재합니다.)

ð  LINQ에 대한 MSDN Library 링크

2.    빌드(F6), App.config 파일 수정 (해당 기능 꼭 알아두기)

-       해당 파일을 열어 수정하는 방법도 있지만, WCF 구성 편집 항목을 이용하여 편집해보겠습니다.

-      App.config 파일에 마우스 오른쪽 버튼을 클릭하면 WCF 구성 편집 항목을 선택합니다.

-       WCF 구성 편집 창이 나타나며, WCF 서비스 라이브러리에 정의된 것과 같은지 확인합니다. 틀릴 경우 해당 항목을 선택하면 <!--[if !vml]--><!--[endif]-->이 나타나는데 클릭합니다. 그리고, bin폴더/Debug폴더 안에 WCFServiceLibrary.dll을 선택한 후, 알맞은 형식 이름을 선택하시면 자동으로 변경됩니다.

-       위 파트에서 설명한 바가 있지만, Silverlight에서는 바인딩을 basicHttpBinding만 지원하므로 반드시 변경해주여야 합니다.

-       그리고 Contact 속성이 맞게 지정되어 있는지 확인합니다. 틀릴 경우 위에서 했던 방식으로 알맞은 형식 이름을 선택합니다.

3.     WCF 서비스 구성이 잘 되어 작동이 이상유무를 확인해 봅니다.

-       실행(F5)를 해보면, 아래와 같이 WCF 테스트 클라이언트 창이 나타나며, 트라이아이콘에 WCF 서비스 호스트 아이콘이 나타나며 구성에는 이상없음을 나타냅니다.

-       SelectProduct()을 더블클릭 한 후, 별다른 인자가 특별 없기 때문에 우측에 호출 버튼을 클릭합니다. Length에 아마 NorthWind 데이터베이스의 Products테이블의 아이템 개수와 동일하게 나나타나는 것을 볼 수 있습니다.

-       이번에는 InsertProduct()을 더블클릭 한 후, 각 변수의 임의의 값을 넣어주고 호출을 하면 성공시, 응답 화면에 return 값에 true가 나타나며, DB 테이블에 아이템 개수가 한 개 늘어난 것을 볼 수 있습니다.

ü  WCF 서비스 라이브러리를 사용하여 WCF Service 만들기

1.     구현 설명

-       Linq to Sql 클래스를 통해 DB 서비스 구현

-       CRUD(Select, Insert, Update, Delete) 기능 구현

-       Silverlight DataGrid 컨트롤 추가하여 데이터 바인딩 및 CRUD 이벤트 구현

2.     WCF 서비스 라이러브리 프로젝트 추가하기

-       웹사이트에 Silverlight 사용 WCF 서비스 항목을 선택하여 서비스 구현하여도 상관없지만, 확장성 및 유지 보수를 고려해 볼 때, WCF 서비스 라이브러리 프로젝트로 서비스 구현하는 것이 관리하기 좋습니다.

-       WCF 서비스 라이브러리 항목을 선택 한 후, 새 프로젝트를 추가합니다.

-       IService1.cs Service1.cs, App.config 세 개의 파일이 생성되어 있는 것을 볼 수 있으며, 모두 삭제 한 후 새로 구현해 보겠습니다.

3.     “Northwind and pubs Sample Databases for SQL Server 2000” 를 다운 받아 샘플 데이터베이스 환경을 만듭니다.

-       링크 페이지에서 SQL2000SampleDb.msi 파일을 다운 받아 설치 합니다. (링크)

-       기본적으로 C:\SQL Server 2000 Sample Databases 아래 데이터 베이스 파일이 저장됩니다.

-       Microsoft SQL Server Studio를 열어, Northwind DB를 연결 추가합니다.

-      연결할 데이터 베이스 추가할 항목을 선택한 후, 추가합니다.

 =>

4.    LINQ to SQL 클래스 추가한 후, DB 연결 하기

-      WCF 서비스 라이브러리 프로젝트에 LINQ to SQL 클래스를 선택하고, 이름 작성한 후, 추가버튼을 클릭합니다.

-      아래와 같은 화면이 나타나며 서버 탐색기를 열어(메뉴에서 보기à서버 탐색기 혹은 Ctrl + W, L) 샘플 데이터 베이스(Northwind) 스키마를 추가합니다.

-      서버 탐색기에서 데이터 연결에 마우스 오른쪽 버튼을 클릭하면 연결 추가가 나오며, Microsoft SQL Server를 선택한 후, 계속 버튼을 클릭합니다.

 =>

-       연결할 서버 이름 및 데이터베이스 이름을 선택하며, 연결 테스트 버튼을 클릭한 후, “테스트 연결에 성공하였습니다.” 라는 성공 메시지가 나타나면 확인을 누릅니다.

5.     Northwind 데이터베이스 스키마가 추가된 것을 볼 수 있으며, 테이블 및 저장 프로시저를 볼 수 있습니다.

-       SQL Server 2005 Management Studio 에서의 기본적인 기능은 제공한다고 합니다.

(데이블 데이터 조회, 쿼리 디자이너, 저장 프로시저 작성)

6.     작업을 진행할 테이블 및 저장 프로시저를 오른쪽 화면으로 드래그하면 아래 화면과 같이 추가됩니다. 여러 개의 테이블을 사용할 경우에는 여러 개를 드래그하여 스키마를 관리하면 됩니다.

7.    속성 창을 열어 DataContext 정의 할 때, Serialization Mode None에서 Unidirectional으로 변경해 줍니다. (객체를 직렬화)

ü  WCF Service의 개념

1.     닷넷의 여러 분산 기술들을 하나로 통합하여 SOA기반의 애플리케이션을 쉽게 개발해 줄 수 있게 지원해주는 기술이며, 기존의 복잡했던 각각의 개발 방식을 일관된 방식으로 프로그래밍할 수 있게 제공해줍니다.

2.     보안이나 트랜잭션과 같은 기능을 구현할 수 있는 높은 생산성을 제공해주고 있고, 기존의 닷넷 분산 기술과 웹 서비스 확장 스펙(WS-*)과의 높은 상호 운용성을 제공해 주고 있습니다. , 닷넷 웹 서비스를 포함하여 좀 더 포괄적인 분산 기술을 지원한 닷넷 기술이라고 보시면 됩니다.

     참고 사이트

MSDN - WCF(Windows Communication Foundation) 서비스 구축

ü  Silverlight에서 WCF Service를 사용하는 경우

1.     DB에 접근할 때

-       Silverlight에서는 .NET의 데이터 처리(DataSet)가 지원하지 않습니다. 웹 서비스 및 WCF 서비스를 통해 데이터를 가져와야 합니다.

2.    다른 플랫폼과 소통을 위한 경우

3.     기타 외부에서 필요한 인자를 읽어오려 할 때

ü  Silverlight를 위한 WCF Service 만들기

1.     WCF의 가장 기본이 되는 개념인 엔드포인트(EndPoint)의 개념

-       WCF서비스와 클라이언트가 엔드포인트를 통해 메시지를 주고 받게 됩니다..

-      엔드포인트는 주소(Address), 바인딩(Binding), 계약(Contact) 3가지 요소로 구성되어 있습니다. , 어디에서(Where) 무엇을(What) 어떻게(How) 통신할 것인지에 대한 개념입니다.

2.   웹사이트에 WCF Service 만들기 방법

-       새로 만들기에 웹사이트를 새로 만듭니다.

-       WCF 서비스를 선택하고, 폴더 경로를 선택하여 프로젝트를 생성합니다.

-       App_Code폴더에 IService.cs Service.cs 두개의 파일이 생성되어 있는 것을 볼 수 있으며, 파일에 작성되어 있는 샘플 코드를 지우고 아래와 같이 작성합니다.

Code

IService.cs

[ServiceContract]

public interface IService

{

    [OperationContract]

    DateTime GetNowDate();

}

 

Service.cs

public class Service : IService

{

    public DateTime GetNowDate()

    {

        return DateTime.Now;

    }

}

-       Web.config을 열어보시면, EndPoint binding 속성을 basicHttpBinding으로 변경합니다.

Code

<!-- 중략 -->

<system.serviceModel>

    <services>

      <service name="Service" behaviorConfiguration="ServiceBehavior">

        <!-- Service Endpoints -->

        <endpoint address="" binding="basicHttpBinding" contract="IService">

          <!--

              배포 시 다음 identity 요소는 배포된 서비스를 실행할 때 사용하는 ID를 반영하도록

              제거되거나 대체되어야 합니다. 해당 요소가 제거되면 WCF에서는 적합한 ID

              자동으로 유추합니다.

          -->

          <identity>

            <dns value="localhost"/>

          </identity>

        </endpoint>

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

      </service>

    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior name="ServiceBehavior">

          <!-- 메타데이터 정보를 공개하지 않으려면 배포하기 전에 아래의 값을 false로 설정하고 위의 메타데이터 끝점을 제거하십시오. -->

          <serviceMetadata httpGetEnabled="true"/>

          <!-- 디버깅 목적으로 오류에서 예외 정보를 받으려면 아래의 값을 true로 설정하십시오. 예외 정보를 공개하지 않으려면 배포하기 전에 false로 설정하십시오. -->

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

</configuration>

Description

ð  Silverlight Web에 종속된 기술이기 떄문에 기본적인 바인딩인 basicHttpBinding만 지원합니다.

-      컴파일 후, Service.svc 파일을 브라우저에서 보기 하면 다음과 같은 화면이 나타나며, 제대로 작동하고 있다는 것을 알 수 있습니다. 이 서비스는 WCF 서비스이자 웹 서비스라 할 수 있습니다.

3.     Silverlight 에서 WCF Service 참조하기

-       Silverlight 응용 프로그램을 선택한 후, 새 프로젝트를 추가합니다.

-       WCF 서비스 프로젝트에서 결과를 확인할 수 있게 기존 웹 사이트에 연결합니다.

-       Silverlight 응용 프로젝트가 생성이 되면, 프로젝트 참조 부분에 오른쪽 마우스를 눌러 서비스 참조를 선택합니다. (이하, ASP.NET에 웹 서비스 참조 하는 방식과 유사합니다.)

-       좀전에 Service.svc URL를 주소에 넣고, 이동을 누르면 해당 서비스 목록이 나타나며, 서비스 네임스페이스명을 지정합니다.

-       서비스 참조된 것을 볼 수 있으며, 서비스 설정 파일(ServcieReferences.ClientConfig)이 생성된 것을 볼 수 있으며, ServcieReferences.ClientConfig 파일을 열어보면 WCF 서비스 설정이 생성된 것을 볼 수 있습니다.

Code

ServcieReferences.ClientConfig

<configuration>

    <system.serviceModel>

        <bindings>

            <basicHttpBinding>

                <binding name="BasicHttpBinding_IService" maxBufferSize="2147483647"

                    maxReceivedMessageSize="2147483647">

                    <security mode="None" />

                </binding>

            </basicHttpBinding>

        </bindings>

        <client>

            <endpoint address="http://localhost:8553/WCFService1/Service.svc"

                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService"

                contract="WCFService.IService" name="BasicHttpBinding_IService" />

        </client>

    </system.serviceModel>

</configuration>

ð  basicHttpBinding전송수준에서의 보안이나 메시지자체의 보안기능은 제공하지만, 트랙젼선이나 세션과 같은 기능은 제공하지 않습니다.

4.    WCF Service 호출하여 Silverlight에 데이터 결과를 보여주기

-       Page.xaml 파일에 데이터를 받기 위한 텍스트블록 컨트롤을 추가하고, 페이지 로드시, 서비스 호출하여 화면에 보여줍니다.

Code

Page.xaml

<TextBlock x:Name="txtDateNow"></TextBlock>

 

Page.xaml.cs

public partial class Page : UserControl

{

    public Page()

    {

        InitializeComponent();

 

        this.Loaded += new RoutedEventHandler(Page_Loaded);

    }

 

    void Page_Loaded(object sender, RoutedEventArgs e)

    {

        //WCF 서비스 객체 생성

        WCFService.ServiceClient service = new WCFBinding.WCFService.ServiceClient();

        //GetDateNow 메서드 결과를 리턴받는 이벤트

        service.GetDateNowCompleted += new EventHandler<WCFBinding.WCFService.GetDateNowCompletedEventArgs>(service_GetDateNowCompleted);

        //비동기 호출

        service.GetDateNowAsync();

    }      

 

    //서비스로부터 호출결과를 반환받을 경우

    void service_GetDateNowCompleted(object sender, WCFBinding.WCFService.GetDateNowCompletedEventArgs e)

    {

        txtDateNow.Text = e.Result.ToShortDateString();

    }

}

Result

-       Microsoft Silverlight

http://silverlight.net/

-       실버라이트 정보 공유 카페

http://cafe.naver.com/mssilverlight.cafe

-       ScottGu's Blog

http://weblogs.asp.net/scottgu/pages/silverlight-posts.aspx

-       MSDN Library (Silverlight)

http://msdn.microsoft.com/ko-kr/library/cc838158(VS.95).aspx

ü  Silverlight 배포하는 방법

1.     Object 태그를 이용한 방법

-       Naver에서 보면 퍼가기와 같은 기능 구현이 가능하며, 특정 웹 서버의 제약 없이 구동 할 수 있어 Silverlight 배포 추천 방법이라 할 수 있습니다.

2.     Silverlight.js의 함수를 이용한 방법

3.     ASP.NET Silverlight 컨트롤을 이용한 방법

-       3번과 배포 방법은 웹사이트가 닷넷 환경이어야 한다는 제약이 있습니다.

ü  Object 태그를 이용한 방법 (알아두면 좋은 것)

1.     Object 태그의 필수적인 속성

속성

내용

Id

HTML 안에 포함될 실버라이트 플러그인의 이름

Data

실버라이트를 어떻게 로드할지에 대한 MIME 타입

Type

실버라이트의 버전

Height

실버라이트를 나타낼 높이(픽셀, %, 둘 다 지정가능)

Width

실버라이트를 나타낼 넓이(픽셀, %, 둘 다 지정가능)

2.     속성과 이벤트의 주요 파라미터

파라미터

내용

Source

URI형식으로 나타낸 실버라이트 파일의 주소이고, 기본 값은 null입니다.

onError

실버라이트에서 에러가 발생할 경우 그 에러 내용을 Javascript로 전달하여 보여줍니다.

onResize

실버라이트의 ActalHeight, ActualWidth 속성이 변경될 때 발생하는 이벤트이며, 처음 로드할 때도 발생하지만 Full-Screen 모드로 변경될 때는 발생하지 않습니다.

3.     선택적인 파라미터

파라미터

내용

background

실버라이트가 로드될 때의 배경색으로 기본값은 null입니다.

enableHtmlAccess

HTML DOM에서 실버라이트 개체로의 접근이나 실버라이트에서 HTML 컨텐트로의 접근을 허용할지에 대한 여부로 기본값은 false입니다.

initParams

실버라이트 런타임으로 전달할 초기 설정 문자열로 콤마(,)을 이용해서 여러 개의 문자열을 구분하여 전달 할 수 있습니다.(key1=value1,key2=value2,key3=value3)

maxFrmaerate

1초간 보여줄 프레임 수의 최대치로 기본값은 60입니다. 이 값은 높을수록 사용자 브라우저의 성능을 늦출 수 있고, 또한 낮을수록 애니메이션이 상당히 부자연스러울 수 있습니다.

splashScreenSource

Source 파라미터에서 지정한 파일이 다운로드 되는 동안의 로딩을 보여줄지에 대한 여부입니다.

windowless

HTML과 혼합되어 사용할 수 있는 Windowless 모드를 설정할 지에 대한 여부로 기본 값은 fasle입니다. 이 속성은 MS 원도우에서 동작되는 브라우저에만 작동됩니다.

*음영 처리된 부분은 기억해 두시는 겟 좋습니다.

4.     추가적인 이벤트 파라미터

파라미터

내용

onLoad

실버라이트가 에러없이 로드되고 모든 내용이 표시될 때 발생하는 이벤트입니다.

onSourceDownloadComplete

Source 파라미터에서 지정한 파일의 다운로드가 완료될 때 발생하는 이벤트입니다.

onSourceDownloadProgressChanged

Source 파라미터에서 지정한 파일의 다운로드가 진행될 떄 발생하는 이벤트입니다.

5.     애니메이션의 진단을 위한 추가 파라미터

-       설정한 속성 외에도 프레임 속도를 브라우저에 보여주거나 렌더링되는 위치를 진단해 보고 싶을 경우 사용합니다. 이 부분에 대해서는 자세히 정리 하지 않겠지만 도움이 될 만한 사이트 주소를 걸어두도록 하겠습니다. (링크)

 

 

ü  Sample Code

1.     initParams을 이용한 데이터 전달하기

-       Silverlight 응용 프로그램 빌드 시, 생성되는 TestPage.html object태그에 파라미터 추가합니다.

Code

TestPage.html

<object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">

             <param name="source" value="DemoSample4.xap"/>

             <param name="onerror" value="onSilverlightError" />

             <param name="background" value="white" />

             <param name="minRuntimeVersion" value="2.0.31005.0" />

             <param name="autoUpgrade" value="true" />

             <param name="initParams" value="message1=demo1,message2=demo2" />

             <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                           <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Microsoft Silverlight 가져오기" style="border-style: none"/>

             </a>

</object>

-       App.xaml.cs에서 Application_Startup 이벤트에서 해당 값을 가져와서 Page.xaml에서 값 전달 받아, 메시지창 띄우기

Code

App.xaml.cs

private void Application_Startup(object sender, StartupEventArgs e)

{

    string strMessage = e.InitParams["message1"] + e.InitParams["message2"];

    this.RootVisual = new Page(strMessage);

}

Page.xaml.cs

public Page(string strMessage)

{

    InitializeComponent();

 

    MessageBox.Show(strMessage);

}

2.     Silverlight에서 HTML 개체에 접근하기

-       Silverlight 역시 DOM 방식을 이용하여 HTML 엘리먼트에 접근할 수 있습니다.

-       TestPage.html Silverlight div 영역 상단에 우선 HTML 개체인 input 엘리먼트를 추가합니다.

Code

TestPage.html

<input type="text" id="txtDemo" value="demo" />

<div id="silverlightControlHost">

             <object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">

                           <param name="source" value="DemoSample4.xap"/>

                           <param name="onerror" value="onSilverlightError" />

                           <param name="background" value="white" />

                           <param name="minRuntimeVersion" value="2.0.31005.0" />

                           <param name="autoUpgrade" value="true" />

                           <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                                        <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Microsoft Silverlight 가져오기" style="border-style: none"/>

                           </a>

             </object>

             <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>

</div>

-       Page.xaml에서 텍스트 박스와 버튼 컨트롤 추가하고, 버튼 클릭 이벤트에 텍스트 박스의 값을 HTML개체인 input value에 넣은 로직을 구현해보겠습니다.

Code

Page.xaml

<UserControl x:Class="DemoSample4.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White" Orientation="Horizontal">

        <TextBox x:Name="TextBox1"  Width="150" Height="20"></TextBox>

        <Button x:Name="Button1" Width="100" Height="20" Content="클릭" Click="Button1_Click"></Button>

    </StackPanel>

</UserControl>

Page.xaml.cs

//추가 네임스페이스

using System.Windows.Browser;

 

private void Button1_Click(object sender, RoutedEventArgs e)

{

    //현재 HTML 페이지의 Document 가져오기

    HtmlDocument document = HtmlPage.Document;

 

    //GetElementById input 개체 접근

    HtmlElement element = document.GetElementById("txtDemo");

 

    //GetAttribute value 값 가져오기

    //element.GetAttribute("value");

 

    //SetAttribute value 값 설정하기

    element.SetAttribute("value", TextBox1.Text);

}

Result

  =>

ð  상단 영역은 HTML 개체이고, 아래는 Silverlight 영역입니다.

ð  Silverlight 영역의 텍스트박스에 텍스트 입력 후, 클릭 하시면, HTML 개체의 값이 변경되는 것을 볼 수 있습니다.

3.     HTML 엘리먼트의 이벤트 구독하기

-       테스트 페이지에 2번과 같이 Silverlight 영역 상단에 텍스트박스와 버튼 개체를 추가합니다.

Code

TestPage.html

<input type="text" id="txtDemo" value="demo" />

<input type="button" id="btnDemo" value="메시지 보이기" />

-       Page.xaml.cs에서 Page() 생성자에 HTML 개체 이벤트를 로직을 추가합니다.

Code

Page.xaml.cs

public Page()

{

    InitializeComponent();

 

    //이벤트 구독

    HtmlElement btnElement = HtmlPage.Document.GetElementById("btnDemo");

    btnElement.AttachEvent("onclick", new EventHandler<HtmlEventArgs>(this.OnBtnDemoClicked));

}

 

private void OnBtnDemoClicked(object sender, EventArgs e)

{

    HtmlElement txtElement = HtmlPage.Document.GetElementById("txtDemo");

    MessageBox.Show(txtElement.GetAttribute("value"));

}

Result

4.     Silverlight Javascript의 연동

-       Silverlight에서 Scriptable 어트리뷰트를 제공해 주며, 어트리뷰트를 선언함으로써 자바스크립트로의 접근을 허용할 수 있습니다.

-       Silverlight 응용 프로젝트 생성 후, TestPage.html 파일에 input 엘리먼트를 추가하고, Silverlight Object 태그에 id가 지정되어 있지 않는다면, id를 지정합니다.

Code

<body>

    메시지 입력 : <input type="text" id="txtMessage" /><br />

    <input type="button" id="btnReg" onclick="RegMessage()" value="등록" />

 

    <div id="silverlightControlHost">

                           <object id="silverlightObject" data="data:application/x-silverlight-2,"  type="application/x-silverlight-2" width="100%" height="100%">

                                        <param name="source" value="ClientBin/DemoSample4.xap"/>

                                        <param name="onerror" value="onSilverlightError" />

                                        <param name="background" value="white" />

                                        <param name="minRuntimeVersion" value="2.0.31005.0" />

                                        <param name="autoUpgrade" value="true" />

                                        <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                                       <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Microsoft Silverlight 가져오기" style="border-style: none"/>

                                        </a>

                           </object>

                           <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>

    </div>

</body>

-       Page.xaml에서 받은 텍스트를 보여줄 TextBlock를 선언하고, Page.xaml.cs에서 HTML의 자바스크립트에서 접근할 수 있는 속성과 메서드를 만들겠습니다.

Code

Page.xaml

<UserControl x:Class="DemoSample4.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBlock x:Name="txtMessage" Text="메시지 : " ></TextBlock>

    </Grid>

</UserControl>

 

Page.xaml.cs

[ScriptableType]

public partial class Page : UserControl

{

    public string message;

 

    public Page()

    {

        InitializeComponent();

        HtmlPage.RegisterScriptableObject("MessageInfo", this);

    }

 

    [ScriptableMember()]

    public void AlertMessage()

    {

        txtMessage.Text = "메시지 : " + this.Message;

 

        //자바스크립트 함수 호출하기

        //MessageBox.Show("등록되었습니다."); 와 동일함.

        HtmlElement alertScript = HtmlPage.Document.CreateElement("script");

        alertScript.SetAttribute("text", "alert('등록되었습니다.');");

        HtmlPage.Document.DocumentElement.AppendChild(alertScript);

    }

  

    [ScriptableMember()]

    public string Message

    {

        get { return message; }

        set { message = value; }

    }

}

Description

ð  클래스 속성에 [ScriptableType]를 선언하면, HtmlPage.RegisterScriptableOjbect() 메소드를 통해 모든 공용 속성, 메서드 및 이벤트를 JavaScript 코드에서 사용할 수 있으며, Javascript에서의 접근을 위해 반드시 선언하여야 합니다.

ð  각각의 속성에 선언한 [ScriptableMember()] 어트리뷰트는 HTML스크립트에서 해당 코드에 접근할 수 있도록 허용하기 위해 선언해 주어야 합니다.

-       TestPage.html 에서 RegMessage() 스크립트를 작성합니다.

Code

<script type="text/javascript">

    function RegMessage() {

 

        //실버라이트 객체

        var host = document.getElementById("silverlightObject");

 

        //사용자 정보 등록

        host.content.MessageInfo.Message = document.getElementById("txtMessage").value;

 

        //사용자 메서드 호출

        host.content.MessageInfo.AlertMessage();

    }

</script>

ð  HtmlPage.RegisterScriptableOjbect()에서 선언하였던 Script Key를 통해 JavaScript 코드에서 접근이 가능합니다.

Result

=>

ü  Understand ControlTemplate

1.     템플릿을 활용하면 컨트롤의 전체 모양을 바꿀 수 있을 뿐만 아니라, 컨트롤의 컨텐트 영역만도 바꿀 수 있으며, 컨트롤이 가지고 있는 애니메이션 역시도 바꿀 수 있습니다

2.     대부분의 컨트롤들은 컨트롤 클래스를 상속하고 있는데, 템플릿은 이 컨트롤 클래스의 Template 속성을 사용하게 됩니다. 리소스 형태 또는 컨트롤에 속성 엘리먼트로 Template 속성 값을 설정하게 됩니다.

3.     템플릿 속성 지정 방법

-       컨트롤 속성 엘리먼트로 지정하는 방법

Code

<Grid x:Name="LayoutRoot" Background="White">

    <Button x:Name="Button1" Width="100" Height="50" Content="버튼1" >

        <Button.Template>

            <ControlTemplate>

                <Grid>

                    <!-- 중략 -->

                </Grid>

            </ControlTemplate>

        </Button.Template>

    </Button>

</Grid>

ð  가장 쉽고 명백하지만, 다른 컨트롤과 공유되지 않기 때문에 매우 제한된 경우에 주로 사용합니다.

-       컨트롤 템플릿 리소스로 값 설정하는 방법

Code

<Grid x:Name="LayoutRoot" Background="White">

    <Grid.Resources>

        <ControlTemplate x:Key="buttonTemplate">

            <Grid>

                <!-- 중략 -->

            </Grid>

        </ControlTemplate>

    </Grid.Resources>

    <Button x:Name="Button1" Width="100" Height="50" Content="버튼1" Template="{StaticResource buttonTemplate}" ></Button>

</Grid>

ð  템플릿을 리소스에서 정의하며, x:Key 속성을 설정하여 각 컨트롤들이 바인딩을 통해 값을 설정하게 됩니다.

-       스타일 리소스로 값 설정하는 방법(스타일의 Setter를 통해 템플릿 속성값을 변경)

Code

<Grid x:Name="LayoutRoot" Background="White">

    <Grid.Resources>

        <Style x:Key="buttonStyle" TargetType="Button">

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="Button">

                        <Grid>

                            <!-- 중략 -->

                        </Grid>

                    </ControlTemplate>

                </Setter.Value>

            </Setter>

        </Style>

    </Grid.Resources>

    <Button x:Name="Button1" Width="100" Height="50" Content="버튼1" Style="{StaticResource buttonStyle}" ></Button>

</Grid>

ð  가장 많이 쓰이는 방식으로, Setter를 통해 설정된 속성값에 템플릿을 정의하는데 바인딩 표현식을 사용할 수 있어, 유연하게 활용할 수 있습니다.

 

ü  Sample Code

1.     버튼 컨트롤 모양 바꾸기

-       템플릿에 그라디언트가 적용된 타원 버튼을 만들어보겠습니다.

Code

<UserControl x:Class="DemoSample4.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Grid.Resources>

            <Style x:Key="buttonStyle" TargetType="Button">

                <Setter Property="Template">

                    <Setter.Value>

                        <ControlTemplate>

                            <Grid>

                                <Ellipse>

                                    <Ellipse.Fill>

                                        <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5, 0">

                                            <GradientStop Color="#FF000000" Offset="1" />

                                            <GradientStop Color="#FFFFFFFF" Offset="0" />

                                        </LinearGradientBrush>

                                    </Ellipse.Fill>

                                </Ellipse>

                            </Grid>

                        </ControlTemplate>

                    </Setter.Value>

                </Setter>

            </Style>

        </Grid.Resources>

       

        <Button Width="100" Height="50" Content="버튼1" Style="{StaticResource buttonStyle}"></Button>

    </Grid>

</UserControl>

 

Result


Description

ð  버튼 컨트롤 모양을 바꾸는데는 성공하였지만, “버튼1”이라는 컨트롤의 텍스트 즉, 컨텐트 내용이 표시되지 않았습니다.

-       ContentPresenter을 통한 컨트롤의 컨텐트 영역을 표시합니다.

Code

<!-- 생략 -->

<Grid.Resources>

    <Style x:Key="buttonStyle" TargetType="Button">

        <Setter Property="Template">

            <Setter.Value>

                <ControlTemplate>

                    <Grid>

                        <Ellipse>

                            <Ellipse.Fill>

                                <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5, 0">

                                    <GradientStop Color="#FF000000" Offset="1" />

                                    <GradientStop Color="#FFFFFFFF" Offset="0" />

                                </LinearGradientBrush>

                            </Ellipse.Fill>

                        </Ellipse>

                        <ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/>

                    </Grid>

                </ControlTemplate>

            </Setter.Value>

        </Setter>

    </Style>

</Grid.Resources> <!-- 생략 -->

Result

Description

ð  ContentPresenter의 컨텐트 속성을 이 템플릿이 설정된 컨트롤의 컨텐트 속성과 바인딩을 통해서 동일한 값을 설정할 수 있도록 선언하고 있습니다. (TemplateBinding 사용)

 

ü  Sample Code

1.     ListBox 컨트롤의 SelectionChanged 이벤트를 이용한 DetailView Dialog를 구현

-       DetailView를 위해 DetailView명으로 UserControl(Silverlight 사용자 정의 컨트롤)을 추가합니다.

-       UI 화면 만들고, 닫기 버튼 이벤트를 작성합니다.

Code

DetailView.xaml

<UserControl x:Class="DemoSample3.DetailView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="OrangeRed"></Rectangle>           

       

        <Button x:Name="btnClose" Content="닫기" Width="100" Height="50" Click="btnClose_Click"></Button>

    </Grid>

</UserControl>

 

DetailView.xaml.cs

// 닫기 버튼 이벤트를 추가

private void btnClose_Click(object sender, RoutedEventArgs e)

{

    Visibility = Visibility.Collapsed;

}

-       초기 페이지 Page.xaml ListBox 컨트롤 Item 선택 이벤트를 작성합니다.

Code

Page.xaml

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="DemoSample3.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:detailview="clr-namespace:DemoSample3"

    >

    <Grid x:Name="LayoutRoot" Background="DarkOrange" >

        <!-- 중략 -->

        ………

        <ListBox x:Name="lbResult" Grid.Row="1"  SelectionChanged="lbResult_SelectionChanged">

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <!-- 중략 -->

………

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

       

        <!-- Modal Detail View UserControl 추가 -->

        <detailview:DetailView x:Name="DetailView" Grid.Row="1" Visibility="Collapsed"></detailview:DetailView>

    </Grid>

</UserControl>

Page.xaml.cs

private void lbResult_SelectionChanged(object sender, SelectionChangedEventArgs e)

{

    DetailView.Visibility = Visibility.Visible;

}

Description

ð  Silverlight 초기 페이지 Page.xaml 상단에 DetailView UserControl을 추가하기 위해 태그를 추가합니다. (ASP.NET 에서 UserControl 추가하는 것과 유사합니다.)

ð  DetailView 컨트롤 추가 한 후, Visiblity 속성을 Collapsed를 지정하여, 기본적으로 화면에 보이지 않게 하고, ListBox 컨트롤의 Item 선택 이벤트에 DetailView 컨트롤 Visible 처리 합니다.

Result
     

     

2.     DataContext 를 이용하여 DetailView 상세 화면 구현하기

-       DetailView에 상세 데이터를 표현하기 위해 UI를 변경하였습니다.

(데이터 표현하기 위한 TextBlock 추가)

Code

DetailView.xaml

<UserControl x:Class="DemoSample3.DetailView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="OrangeRed"></Rectangle>

 

        <StackPanel Orientation="Vertical">

            <StackPanel  Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">책 이름 :</TextBlock>

                <TextBlock x:Name="txtBookName"  Margin="5" Text="{Binding BookName}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">책 소개 :</TextBlock>

                <TextBlock x:Name="txtBookDesc" Margin="5" Text="{Binding Description}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">작성자 :</TextBlock>

                <TextBlock x:Name="txtBookAuthor" Margin="5" Text="{Binding Author}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">책 가격 :</TextBlock>

                <TextBlock x:Name="txtBookPrice" Margin="5" Text="{Binding Price}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">발행사 :</TextBlock>

                <TextBlock x:Name="txtBookPublisher" Margin="5" Text="{Binding Publisher}"></TextBlock>

            </StackPanel>

            <StackPanel Margin="7" Orientation="Horizontal">

                <TextBlock Margin="5">발행일 :</TextBlock>

                <TextBlock x:Name="txtBookPubDate" Margin="5" Text="{Binding PubDate}"></TextBlock>

            </StackPanel>

            <Button x:Name="btnClose" Content="닫기" Width="100" Height="50" Click="btnClose_Click"></Button>

        </StackPanel>

       

    </Grid>

</UserControl>

-       ListBox 컨트롤의 Item 선택시 DetailView 컨트롤에 DataContext를 이용하여 데이터 전송

Code

Page.xaml

private void lbResult_SelectionChanged(object sender, SelectionChangedEventArgs e)

{

    Book book = (Book)lbResult.SelectedItem;

 

    DetailView.DataContext = book;

    DetailView.Visibility = Visibility.Visible;

}

Result


Description

ð  DetailView UserControl과 같이 FrameworkElement가 데이터 바인딩에 참여하는 경우, 해당 DataContext를 가져오거나 설정할 수 있으며, DataContext는 특정 컨텍스트가 다른 컨텍스트에 바인딩될 수 있는 시나리오의 작업을 원활하게 수행할 수 있도록 바인딩 가능한 속성입니다.

 

u  Understand DataBinding

1.    데이터 바인딩의 개념

-      우선, UI 엘레먼트와 데이터 개체와의 연결을 만드는 과정이라고 보시면 됩니다.

-      바인딩 원본 개체의 특정 속성이 바인딩대상 엘리먼트의 의존 속성과 다르거나 원본 개체 속성의 값이 가공해야 할 경우 변환기(ValueConverter)를 통해 변경해야 합니다.

-      데이터 바인딩 기본 개념도

    데이터 바인딩의 장점  

-      모든 개체들의 속성(Property)이 바인딩을 지원합니다.

-      데이터 템플릿과 스타일을 통해 데이터표현이 자유롭고 유연합니다.

-      UI로 부터 비즈니스 로직을 완벽히 분리할 수 있습니다.

2.    데이터 흐름

-      BindingMode열거형

속성

설명

OneWay

바인딩이 만들어지거나 바인딩 원본 개체 속성이 변경되었을 때 바인딩 대상 개체의 속성 값을 변경합니다.

OneTime

바인딩이 만들어질 때만 바인딩 대상 개체의 속성 값을 변경합니다.

TwoWay

바인딩 원본과 대상 개체의 속성 중 하나가 변경되면 나머지 하나의 속성 값을 변경합니다.

-      OneWay, TwoWay와 같이 바인딩 원본 개체의 속성값이 변경되었을 때 대상 개체의 속성값을 변경하기 위해서는 INotifyPropertyChanged 인터페이스를 구현해야만 합니다.

3.    데이터 바인딩 표현식

<object Property=”{Binding}” …/>

<object Property=”{Binding propertyPath}” …/>

<object Property=”{Binding oneOrMoreBindingProperties}” …/>

<object Property=”{Binding propertyPath , oneOrMoreBindingProperties }” …/>

 

u  Sample Code

1.    마우스 왼쪽 버튼 클릭 이벤트로 TextBlock 색깔 바꾸기

-      텍스트 블록에 Foreground 데이터 바인딩하기

Code

Page.xaml

<UserControl x:Class="DemoSample2.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White" >

        <TextBlock x:Name="TextBlock1" Margin="10" Foreground="{Binding ChangingColor}">DataBinding Sample Code</TextBlock>

    </Grid>

</UserControl>

 

Page.xaml.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace DemoSample2

{

    public partial class Page : UserControl

    {

 MyColors myColor = new MyColors();

 

        public Page()

        {

            InitializeComponent();

 

            myColor.ChangingColor = new SolidColorBrush(Colors.Red);

            this.TextBlock1.DataContext = myColor;

        }

    }

 

    public class MyColors

    {

        private SolidColorBrush changingColor;

 

        public SolidColorBrush ChangingColor

        {

            get { return changingColor; }

            set { changingColor = value; }

        }

    }

}

Description

ð  Page.xaml 텍스트 블록의 Foreground 속성에 바인딩합니다.

ð  데이터 바인딩을 위한 원본 개체를 만들기 위해 MyColors 클래스를선언하였습니다.

ð  Page()에서 Object 개체에 데이터 바인딩을 지정하였습니다.

Result

 

-      마우스 왼쪽 버튼 클릭 이벤트 추가

Code

Page.xaml

<TextBlock x:Name="TextBlock1" Margin="10" Foreground="{Binding ChangingColor}" MouseLeftButtonDown="TextBlock1_MouseLeftButtonDown">DataBinding Sample Code</TextBlock>

 

Page.xaml.cs

private void TextBlock1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

{

    myColor.ChangingColor = new SolidColorBrush(Colors.Black);

}

Description

ð  마우스 왼쪽 버튼 클릭 이벤트를 추가하였습니다. 빌드 후, 결과 화면을 보시면, 상단 이미지와 동일하게 텍스트 블록 색깔 변화가없는 것을 볼 수 있습니다.

ð  속성 값 변경을 감지해서 대상 속성의 값을 변경하기 위해서는INotifyPropertyChanged 인터페이스를 반드시 구현해 주어야 합니다.

-      INotifyPropertyChanged인터페이스 구현

Code

public class MyColors : INotifyPropertyChanged

{

    public event PropertyChangedEventHandler PropertyChanged;

 

    private SolidColorBrush changingColor;

    public SolidColorBrush ChangingColor

    {

        get { return changingColor; }

        set

        {

            changingColor = value;

            NotifyPropertyChaged("ChangingColor");

        }

    }

 

    private void NotifyPropertyChaged(string propertyName)

    {

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

    }

}

2.    ListBox컨트롤에 DataBinding 하기

-      Part3.“Naver OpenAPI 를 이용한 Book검색코드에서 DataGrid 컨트롤를 삭제하고, ListBox 컨트롤로 변경한 후, 데이터 보여주기

Code

Page.xaml

// DataGrid 컨트롤 삭제하고, ListBox 컨트롤 로 대체함.

<ListBox x:Name="lbResult" Grid.Row="1"></ListBox>

 

Page.xaml.cs

void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

{

    if (e.Error == null)

    {

        //Using LINQ to XML to Parse NaverOpenAPI XML Items into Book Class

        XDocument xmlBooks = XDocument.Parse(e.Result);

 

        var books = from book in xmlBooks.Descendants("item")

                    select new Book

                    {

                        BookName = (string)book.Element("title"),

                        LinkUrl = new Uri((string)book.Element("link")),

                        ImageUrl = new Uri((string)book.Element("image")),

                        Author = (string)book.Element("author"),

                        Price = (int)book.Element("price"),

                        Publisher = (string)book.Element("publisher"),

                        PubDate = (string)book.Element("pubdate"),

                        ISBN = (string)book.Element("isbn"),

                        Description = (string)book.Element("description")

                    };

 

        // XML Parse 한 데이터 바인딩하기

        lbResult.ItemsSource = books;

    }

}

Result

Description

ð  검색 버튼 클릭 시, ListBox 에 해당 데이터 영역에바인딩된 컬렉션명이 나타나는데, ListBox 컨트롤 부분에 <ListBox x:Name="lbResult" DisplayMemberPath="BookName" Grid.Row="1"></ListBox> 어떤 데이터를보여줄지 매핑을 하지 않았기 때문입니다. 위와 같이 DisplayMemberPath를 지정해 주시면,아래와 같이 원하는 데이터를 화면에 보여줍니다.


-      ListBox.ItemTemplate를 이용한 DataTemplate 구현하기

Code

Page.xaml

<ListBox x:Name="lbResult" Grid.Row="1">

    <ListBox.ItemTemplate>

        <DataTemplate>

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 이름 : </TextBlock>

                    <TextBlock x:Name="txtBookName"  Margin="5" Text="{Binding BookName}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 소개 :</TextBlock>

                    <TextBlock x:Name="txtBookDesc" Margin="5" Text="{Binding Description}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 발행일 :</TextBlock>

                    <TextBlock x:Name="txtBookPubDate" Margin="5" Text="{Binding PubDate}"></TextBlock>

                </StackPanel>

            </StackPanel>

        </DataTemplate>

    </ListBox.ItemTemplate>

</ListBox>

Result


Description

ð  ListBox 1개 이상의 정보를 보여줄 경우, ListBox 컨트롤의 ItemTemplate안에 DateTemplate를 정의하여 표현하고자하는 UI를 표현할 수 있습니다.

ð  DataTemplate 안에는 한 개의 컨트롤만 사용 가능하나, 여러 개의 컨트롤을 사용할 경우, StackPanel를 감싸줘서 사용할 수 있습니다.

3.     Tooltips (중요)

-      Part3“Silverlight Network 이해하기 에서 Silverlight Application보안을 위한 URL 접근이 제약되어 있고, 보안 정책 파일을 통해 특정 클라이언트의 접근을허용할 수 있다고 설명 드렸습니다. 우선 샘플 코드를 통해 자세한 설명을 이어가겠습니다.

-      ListBox컨트롤의 ItemTempalte 에검색한 책 이미지를 넣어보겠습니다.

Code

Page.xaml

<ListBox x:Name="lbResult" Grid.Row="1" >

    <ListBox.ItemTemplate>

        <DataTemplate>

            <StackPanel Orientation="Vertical">

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 이미지 :</TextBlock>

                    <Image Source="{Binding ImageUrl}" Width="16" Height="10"></Image>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 이름 :</TextBlock>

                    <TextBlock x:Name="txtBookName"  Margin="5" Text="{Binding BookName}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 소개 :</TextBlock>

                    <TextBlock x:Name="txtBookDesc" Margin="5" Text="{Binding Description}"></TextBlock>

                </StackPanel>

                <StackPanel Orientation="Horizontal">

                    <TextBlock Margin="5">책 발행일 :</TextBlock>

                    <TextBlock x:Name="txtBookPubDate" Margin="5" Text="{Binding PubDate}"></TextBlock>

                </StackPanel>

            </StackPanel>

        </DataTemplate>

    </ListBox.ItemTemplate>

</ListBox>

Result


Description

ð  결과 화면처럼 에러 코드 : 4001 , 범주 : ImageError , 메시지 : AG_E_NETWORK_ERROR 가 발생하는 것을 볼 수 있습니다. 좀 더 자세히 알아보기 위해 HttpWatch, Fildder IE 개발 툴을 사용하여 요청한기록(아래 이미지)을 보면 요청한 도메인 최상위 루트에 clientaccesspolicy.xml 파일과 crossdomain.xml를먼저 요청하는 것을 볼 수 있습니다. 크로스 도메인 접근시 자동으로 요청하는 2개의 파일입니다.

ð  Clientaccesspolicy.xml 파일은 Silverlight에서 사용하는 보안 정책 파일이고, Crossdomain.xml 파일은 기존에 어드비 플래시에서 사용하는 정책 파일로, 어떤 파일과 어떤 디렉토리를 접근 허용할지를 설정해 놓은 규약서라고 보시면 됩니다.

-      보안 정책 파일 작성하고 배포하기

ð  이 사이트의 모든 경로나 파일의 접근이 가능하도록 작성하였습니다.

Code

Clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8"?>

<access-policy>

  <cross-domain-access>

    <policy>

      <allow-from http-request-headers="*">

        <domain uri="*"/>

      </allow-from>

      <grant-to>

        <resource path="/" include-subpaths="true"/>

      </grant-to>

    </policy>

  </cross-domain-access>

</access-policy>

추가 설명 (예시)

<resource path="/demo" include-subpaths="false"/> 로 지정시,

허용되는 접근

demo#intro

/demo?bar=true#intro

허용되지 않는 접근

/demo

/demo.txt

/demo/sample

/demo/sample.txt

/demo/sample?bar=true

/sample

 

<resource path="/demo" include-subpaths="true"/> 로 지정시,

허용되는 접근

/demo/sample

/demo/sample.txt

/demo/sample?bar=true

/demo#intro

허용되지 않는 접근

/sample

Crossdomain.xml

<?xml version="1.0"?>

 

<!DOCTYPE cross-domain-policy SYSTEM

"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">

 

<cross-domain-policy>

  <allow-access-from domain="*"/>

  <allow-http-request-headers-from domain="* " headers="*" />

</cross-domain-policy>

ð  위 코드와 같이 작성한 후, 사이트 최상위 루트에 배포하시면 됩니다.

 

u  Understand Style

1.     Setter를 통해 속성의 값을 설정할 수 있으며, 이렇게 설정된 속성값들은 하나의 스타일로 묶이게 되며, 여러 컨트롤에 적용이 가능합니다. HTML페이지에 정의한 스타일시트(.CSS) 개념과 유사하다고 보시면 됩니다.

-       스타일 선언은 리소스에 해야 하며, 리소스는 Silverlight특정 레이아웃 컨트롤 또는 페이지 단위로 그 적용 범위를 제어 할 수 있습니다.

-       선언된 스타일 리소스가 여러 개의 페이지에 공통으로 적용될 경우는 Application의 리소스를 사용하시면 됩니다.

u  Sample Code

1.     스타일 정의 하지 않고 일반적인 UI (컨트롤에 스타일 정의)

Code

<UserControl x:Class="DemoSample1.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

<Button x:Name="Button1" Width="100" Height="50" Margin="10" Content="버튼1" Background=" Red "></Button>

        <Button x:Name="Button2" Width="100" Height="50" Margin="10" Content="버튼2" Background=" Red "></Button>

    </StackPanel>

</UserControl>

2.     스타일 정의 후, 적용한 UI (레이아웃의 리소스에 스타일 정의)

Code

<UserControl x:Class="DemoSample1.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

        <StackPanel.Resources>

            <Style TargetType="Button" x:Key="buttonStyle">

                <Setter Property="Width" Value="100"></Setter>

                <Setter Property="Height" Value="50"></Setter>

                <Setter Property="Margin" Value="10"></Setter>

                <Setter Property="Background" Value="Red"></Setter>

            </Style>

        </StackPanel.Resources>

       

        <Button x:Name="Button1" Style="{StaticResource buttonStyle}" Content="버튼1"></Button>

        <Button x:Name="Button2" Style="{StaticResource buttonStyle}" Content="버튼2"></Button>

    </StackPanel>

</UserControl>

ð  1번과 2번의 결과 화면은 동일하며, 아래 이미지와 같습니다.

Result

3.     Setter.Value 속성 엘리먼트 사용

-       1번과 2번의 경우는, 컨트롤의 너비나 색과 같이 어트리뷰트 형태로 속성값을 지정하였지만, 그라디언트와 같이 복잡한 형태의 속성값을 지정하기 위해서는 Setter Value 속성 엘리먼트를 통해 지정할 수 있습니다.

Code

<UserControl x:Class="DemoSample1.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

        <StackPanel.Resources>

            <Style TargetType="Button" x:Key="buttonStyle">

                <Setter Property="Width" Value="100"></Setter>

                <Setter Property="Height" Value="50"></Setter>

                <Setter Property="Margin" Value="10"></Setter>

                <Setter Property="Background">

                    <Setter.Value>

                        <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5, 0">

                            <GradientStop Color="White" Offset="0"></GradientStop>

                            <GradientStop Color="Black" Offset="1"></GradientStop>

                        </LinearGradientBrush>

                    </Setter.Value>

                </Setter>

            </Style>

        </StackPanel.Resources>

       

        <Button x:Name="Button1" Style="{StaticResource buttonStyle}" Content="버튼1"></Button>

        <Button x:Name="Button2" Style="{StaticResource buttonStyle}" Content="버튼2"></Button>

    </StackPanel>

</UserControl>

Result
               

4.     코드 비하인드에서 스타일 정의

Code

public partial class Page : UserControl

{

    public Page()

    {

        InitializeComponent();

 

        Style style = new Style(typeof(Button));

        style.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Red)));

        style.Setters.Add(new Setter(WidthProperty, 100));

        style.Setters.Add(new Setter(HeightProperty, 50));

        style.Setters.Add(new Setter(MarginProperty, 10));

 

        this.Button1.Style = style;

    }

}

 

u  Understand Silverlight Networking

1.     다양한 네트워크 통신을 지원합니다.

-       HTTP 통신 뿐만 아니라 TCP 통신을 위한 Socket 또한 지원합니다.

-       웹 서비스나 WCF 서비스로 데이터를 교환 할 수 있으며, RSS와 같은 Feed를 쉽게 가져올 수도 있습니다.

2.     네트워크 통신을 위한 클래스

-       WebClient (System.Net) 클래스

ð  일반 XML과 같은 데이터를 가져오기 위해 사용합니다.

-       SyndicationFeed (System.ServiceModel.Syndication) 클래스

ð  RSS ATOM과 같은 Feed 데이터를 해당 클래스를 활용하여 보다 쉽게 Feed 데이터를 가져올 수 있습니다.

ð  TCP 프로토콜의 통신을 지원하는 Socket 클래스를 제공하고, Socket의 경우 양방향으로 데이터를 주고 받을 수 있고, 비동기 이벤트와 메서드들을 제공합니다.

3.     보안을 위한 URL 접근 제약

-       Silverlight는 기본적으로 크로스 도메인의 통신을 지원하지 않습니다.

ð  demosample1.kr에서 제공하는 서비스를 demosample2.kr이라는 곳에서 호출하여 사용할 수 없습니다. 하지만, 보안 정책 파일을 통해서 특정 클라이언트의 접근을 허용할 수 있습니다. 추후에 샘플 코드를 통해 자세히 소개하겠습니다.

클래스명

WebClient HTTP클래스

Image클래스와 MediaElement 클래스(프로그레시브)

XAML 소스 파일

Font 파일

미디어 스트리밍

허용된 스키마

HTTP, HTTPS

HTTP, HTTPS, FILE

HTTP, HTTPS, FILE

HTTP, HTTPS, FILE

HTTP

크로스 스키마 접근

허용되지 않음

허용되지 않음

허용되지 않음

안됨

HTTP에서는 허용되지 않음

크로스 도메인 접근

보안정책 파일에서 필요 HTTPS에서 HTTPS라면 허용되지 않음

HTTPS에서 HTTPS가 아닐 경우 허용

HTTPS에서 HTTPS가 아닐 경우 허용

허용되지 않음

HTTPS에서 HTTPS가 아닐 경우 허용

 

u  Sameple Code

1.     Naver OpenAPI 를 이용한 Book Search (WebClient 클래스 이용)

-       UI 만들기

Code

<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    >

    <Grid x:Name="LayoutRoot" Background="DarkOrange" >

        <Grid.RowDefinitions>

            <RowDefinition Height="60"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

        </Grid.RowDefinitions>

       

        <Grid Grid.Row="0">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="*"></ColumnDefinition>

                <ColumnDefinition Width="300"></ColumnDefinition>

                <ColumnDefinition Width="100"></ColumnDefinition>

            </Grid.ColumnDefinitions>

           

            <Border CornerRadius="10" Background="Beige" Margin="10">

                <TextBlock Text="Naver OpenAPI를 이용한 책 검색" Margin="10" FontSize="16"></TextBlock>

            </Border>

            <TextBox x:Name="txtSearhWord" Width="700" Height="40" Grid.Column="1" HorizontalAlignment="Left" FontSize="20"  ></TextBox>

            <Button x:Name="btnSearch" Grid.Column="2" Content="검색" Width="90" Height="50" Click="btnSearch_Click" ></Button>

           

        </Grid>

       

       <data:DataGrid x:Name="dgResult" Grid.Row="1"></data:DataGrid>

    </Grid>

</UserControl>

Result

-       WebClient 클래스를 이용하여 검색 데이터(XML) 가져온 후, DataGrid에 데이터 바인딩 시키기

Code

private void btnSearch_Click(object sender, RoutedEventArgs e)

{

    string strSearchWord = txtSearhWord.Text;

    string strSearchUrl = string.Format("http://openapi.naver.com/search?key=acb8d10036417f370d5db98b94f3be49&target=book&query={0}&display=5&start=1&sort=sim", strSearchWord);

 

    WebClient webClient = new WebClient();

    webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);

    webClient.DownloadStringAsync(new Uri(strSearchUrl));

}

 

void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

{

    if (e.Error == null)

    {

        // 검색 XML 데이터 바인딩하기

        dgResult.ItemsSource = e.Result;

    }

}

Result

Description

ð  검색 클릭 시, XML 구조가 한 열에 그려지는 것을 확인 할 수 있습니다. 데이터 그리드에 알맞게 나타내 주기 위해, LINQ를 이용하여 보여주고자 UI에 맞게 XML 데이터를 Parse 하겠습니다.

-       LINQ를 사용하여 검색 XML 데이터 Parse하여 데이터 바인딩 하기

Code

1.     Book 클래스

ð  XML 데이터를 맵핑하기 위해 “Book” 클래스를 정의한 후, 데이터에 알맞은 타입으로 프로퍼티를 생성해보겠습니다.

public class Book

{

    public string BookName { get; set; }

    public Uri LinkUrl { get; set; }

    public Uri ImageUrl { get; set; }

    public string Author { get; set; }

    public int Price { get; set; }

    public string Publisher { get; set; }

    public string PubDate { get; set; }

    public string ISBN { get; set; }

    public string Description { get; set; }

}

2.     Page.xaml 클래스

void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)

{

    if (e.Error == null)

    {

        //Using LINQ to XML to Parse NaverOpenAPI XML Items into Book Class

        XDocument xmlBooks = XDocument.Parse(e.Result);

 

        var books = from book in xmlBooks.Descendants("item")

                    select new Book

                    {

                        BookName = (string)book.Element("title"),

                        LinkUrl = new Uri((string)book.Element("link")),

                        ImageUrl = new Uri((string)book.Element("image")),

                        Author = (string)book.Element("author"),

                        Price = (int)book.Element("price"),

                        Publisher = (string)book.Element("publisher"),

                        PubDate = (string)book.Element("pubdate"),

                        ISBN = (string)book.Element("isbn"),

                        Description = (string)book.Element("description")

                    };

 

        // XML Parse 한 데이터 바인딩하기

dgResult.ItemsSource = books;

    }

}

Result



 

u  Understand Layouts Controls

1.     Canvas

-       컨트롤 내부에 자식 컨트롤들을 가질 수 있으며, 자식 컨트롤들은 부모 컨트롤의 왼쪽 상단의 시작점을 기준으로 자신의 위치를 고정합니다.

-       Canvas 컨트롤 역시도 또 다른 Canvas 컨트롤을 자식으로 가질 수 있습니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Canvas x:Name="LayoutRoot" Background="DarkOrange">

<Button Content="Button1" Width="100" Height="50"  Canvas.Top="80" Canvas.Left="50" Canvas.ZIndex="1"  ></Button>

<Button Content="Button2" Width="100" Height="50"  Canvas.Top="120" Canvas.Left="110"  Canvas.ZIndex="0" ></Button>

    </Canvas>

</UserControl>

Result


Description

ð  Canvas.Top는 해당 Canvas 영역의 상단 시작점 좌표를 나타내며, Canvas.Left는 해당 Canvas 영역의 왼쪽 시작점 좌표를 나타냅니다.

ð  Canvas.ZIndex는 해당 Canvas 영역의 렌더링 순서를 나타내며, 숫자가 높을수록, 영역의 상단에 나타납니다.

2.     StackPanel

-       Canvas와 같이, 자식 컨트롤을 가질 수 있습니다. 하지만, 절대 위치를 지정하지 않고, StackPanel에 속한 자식들을 순서대로 표시합니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="DarkOrange" Orientation="Horizontal">

        <Button Width="100" Height="50" Content="Button1"></Button>

        <Button Width="100" Height="50" Content="Button2"></Button>

        <Button Width="100" Height="50" Content="Button3"></Button>

    </StackPanel>

</UserControl>

Result

Description

ð  Orientation 속성에 Horizontal(수평), Vertical(수직) 지정으로 자식 컨트롤의 정렬 방향 지정을 합니다.

3.     Grid

-       Grid 컨트롤 역시 자식 컨트롤을 가질 수 있으며, HTML의 테이블과 흡사하지만, 해당 셀에 직접 컨트롤을 위치하지 못합니다.

-       RowDefinitions ColumnDefinitions 속성을 이용하여 그리드의 열과 행을 정의해야 합니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="DarkOrange" ShowGridLines="True">

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="100"></ColumnDefinition>

            <ColumnDefinition Width="200"></ColumnDefinition>

            <ColumnDefinition Width="*"></ColumnDefinition>

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition Height="100"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="100"></RowDefinition>

        </Grid.RowDefinitions>

        <Button Width="100" Height="50" Content="Button1" Grid.Row="0"></Button>

        <Button Width="100" Height="50" Content="Button2"  Grid.Row="2" Grid.Column="2"></Button>

        <Button Width="100" Height="50" Content="Button3"  Grid.Row="1" Grid.Column="1" Grid.RowSpan="2"></Button>

    </Grid>

</UserControl>

Result


Description

ð  코드의 음영 부분을 보시면 3 3열로 정의해 보았습니다. 이때, 행과 열의 Width Height 를 지정해 주셔야 합니다. 유심히 보시면, 정의 부분의 Width, Height * 로 지정한 부분이 있는데, 열과 행 크기를 비율로 설정할 수 있습니다.

ð  아래 코드로 설명하자면, 3열로 각각 *, *, 2* Height를 지정하였습니다.

이 같은 경우는 그리드 영역를 비율로 설정합니다. 따라서 아래 코드는 Grid 높이가 300이므로, 첫번째 열 높이 100, 두번째 열 높이 200, 세번째 열 높이 100으로 자동 지정됩니다.

<Grid x:Name="LayoutRoot" Background="DarkOrange" ShowGridLines="True" Height="300">

        <Grid.RowDefinitions>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="2*"></RowDefinition>

</Grid.RowDefinitions>

<Button Width="100" Height="50" Content="Button1" Grid.Row="0"></Button>

        <Button Width="100" Height="50" Content="Button2"  Grid.Row="2"></Button>

        <Button Width="100" Height="50" Content="Button3"  Grid.Row="1"></Button>

</Grid>

 

u  Visual Studio 2008을 이용한 Silverlight 기반 솔루션 만들기

1.     파일/새로 만들기에서 프로젝트를 선택합니다.

2.     새 프로젝트 대화 상자에서 개발 언어 선택 후, Silverlight 를 선택합니다. (Microsoft Silverlight Tools for Visual Studio 2008 SP1이 설치되어 있어야 Silverlight 프로젝트 형식이 나타납니다.)

3.     템플릿 항목에서 Silverlight 응용 프로그램을 선택 한 후, 프로젝트 이름 입력 후, 확인합니다. (대상 플렛폼이 .NET Framework 3.5 로 선택되어 있어야 합니다.)

         

4.     Silverlight 응용 프로그램 추가 대화상자에서 Silverlight 응용 프로그램 호스팅 방법을 선택합니다.

-       Silverlight 응용 프로그램과 Silverlight 컨트롤을 호스팅하는 ASP.NET 기반의 웹 사이트를 구분하여 프로젝트를 구성하는 경우 "솔루션에 Silverlight를 호스팅할 새 ASP.NET 웹 프로젝트 추가"를 선택하고, 웹 프로젝트의 타입과 이름을 추가로 입력합니다.

-       솔루션에 Silverlight 기반 응용프로그램 프로젝트만을 구성하는 경우, “빌드할 때 Silverlight를 호스팅할 테스트 페이지를 자동으로 생성항목을 선택합니다.


u  Silverlight 응용 프로그램 이해하기

1.     XAML 파일

-       Silverlight WPF 응용 프로그램의 UI를 지정하기 위하여 이용 될 수 있는 XML 기반의 파일입니다.

2.     App.xaml 파일

-       Sivlerlight 응용 프로그램의 시동과 구동을 위한 메인 클래스입니다. 이 클래스는 패키지 파일(.xap)이 다운로드 되면 Silverlight 플러그-인에 의하여 관리됩니다.

3.     Page.xaml 파일

-       Page 클래스는 응용프로그램에서 메인 UI를 표시하는 역할을 하며, UserControl로 부터 상속을 받고 XAML 마크업 파일과 .cs, .vb의 코드비하인드 파일의 쌍으로 구성되어 있습니다.

4.     Xap 파일

-       Silverlight 응용 프로그램의 패키지 파일로, 표준 .zip compression 압축 산법을 극소화하기 위하여 클라이언트 다운로드 크기를 이용합니다.

5.     Silverlight 응용 프로그램을 호스팅하는 웹사이트의 구성 요소

-       .aspx, .html 로 구성된 두 개의 페이지로 구성되어 있으며, Silverlight 응용 프로그램 프로젝트 이름에 TestPage라는 이름이 붙어 있습니다.

-       .html 페이지는 Silverlight 응용프로그램을 호스팅하기 위해 <object> 태그를 사용합니다.

-       .aspx 페이지는 .html 과 유사한 결과물을 얻기 위해 ASP.NET Silverlight 서버 컨트롤을 사용합니다.

               


u  Sample Code

1.     기본 컨트롤(버튼) 추가

-       버튼 컨트롤을 아래와 같은 코드를 추가합니다.

Code

<UserControl x:Class="DemoSample.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="DarkOrange">

        <Button x:Name="MyButton" Content="버튼" Width="100" Height="50"></Button>

    </Grid>

</UserControl>

Description

Button 컨트롤을 보시면 x:Name라는 Attribute 값에 MyButton이라고 지정하였고, Content버튼이라는 텍스트를 넣었습니다.

ð  x:Name를 설명드리자면 코드 숨김 또는 일반 코드에서 인스턴스화된 개체에 액세스하기 위해 개체 요소를 고유하게 식별할 때 쓰입니다. (ASP.NET으로 보시면 개체 ID로 보시면 됩니다.)

ð  Content ASP.NET 버튼컨트롤의 Text 라고 보시면 됩니다. (컨트롤의 속성은 ASP.NET 컨트롤과 비슷하므로 금방 이해할 수 있습니다.)

Result

2.     이벤트 핸들러 추가

-       Click 이벤트를 추가해 보겠습니다. Click=” 입력시, 아래 이미지와 같이 나타납니다.

엔터 키 또는 Tab 키를 누르면, Click 이벤트 핸들러 함수명을 x:Name에 해당 이벤트명이 붙어 자동 지정되며, Code Behide 클래스에도 이벤트 핸들러 함수가 자동으로 추가됩니다. (ASP.NET 과 유사함)

-       버튼 클릭시, 버튼 컨트롤 Text“Hello World” 로 변경하는 이벤트 추가해 보겠습니다.


3.     ToolTips

-       xaml 파일에서 Code Behide 클래스로 가는 단축키 : F7

-       Code Behide 클래스에서 xaml 파일로 가는 단축키 : Shift + F7

+ Recent posts