달력

032010  이전 다음

  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  

ASP.NET에서 파라미터 값을 암호화해서 실버라이트로 넘길려고 했습니다.
그리서 C#에서 많이 사용하는 RijndaelManaged 클래스를 사용할려고 하니 이런.. 헉!!~~
아니 실버라이트에서 지원을 안하네요.. ㅋㅋㅋ
그래서 실버라이트에서도 지원하는 AesManaged 클래스를 사용하여 암복호화를 하였습니다.

그럼 암복호화하는 클래스를 생성하고 사용방법을 알아보도록 하겠습니다.


1. 암복호화 클래스 작성

암복호화 클래스는 실버라이트와 ASP.NET에서 별도로 하나씩 만들어 줘야 합니다.
물론 같은 소스로 그대로.. ^^ 이유는 아실거라 생각합니다..

클래스를 하나 생성합니다. 저는 MyAesManaged 라는 이름으로 클래스를 생성했습니다.
일단 상단에 필요한 네임스페이지를 추가합니다.

using System.Security.Cryptography;
using System.Text;
using System.IO;

클래스 내용을 아래와 같이 작성해줍니다.
저는 static 클래스에 static 함수로 작성을 했습니다. 일반 함수로 작성 후 생성하여 사용하셔도 상관없습니다.

아래 파란색으로 된 PasswordKey, PasswordSalt 값은 원하는 값으로 설정을 하면됩니다.

public static class MyAesManaged
{
    private const string PasswordKey = "키 파생에 사용되는 암호입니다.";
    private const string PasswordSalt = "키 파생에 사용되는 키 솔트입니다.";

    /// <summary>
    /// 암호화
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static string Encrypt(string input)
    {
        return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(input)));
    }

    /// <summary>
    /// 암호화
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static byte[] Encrypt(byte[] input)
    {
        byte[] retValue = null;

        using (Aes aes = new AesManaged())
        {
            Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(PasswordKey, Encoding.UTF8.GetBytes(PasswordSalt));
            MemoryStream ms = new MemoryStream();

            aes.Key = deriveBytes.GetBytes(aes.KeySize / 8);
            aes.IV = deriveBytes.GetBytes(aes.BlockSize / 8);


            using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(input, 0, input.Length);
                cs.FlushFinalBlock();
            }

            retValue = ms.ToArray();
        }

        return retValue;
    }

    /// <summary>
    /// 복호화
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static string Decrypt(string input)
    {
        byte[] ret = Decrypt(Convert.FromBase64String(input));
        return Encoding.UTF8.GetString(ret, 0, ret.Length);

    }

    /// <summary>
    /// 복호화
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static byte[] Decrypt(byte[] input)
    {
        byte[] retValue = null;

        using (Aes aes = new AesManaged())
        {
            Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(PasswordKey, Encoding.UTF8.GetBytes(PasswordSalt));
            MemoryStream ms = new MemoryStream();

            aes.Key = deriveBytes.GetBytes(aes.KeySize / 8);
            aes.IV = deriveBytes.GetBytes(aes.BlockSize / 8);

            using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cs.Write(input, 0, input.Length);
                cs.FlushFinalBlock();
            }

            retValue = ms.ToArray();
        }

        return retValue;
    }
}


2. ASP.NET 페이지에서 실버라이트로 넘길 데이터 암호화

저는 파라미터를 암호화해서 넘길려고 해당 클래스를 작성했습니다. 파라미터가 아닌 데이터 연동시 사용해도 좋을거 같습니다. 웹서비스를 이용해서 데이터를 가져올때 암호화해서 실버라이트로 넘기면 좋겠죠^^

아래 코드는 실버라이트로 넘기는 파라미터를 암호화해서 설정하는 코드입니다.
실버라이트의 컨트롤 이름이 slPlayer 입니다^^

string initParam = MyAesManaged.Encrypt("style=blue,code=120");
slPlayer.InitParameters = string.Format("ip={0}", initParam);


3. 실버라이트에서 ASP.NET에서 넘긴 데이터를 받아 복호화

ASP.NET에서 넘긴 파라미터를 받아 복호화한 후 일반 파라미터처럼 사용하도록 설정을 하도록 하겠습니다.
파라미터는 App.xaml.cs 파일에서 받아서 초기화를 하는 방법을 선택했습니다.

private void Application_Startup(object sender, StartupEventArgs e)
{
    if (e.InitParams.Keys.Contains("ip"))
    {
        string[] paramList = MyAesManaged.Decrypt(e.InitParams["ip"]).Split(',');

        foreach (string param in paramList)
        {
            string[] paramValue = param.Split('=');
            this.Resources.Add(paramValue[0], paramValue[1]);
        }

        this.RootVisual = new Page();
    }
    else
    {
        this.RootVisual = new Error();
    }
}


이상으로 실버라이트와 ASP.NET에서 공통으로 사용할 수 있는 암복호화 클래스를 작성해보고 사용하는 방법까지 알아보았습니다. 프로젝트 하시는데 도움이 되었으면 좋겠네요^^
Posted by 상현넘™

댓글을 달아 주세요

실버라이트에는 기본 효과가 그림자(DropShadow) 효과와 번짐(Blur) 효과가 있습니다. (제 기억엔.. 아니면... ㅋㅋ)
이번에 프로젝트를 하면서 실버라이트로 동영상 플레이어를 만드는데 재생중인 동영상을 어둡고 밝게하는 Brightness 효과를 주려고 했는데 지원을 안하다보니... 구글에서 엄청 찾았습니다.
그래서 찾은게 WPF에서 어느분이 만들어 놓은 Custom Effect 내용을 찾아 실버라이트에 적용을 해보았습니다.

일반 먼저 제가 작성한 샘플 프로젝트를 첨부합니다.

MyEffect.zip


1. Visual Studio를 실행하고 실버라이트 프로젝트를 생성합니다. 저는 MyEffect 라는 솔루션에 MyEffect.SL 실버라이트 프로젝트를 만들고 MyEffect.Web 이라는 웹사이트를 생성했습니다.

2. 밝기와 명암비 효과를 내는 쉐더파일(bricon.ps)을 실버라이트 프로젝트에 추가를 합니다. (샘플 프로젝트에 포함되어 있습니다.)

3. 2단계에서 추가한 쉐더파일을 사용할 클래스를 생성을 합니다. 전 BrightContrastEffect 클래스 파일을 생성했습니다. 내용은 아래와 같습니다.

Custom Effect를 작성할때는 ShaderEffect 클래스를 상속받아서 작성을 해야합니다.
아래는 ShaderEffect 클래스를 상속받은 BrightContrastEffect 입니다.
생성자에서는 2단계에서 추가한 쉐더파일을 읽어 PixelShader에 설정하고, 프로퍼티로는 밝기 값을 설정하거나 가져오는 Brightness와 명암비 값을 설정하거나 가져오는 Contrast를 추가했습니다.

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;

namespace MyEffect.SL
{
    // Custom Effect는 ShaderEffect 클래스를 상속받아서 작성을 합니다.
    public class BrightContrastEffect : ShaderEffect
    {
        public static readonly DependencyProperty InputProperty      = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(BrightContrastEffect), 0);
        public static readonly DependencyProperty BrightnessProperty = DependencyProperty.Register("Brightness", typeof(double), typeof(BrightContrastEffect), new System.Windows.PropertyMetadata(0.0, PixelShaderConstantCallback(0)));
        public static readonly DependencyProperty ContrastProperty   = DependencyProperty.Register("Contrast", typeof(double), typeof(BrightContrastEffect), new System.Windows.PropertyMetadata(0.0, PixelShaderConstantCallback(1)));

        public BrightContrastEffect()
        {
            Uri u = new Uri(@"/MyEffect.SL;component/bricon.ps", UriKind.Relative);
            PixelShader = new PixelShader() { UriSource = u };

            this.UpdateShaderValue(InputProperty);
            this.UpdateShaderValue(BrightnessProperty);
            this.UpdateShaderValue(ContrastProperty);
        }

        public Brush Input
        {
            get { return (Brush)GetValue(InputProperty); }
            set { SetValue(InputProperty, value); }
        }
       
        /// <summary>
        /// 밝기
        /// </summary>
        public double Brightness
        {
            get { return (double)GetValue(BrightnessProperty); }
            set { SetValue(BrightnessProperty, value); }
        }

        /// <summary>
        /// 명암비
        /// </summary>
        public double Contrast
        {
            get { return (double)GetValue(ContrastProperty); }
            set { SetValue(ContrastProperty, value); }
        }
    }
}

4. XAML 파일에서 위에서 만든 BrightContrastEffect를 사용해 보도록 하겠습니다.

상단에 생성한 컨트롤을 사용할 수 있도록 네임스페이스를 지정해 줍니다.
컨트롤은 Image 컨트롤을 추가하고 이 Image 컨트롤에 BrightContrastEffect 효과를 주도록 하겠습니다.
그리고 2개의 Slider를 추가하여 밝기(Brightness)와 명암비(Contrast)를 조절하도록 합니다.

<UserControl x:Class="MyEffect.SL.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:my="clr-namespace:MyEffect.SL"
    mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="600">
    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Image Source="komusin.jpg" Grid.Row="0" Width="400" Height="573">
            <Image.Effect>
                <my:BrightContrastEffect x:Name="myBCEffect" />
            </Image.Effect>
        </Image>
        <Canvas Grid.Row="1">
            <TextBlock Text="밝기" Canvas.Top="5" />
            <Slider Width="150" Minimum="-1" Maximum="1" Value="{Binding Brightness, ElementName=myBCEffect, Mode=TwoWay}" Canvas.Left="25" Canvas.Top="5" />
            <TextBlock Text="명암비" Canvas.Top="5" Canvas.Left="190" />
            <Slider Width="150" Minimum="-1" Maximum="1" Value="{Binding Contrast,   ElementName=myBCEffect, Mode=TwoWay}" Canvas.Left="225" Canvas.Top="5" />
        </Canvas>
    </Grid>
</UserControl>

밝기와 명암비의 값은 -1에서 1까지입니다. 그런데 저는 밝기는 -0.7 ~ 0.7, 명암비는 -0.9 ~ 0.9까지로 설정해서 프로젝트에 적용을 하였습니다. 그 이유는 지금까지 작성한 실버라이트를 실행해보고 밝기 및 명암비를 조절해보면 아실겁니다^^

그리고 위에 소스는 XAML에서 직접 컨트롤끼리 바인딩을 했지만 Slider 컨트롤에 ValueChanged 이벤트를 이용하여 값을 설정해도 됩니다.

자... 이젠 테스트 웹페이지를 열어보도록 하겠습니다.......... 아래 예제 이미지처럼 잘 나오나요??
안되시는 분은.. 다시 차근 차근 한번 읽어보고 실수한 부분이 있는지 확인을 해보시기 바랍니다.



이것으로 밝기, 명암비를 조절하는 Custom Effect를 만들어 보았습니다.
어렵진 않죠?? 전 이거 찾는라 고생을 했답니다.. ㅎㅎ^^;


이미지출처 : 고무신 사진동화 [komusin.pe.kr]
참고사이트
 → [Silverlight MSDN Library] ShaderEffect 클래스
 → Brightness and contrast manipulation in WPF 3.5 SP1 (다른주소)
Posted by 상현넘™

댓글을 달아 주세요

윈도우즈 2008을 쓰면서 그동안 실버라이트 설치를 미뤄오다가 드디어 설치를 해보았습니다.
그런데 이게 왠일!!~~ 윈도우즈 2003에서 바로 설치가 되던게 설치가 안되고 계속 실패를 하는것입니다.
저만 그런건지는 모르지만 윈2008 쓰면서 저와 같이 설치가 안되시는 분이 있다면 도움이 조금이라도 될까해서 작성해 봅니다.

1. Windows Server 2008에 Silverlight 2 Beta2 Runtime 설치하기

환경
- Windows Server 2008 Standard [버전 6.0 (빌드 6001:Service Pack 1)]

일단 Silverlight 2 Beta2 Runtime을 다운로드 합니다.
다운이 완료되었으면 [제어판] - [시스템] - [고급 시스템 설정] - [고급] 탭 - 성능에 [설정] - [데이터 실행 방지(DEP)] 로 이동을 합니다. [추가] 버튼을 클릭하면 다운로드한 런타임 파일을 선택합니다.



추가를 했다면 탐색기에서 런타임 파일을 실행하여 설치를 합니다. 설치가 아주 잘 될것입니다.


2. Visual Studio 2008에 Silverlight 2 Beta2 Tools 설치하기

환경
- Windows Server 2008 Standard [버전 6.0 (빌드 6001:Service Pack 1)]
- Visual Studio 2008 한글판 [버전 9.0.21022.8 RTM]

다운로드
- Visual Studio 2008용 Microsoft Silverlight Tools 베타 2

요놈도 참 당황스러웠습니다. 런타임을 어케 어케 설치했더니만 비주얼 스튜디오에 툴이 설치가 안되는것입니다. 그래서 설치시 압축이 해제되는 폴더 (해당 드라이브의 루트에 보면 이상한 폴더명으로 생깁니다.) 를 삭제되기 전에 다른 폴더에 복사를 해두었습니다. 그래서 이것저것 해보았습니다. 한참 쇼하면서 해맸죠!!



위에 리스트를 보다보니 개발자용 런타임(Silverlight.2.0_Developer.exe)이 존재를 하더군요!! 그래서 설치를 할려고 했더니 이미 설치되어있다고 안되더군요!! 그래서 프로그램 삭제에서 기존 런타임을 제거 했습니다.

그런후 다시 설치를 해보았습니다. 아주 설치가 잘 되더군요!! 허허.. 이런 이유같지 않은 이유로 설치가 되지 않았다니!! 제가 참으로 한심하더군요!! ㅎㅎ.. 만약 그래도 설치가 안되면 저처럼 압축을 해제된 상태에서 SPInstaller.exe 이 파일을 실행시켜 설치해 보세요!!

아참!! 이것 저것 해보다가 VS90-KB951457.msp 를 먼저 설치를 해보았습니다. 만약 그래도 설치가 안되시는 분은 이 파일을 먼저 설치해 보세요!!

이상입니다. 저처럼 해매지 말고 한번에 설치를 하시기 바랍니다^^

작성자 : 상현넘™ [SHBLITZ.NET]

Posted by 상현넘™

댓글을 달아 주세요

지난번 HttpHelper 클래스를 이어 이번에는 WebClient를 이용한 Downloader 클래스를 만들어 보도록 하겠습니다.

다들 아시겠지만 Downloader 클래스는 실버라이틑 1.1에는 있었지만 실버라이트 2가 나오면서 사라지고 WebClient로 대체가 되었습니다.

물론 바뀐 WebClient가 사용방법이 어려운건 아니지만 좀 더 사용하기 편하게 하기 위해서 WebClient를 이용한 Downloader 클래스를 작성해 보았습니다.

WebClient를 이용한 Downloader 클래스 만들기

1. Downloader 클래스 작성

Downloader 클래스도 HttpHelper 클래스와 마찬가지로 기본 클래스, 이벤트, 다운로드 구분자로 구성 되어 있습니다.

사용할 네임스페이스

using System.Net;
using System.IO;

다운로드 구분

public enum DownloadKind
{
    Text,
    Binary
}

다운로드 구분은 크게 2가지로 텍스트와 바이너리로 구성이 됩니다. 텍스트는 txt, xml, html, js, cs, asp, aspx 같은 순수 텍스트로만 이루어진 파일이며, 바이너리는 wmv, zip, exe 같은 동영상이나 압축파일 등등 텍스트를 제외한 모든 파일이라고 생각해도 좋을거 같습니다.

이벤트 핸들러

public delegate void DownloadCompleteEventHandler(DownloadCompleteEventArgs e);
public class DownloadCompleteEventArgs : EventArgs
{
    public Stream ResultStream { get; set; }
    public string ResultString { get; set; }
    public DownloadCompleteEventArgs(Stream result)
    {
        this.ResultStream = result;
    }
    public DownloadCompleteEventArgs(string result)
    {
        this.ResultString = result;
    }
}
public delegate void DownloadErrorEventHandler(DownloadErrorEventArgs e);
public class DownloadErrorEventArgs : EventArgs
{
    public string Error { get; set; }
    public DownloadErrorEventArgs(string error)
    {
        this.Error = error;
    }
}

이벤트 핸들러는 크게 다운로드 완료 이벤트와 다운로드 에러 이벤트로 구성됩니다.

다음은 기본 클래스의 구성 입니다.

전역

WebClient       m_WebClient;
DownloadKind m_DownloadKind;
Uri                 m_DownloadUri;
public event DownloadCompleteEventHandler DownloadComplete;
private void OnDownloadComplete(DownloadCompleteEventArgs e)
{
    if (this.DownloadComplete != null)
    {
        this.DownloadComplete(e);
    }
}
public event DownloadErrorEventHandler DownloadError;
private void OnDownloadError(DownloadErrorEventArgs e)
{
    if (this.DownloadError != null)
    {
        this.DownloadError(e);
    }
}

다운로드에 필요한 변수와 이벤트를 발생 시키기 위한 내용입니다.

생성자

public Downloader(Uri downloadUri, DownloadKind kind)
{
    m_WebClient = new WebClient();
    m_DownloadKind = kind;
    m_DownloadUri  = downloadUri;
    if (m_DownloadKind == DownloadKind.Binary)
    {
        m_WebClient.OpenReadCompleted += new OpenReadCompletedEventHandler(m_WebClient_OpenReadCompleted);
    }
    else
    {
        m_WebClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(m_WebClient_DownloadStringCompleted);
    }
}

다운로드 구분에 따라서 이벤트를 다르게 생성해 줍니다.

다운로드 시작 함수

public void Start()
{
    if (m_DownloadKind == DownloadKind.Binary)
    {
        m_WebClient.OpenReadAsync(m_DownloadUri);
    }
    else
    {
        m_WebClient.DownloadStringAsync(m_DownloadUri);
    }
}

역시 다운로드 구분에 따라서 Async 함수를 구분해서 실행 합니다.

바이너리 파일 다운로드 완료 이벤트

void m_WebClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if ((e.Error == null) && (e.Cancelled == false))
    {
        OnDownloadComplete(new DownloadCompleteEventArgs(e.Result));
    }
    else
    {
        OnDownloadError(new DownloadErrorEventArgs(e.Error.Message));
    }
}

텍스트 파일 다운로드 완료 이벤트

void m_WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    if(e.Error == null)
    {
        OnDownloadComplete(new DownloadCompleteEventArgs(e.Result));
    }
    else
    {
        OnDownloadError(new DownloadErrorEventArgs(e.Error.Message));
    }
}

이렇게 해서 Downloader 클래스 작성을 완료 했습니다. 이 클래스에 자신이 원하는 기능을 추가해서 확장 클래스를 작성해서 사용해도 좋을 것입니다.

Downloader 클래스 다운로드



2. Downloader 클래스 사용방법

다운로드 하기

Uri uri = new Uri(http://localhost/DownloaderTest.aspx);
Downloader down = new Downloader(uri, DownloadKind.Text);
down.DownloadComplete += new DownloadCompleteEventHandler(down_DownloadComplete);
down.DownloadError += new DownloadErrorEventHandler(down_DownloadError);
down.Start();

이벤트

void down_DownloadError(DownloadErrorEventArgs e)
{
    txtResult.Text = "에러 : " + e.Error;
}
void down_DownloadComplete(DownloadCompleteEventArgs e)
{
    // 텍스트일 경우
    txtResult.Text = e.ResultString;

    // 바이너리일 경우
    MediaElement media = new MediaElement();
    media.SetSource = e.ResultStream;
    ...
}

도메인 접근시 크로스 도메인이 허용이 안된 사이트는 에러 이벤트를 발생 시킵니다.
이 경우 에러는 Download Failure 라는 에러가 나오네요!!

이것으로 다운로더 클래스 사용 방법도 마치도록 하겠습니다.
아무쪼록 이 글을 보시는 분들께 많은 도움이 되었으면 좋겠습니다.

작성자 : 상현넘™ [http://www.shblitz.net]
Posted by 상현넘™

댓글을 달아 주세요

안녕하세요!!
이번에는 HttpWebRequest 를 편하게 사용할 수 있도록 Helper 클래스를 작성해보도록 하겠습니다.
HttpWebRequest 는 1.1에서 2로 넘어오면서 사용방법이 변경된것을 아실겁니다.
좀 복잡해 졌죠^^ 변경된 내용은 MSDN : Breaking Changes in Silverlight 2에서 BrowserHttpWebRequest Removed 부분을 참고하시면 됩니다.
그리고 이번 강좌는 위 MSDN 내용과 CameronAlbert.comHttpWebRequest Helper for Silverlight 2의 내용을 참고했습니다.

Silverlight 2용 HttpWebRequest Helper Class 만들기

1. HttpHelper 클래스 작성

그럼 일단 HttpWebRequest Helper 클래스를 작성해 보겠습니다.
클래스명은 HttpHelper로 하고 파일명은 HttpHelper.cs로 하겠습니다.
어려운 내용은 없으니 소스 위주로 진행을 하도록 하겠습니다!!

실버라이트 프로젝트에서 추가 -> 실버라이트 클래스를 추가하여 주시기 바랍니다.

이 Helper 클래스는 기본 클래스, Method enum, 2개의 이벤트 핸들러를 사용합니다.

추가 Namespace

using System.IO;
using System.Net;
using System.Collections.Generic;

Method enum

public enum Method
{
    Post,
    Get
}

Response 완료 이벤트

public delegate void HttpResponseCompleteEventHandler(HttpResponseCompleteEventArgs e);
public class HttpResponseCompleteEventArgs : EventArgs
{
    public string Response { get; set; }
    public HttpResponseCompleteEventArgs(string response)
    {
        this.Response = response;
    }
}

Error 이벤트

public delegate void HttpErrorEventHandler(HttpErrorEventArgs e);
public class HttpErrorEventArgs : EventArgs
{
    public string Error { get; set; }
    public HttpErrorEventArgs(string error)
    {
        this.Error = error;
    }
}

이제부터 기본 HttpHelper 클래스를 작성하겠습니다.

전역

private HttpWebRequest Request { get; set; }
public Dictionary<string, string> PostValues { get; private set; }

public event HttpResponseCompleteEventHandler ResponseComplete;
private void OnResponseComplete(HttpResponseCompleteEventArgs e)
{
    if (this.ResponseComplete != null)
    {
        this.ResponseComplete(e);
    }
}

public event HttpErrorEventHandler Error;
private void OnError(HttpErrorEventArgs e)
{
    if (this.Error != null)
    {
        this.Error(e);
    }
}

생성자

public HttpHelper(Uri requestUri, Method method, params KeyValuePair<string, string>[] postValues)
{
    this.Request = (HttpWebRequest)WebRequest.Create(requestUri);
    this.Request.ContentType = "application/x-www-form-urlencoded";
    this.Request.Method = method.Equals(Method.Post) ? "POST" : "GET";
    if (postValues.Length > 0)
    {
        this.PostValues = new Dictionary<string, string>();
        foreach (var item in postValues)
        {
            this.PostValues.Add(item.Key, item.Value);
        }
    }
}

헤더 설정

public void SetHeader(string name, string value)
{
    this.Request.Headers[name] = value;
}

실행

public void Execute()
{
    try
    {
        this.Request.BeginGetRequestStream(new AsyncCallback(RequestCallback), this.Request);
    }
    catch (Exception ex)
    {
        OnError(new HttpErrorEventArgs("Execute : " + ex.Message));
    }
}

Request Callback

private void RequestCallback(IAsyncResult asyncResult)
{
    HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest;
    if (request != null)
    {
        try
        {
            if ((PostValues != null) && (PostValues.Count > 0))
            {
                using (StreamWriter writer = new StreamWriter(request.EndGetRequestStream(asyncResult)))
                {
                    foreach (var item in PostValues)
                    {
                        writer.Write("{0}={1}&", item.Key, item.Value);
                    }
                }
            }
            request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
        }
        catch (Exception ex)
        {
            OnError(new HttpErrorEventArgs("RequestCallback : " + ex.Message));
        }
    }
}

Response Callback

private void ResponseCallback(IAsyncResult asyncResult)
{
    HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest;
    if (request != null)
    {
        try
        {
            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);
            if (response != null)
            {
                Stream stream = response.GetResponseStream();
                if (stream != null)
                {
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        OnResponseComplete(new HttpResponseCompleteEventArgs(reader.ReadToEnd()));
                    }
                    stream.Close();
                }
                else
                {
                    OnResponseComplete(new HttpResponseCompleteEventArgs("StatusCode : " + response.StatusCode));
                }
                response.Close();
            }
        }
        catch (Exception ex)
        {
            OnError(new HttpErrorEventArgs("ResponseCallback : " + ex.Message));
        }
    }
}

이렇게 해서 HttpHelper 클래스를 모두 작성했습니다.

2. HttpHelper 클래스 사용방법

HttpHelper 클래스를 사용하는 방법의 몇가지 예를 들어서 설명을 하도록 하겠습니다.
그리고 요청할 URL이 같은 서버이거나 크로스 도메인이 허용된 경우에만 접근이 가능합니다.
다른 도메인에 접근을 했는데 Status Code가 Not Found가 나오면 클로스 도메인이 허용이 안된 사이트입니다.
참고 : 도메인 영역을 넘을 수 있는 서비스 만들기

예제1) 파라미터가 없는 요청

HttpHelper helper = new HttpHelper(
    new Uri("http://localhost/Test/Default.aspx"),
    Method.Post);
helper.ResponseComplete += new HttpResponseCompleteEventHandler(helper_ResponseComplete);
helper.Error += new HttpErrorEventHandler(helper_Error);
helper.Execute();

예제2) 파라미터가 1개인 요청

HttpHelper helper = new HttpHelper(
    new Uri("http://localhost/Test/Default.aspx"),
    Method.Post,
    new KeyValuePair<string, string>("key", "value"));
helper.ResponseComplete += new HttpResponseCompleteEventHandler(helper_ResponseComplete);
helper.Error += new HttpErrorEventHandler(helper_Error);
helper.Execute();

예제3) 파라미터가 2개 이상인 요청

HttpHelper helper = new HttpHelper(
    new Uri("http://localhost/Test/Default.aspx"),
    Method.Post,
    new KeyValuePair<string, string>("key", "value"),
    new KeyValuePair<string, string>("key2", "value2")); //이와 같이 계속 추가하면 됩니다.
helper.ResponseComplete += new HttpResponseCompleteEventHandler(helper_ResponseComplete);
helper.Error += new HttpErrorEventHandler(helper_Error);
helper.Execute();

예제4) 헤더가 존재하는 요청

HttpHelper helper = new HttpHelper(
    new Uri("http://localhost/Test/Default.aspx"),
    Method.Post);
helper.ResponseComplete += new HttpResponseCompleteEventHandler(helper_ResponseComplete);
helper.Error += new HttpErrorEventHandler(helper_Error);
helper.SetHeader("Authorization", "Basic ***************");
helper.Execute();

이벤트 처리

void helper_Error(HttpErrorEventArgs e)
{
    txtLog.Text = "에러 : " + e.Error;
}
void helper_ResponseComplete(HttpResponseCompleteEventArgs e)
{
    txtLog.Text = "완료 : " + e.Response;
}

이상으로 HttpHelper 클래스를 작성하고 사용하는 방법까지 알아보았습니다.
위에 작성한 HttpHelper가 필요하신 분은 다운로드 하시기 바랍니다.

HttpHelper.cs 파일 다운로드


작성자 : 상현넘™ [http://www.shblitz.net]
Posted by 상현넘™

댓글을 달아 주세요

  1. 양기영  댓글주소 수정/삭제 댓글쓰기 2010/02/17 21:43

    안녕하세요~ 작성하신 HttpHelper 클래스를 통해서 많은 도움을 받았습니다.^^
    먼저 감사드립니다.
    의문이 있어 한가지 질문을 드리려고 합니다.
    Execute() 메서드 내의 this.Request.BeginGetRequestStream() 호출 시
    System.Net.ProtocolViolationException이 발생하는데요..
    request 와 response에서 무언가 문제가 있나 싶어 디버깅을 해보았으나 해당 루틴까지
    넘어가지도 않은채 예외를 리턴하며 아무 반응이 없더군요..
    혹시 이점에 대하여 경험이나 노하우가 있으신지 여쭤봅니다.
    앞으로도 게시글 및 자료 참고하여 공부에 많은 도움이 될 듯 합니다.
    감사합니다.

Silverlight에서 파라미터를 받아 초기화를 하자.

이번 강좌는 객체에서 파라미터를 받아서 초기화를 하는 방법에 대해서 알아 보도록 하겠습니다.

모두들 플래시를 많이 사용해 보셨을 것입니다. object 태그의 param 속성에 FlashVars를 이용하여 파라미터를 넘겨서 플래시 내부에서 넘어온 데이터를 사용합니다.

기존 1.0이나 1.1에서 사용이 가능한지는 모르겠지만 (전에 찾아보다 실패했음) 2 Beta1에서는 당당히 지원을 하고 있습니다.

그럼 이제부터 사용방법과 예제를 통하여 배우도록 하겠습니다.

1. 실버라이트를 부르는 페이지에서 파라미터 설정

우리가 실버라이트를 부를때 사용할 수 있는 방법은 2가지가 있습니다(Silverlilght 2 기준). ASP.NET의 Silverlight 컨트롤과 Html의 object 태그입니다.

ASP.NET의 Silverlight 컨트롤


<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/Shblitz.DeepZoom.xap" Version="2.0" Width="100%" Height="100%" InitParameters="Page=cat,Seq=1" />

Html의 object 태그

<div id="silverlightControlHost">
 <object data="data:application/x-silverlight," type="application/x-silverlight-2-b1" width="100%" height="100%">
  <param name="source" value="ClientBin/Shblitz.DeepZoom.xap"/>
  <param name="onerror" value="onSilverlightError" />
  <param name="background" value="white" />
  <param name="initParams" value="Page=cat,Seq=1" />
 
  <a href="http://go.microsoft.com/fwlink/?LinkID=108182" style="text-decoration: none;">
    <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
  </a>
 </object>
 <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>

2. 실버라이트 App.xaml 에서의 처리

App.xaml 파일에서 처리하는 설명은 2가지 예제를 들어서 설명을 하도록 하겠습니다.

예제1) Page 파라미터의 값에 따라 UserControl 생성

private void Application_Startup(object sender, StartupEventArgs e)
{
    // Page 파라미터 값에 따라 원하는 UserControl을 생성한다.
    switch(e.InitParams["Page"])
    {
        case "cat":
            this.RootVisual = new Cat();
            break;
        case "dog":
            this.RootVisual = new Dog();
            break;
        default :
            this.RootVisual = new Page();
            break;
    }

    // 나머지 파라미터들은 각자 알아서 사용해보시면 됩니다.
}

예제2) 파라미터 값을 UserControl로 보내기

UserControl의 Page.xaml 파일에서 생성자 변경

public Page(IDictionary<string, string> InitParams)
{
    // 전역으로 저장하여 필요할 때 사용하시거나 초기화만 시키면 됩니다.
    _initArguments = InitParams;
    InitializeComponent();
}

App.xaml 파일 처리

private void Application_Startup(object sender, StartupEventArgs e)
{
    // 넘어온 파라미터를 UserControl로 넘기기만 하면 됩니다.
    this.RootVisual = new Page(e.InitParams);
}

위 예제 2개를 혼용하여 사용하면 편리하게 사용이 가능할것입니다.

3. 실버라이트를 부르는 페이지의 QueryString 사용

QueryString을 사용하는 방법은 1.1에서와 2에서 사용방법이 변경이 되었습니다.

접속 주소가 아래와 같을 경우

http://shblitz.net/silverlight.aspx?Seq=1

Silverlight 1.1의 경우

string seq = System.Windows.Browser.HtmlPage.QueryString["Seq"];

Silverlight 2의 경우

System.Windows.Browser.HtmlDocument doc = new System.Windows.Browser.HtmlDocument();
string seq = doc.QueryString["Seq"];

이것으로 마치도록 하겠습니다. 이 글을 읽은 분들께 많은 도움이 되었으면 합니다!!

작성자 : 상현넘™ [http://www.shblitz.net]
Posted by 상현넘™

댓글을 달아 주세요

  1. Shorty.  댓글주소 수정/삭제 댓글쓰기 2008/06/04 10:00

    담아가겠습니다..

  2. KillerXman  댓글주소 수정/삭제 댓글쓰기 2008/09/02 10:10

    좋은글 감사합니다. 담아 가겠습니다.

  3. 강태중  댓글주소 수정/삭제 댓글쓰기 2008/10/30 13:14

    정말 유용한 글 감사합니다.^^
    담아갈게요.

  4. dsjeon  댓글주소 수정/삭제 댓글쓰기 2009/10/08 12:59

    제가 찾던 내용입니다. ㅠㅠ~
    감사합니다. 많은 도움되었습니다.

  5. Mazinga  댓글주소 수정/삭제 댓글쓰기 2009/11/24 00:25

    감사합니다!!

실버라이트 1.1에서 2 베타1으로 버전업이 되면서 변경된 부분이 상당히 있습니다.
그래서 마이그레션하기도 쉽지 않습니다.
그래서 실버라이트 2 프로젝트를 새로 만들어서 클래스 복사하는 형식으로 마이그레이션을 하는 분들이 많을 것이라고 생각이 됩니다.
이 마이그레이션 작업을 하는 분들에게 도움이 되고자 변경된 내용을 정리해 보았습니다.

내용은 MSDN실버라이트(Silverlight) 정보공유 카페에서 참고를 하였습니다.

1. EventHandler의 변화


MouseLeftButtonUp과 MouseLeftButtonDown 의 Event가 다음과 같이 바뀌었습니다.

- 1.1 alpha : MouseEventHandler, MouseEventArgs
- 2 beta 1 : MouseButtonEventHandler, MouseButtonEventArgs

MouseLeave 의 Event가 다음과 같이 바뀌었습니다.

- 1.1 alpha : EventHandler, Eventargs
- 2 beta 1 : MouseEventHandler, MouseEventArgs

Loaded 의 Event가 다음과 같이 바뀌었습니다.

- 1.1 alpha : EventHandler, Eventargs
- 2 beta 1 : RoutedEventHandler, RoutedEventArgs

KeyEvent 에서 KeyboardEventArgs의 아규먼트 값의 Key 값이 Key의 enum 타입으로 바뀌었습니다.

void onKeyUp(object sender, KeyboardEventArgs e)
{
    switch (e.Key) // e.Key가 enum 타입입니다.
    {
        ....
    }
}

2. BrowserHost 변경


이 기능은 사이즈 변경이나 전체화면을 사용할 때 많이 사용하셨을 것입니다.
네임스페이스와 클래스가 아래와 같이 변경이 되었습니다.

BrowserHost -> Application.Current.Host.Content

Resize 이벤트 처리는 아래와 같이 변경 되었습니다.

Application.Current.Host.Content.Resized += new EventHandler(Content_Resized);

void Content_Resized(object sender, EventArgs e)
{
    Width = Application.Current.Host.Content.ActualWidth;
    Height = Application.Current.Host.Content.ActualHeight;
}

IsFullScreen 속성의 위치는 아래와 같이 변경되었습니다.

// 풀스크린 여부
Application.Current.Host.Content.IsFullScreen

풀스크린 변경 이벤트 핸들러

Application.Current.Host.Content.FullScreenChanged += new EventHandler(Content_FullScreenChanged);

void Content_FullScreenChanged(object sender, EventArgs e)
{
    System.Windows.Interop.Content content =  Application.Current.Host.Content;

    // 풀스크린 여부
    if (content .IsFullScreen)
    {
        double heightRatio = content.ActualHeight / this.Height;
        double widthRatio = content.ActualWidth / this.Width;
        ScaleTransform scale = new ScaleTransform();
        scale.ScaleX = widthRatio;
        scale.ScaleY = heightRatio;
        this.RenderTransform = scale;
    }
    else
    {
        this.RenderTransform = null;
    }
}

네임스페이스

using System.Windows;

3. Image.Source 사용법

1.1에서는 Uri 클래스를 바로 적용을 했지만 2에서는 Bitmap으로 변경해서 적용을 하도록 변경이 되었습니다.

Image image = new Image();
image.Source = new BitmapImage(new Uri("http://shblitz.net/shblitz.jpg", UriKind.Absolute));

BitmapImage를 사용하면서 좋은 점은 BitmapImage에 DownloadProgress 이벤트가 있어서 이미지가 다 받아졌는지 확인이 가능하다는 것입니다.

Image image = new Image();
BitmapImage bitmap = new BitmapImage(new Uri(http://shblitz.net/shblitz.jpg, UriKind.Absolute));
bitmap.DownloadProgress += new DownloadProgressEventHandler(bitmap_DownloadProgress);

// 다운로드 완료 이벤트 핸들러
void bitmap_DownloadProgress(object sender, DownloadProgressEventArgs e)
{
    BitmapImage bitmap = sender as BitmapImage;
    // 다운로드 성공
    if (e.Progress == 1)
    {
        // 로직...
    }
}

네임스페이스

using System.Windows.Media.Imaging;

4. HtmlTimer 대신 DispatcherTimer 사용

Silverlight 2에서는 HtmlTimer가 사라졌습니다. 대신 아래와 같은 클래스를 사용하면 될것입니다.

System.Threading.Timer
System.Windows.Threading.DispatcherTimer

HtmlTimer를 사용하시던 분은 DispatcherTimer를 사용 할것을 권합니다.

사용법은 비슷하며, Interval을 TimeSpan으로 수정만 하시면 될것입니다.

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(3000); // 3초
// timer.Interval = new TimeSpan(0, 0, 0, 0, 3000); // 3초
timer.Tick += new EventHandler(timer_Tick);
timer.Start();

void timer_Tick(object sender, EventArgs e)
{
    // 로직...
}

5. Downloader 대신 WebClient 사용

1.1에서 한글을 사용하기 위해 Downloder를 많이 사용해 보셔을 것입니다. 그러나 Silverlight 2에서 이 Downloader가 사라졌습니다. 대신 WebClient를 사용하시면 됩니다.

파일 전송을 위한 메서드로 OpenReadAsync와 DownloadStringAsync가 지원됩니다.

OpenReadAsync

받아올 파일이 wmv, zip 파일같이 이진파일일 경우 사용합니다.

WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
wc.OpenReadAsync(new Uri("song.wma", UriKind.Relative));

이벤트 아규먼트로 넘어오는 e.Result 값은 Stream으로 넘어온다.

// 다운로드 완료 이벤트 핸들러
void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    MediaElement media = new MediaElement();
    if ((e.Error == null) && (e.Cancelled == false))
    {
        media.SetSource = e.Result;
        LayoutRoot.Children.Add(media);
        media.Play();
    }
}

Zip 파일 다운로드시 사용 예제

void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
    if ((e.Error == null) && (e.Cancelled == false))
    {
        StreamResourceInfo zipResourceInfo = new StreamResourceInfo(e.Result, null);
        StreamResourceInfo imageResourceInfo = Application.GetResourceStream(zipResourceInfo, new Uri("image1.jpg"));
        // .....
    }
}

DownloadStringAsync

받아올 파일이 xml이나 Text 형식일 경우 이 메소드를 사용합니다.

WebClient wc = new WebClient();
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri("data.xml", UriKind.Relative));

이벤트 아규먼트로 넘어오는 e.Result 값은 String으로 넘어온다.

// 다운로드 완료 이벤트 핸들러
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    XmlReader xr = XmlReader.Create(new StringReader(e.Result));
    //...
}

* 참고 : 실버라이트2의 루트는 1.1과는 달리 ClientBin 폴더가 루트로 인식됩니다. 그러니 다운로드할 파일은 기본적으로 ClientBin 폴더 이하에 있어야 합니다. 절대경로로 사용할 경우는 상관없습니다.

네임스페이스

using System.Net;

6. HtmlPage에서 HtmlDocument로 이동된 함수들

Submit, Cookies, QueryString, DocumentUri

예제)

System.Windows.Browser.HtmlDocument doc = new System.Windows.Browser.HtmlDocument();
string seq = doc.QueryString["ParameterName"];

7. HtmlPage에서 HtmlWindow로 이동된 함수들

CurrentBookmark, Alert/Confirm/Eval/Prompt, CreateInstance, Navigate*/NavigateToBookmark

예제)

System.Windows.Browser.HtmlWindow win = System.Windows.Browser.HtmlPage.Window;
win.Alert("경고");

작성자 : 상현넘™ [http://www.shblitz.net]
Posted by 상현넘™

댓글을 달아 주세요

  1. 이봉호  댓글주소 수정/삭제 댓글쓰기 2008/03/25 16:19

    감사합니다 좋은 참고 자료가 돼겠어요^^

  2. ramses8  댓글주소 수정/삭제 댓글쓰기 2008/07/31 09:42

    좋은 내용 고맙습니다~

  3. 실버라잇  댓글주소 수정/삭제 댓글쓰기 2008/09/06 23:13

    좋은 정보 감사합니다..스크랩 해 갈게요~

Deep Zoom 강좌 : 2. Silverlight 프로젝트 만들기

이미지 갤러리를 만들었으면 이젠 실버라이트로 Deep Zoom 프로젝트를 만들어 보도록 하겠습니다.
(깨진 이미지는 클릭하면 원본 크기로 보실수 있습니다.)

1. 실버라이트 프로젝트 생성

사용자 삽입 이미지

Visual Studio 2008을 실행시켜 [새 프로젝트]를 선택합니다. 프로젝트 형식에서 Silverlight - Silverlight Application을 선택하고, 프로젝트 이름과 위치, 솔루션 이름을 설정합니다.

사용자 삽입 이미지

실버라이트 프로젝트와 함께 만들어질 웹 프로젝트입니다. Project Type에서 Web Site 또는 Web Application 프로젝트 중 선택하면 됩니다. 전 Web Application을 사용하도록 하겠습니다.


2. 이미지 갤러리를 웹 프로젝트에 포함

사용자 삽입 이미지

새 프로젝트를 생성했으면 솔루션을 선택한 후 솔루션 빌드를 한번 해줍니다. 그러면 위 이미지를 보는거와 같이 웹프로젝트에 ClientBin 폴더가 자동 생성이됩니다.

사용자 삽입 이미지사용자 삽입 이미지

이전 첫번째 강의해서 만들어 놓은 이미지 갤러리의 폴더를 위에서 자동 생성된 ClientBin 폴더에 복사를 합니다. 그런 후 위 이미지와 같이 프로젝트에 포함을 시킵니다.

ClientBin 폴더에 이미지 갤러리가 있어야만 화면에 표시가 되니 주의하시기 바랍니다.


3. 실버라이트 프로젝트에 이미지 갤러리 포함시키기

실버라이트 프로젝트에서 Page.xaml 파일을 열어 MultiScaleImage 콘트롤을 사용하겠습니다.

<UserControl x:Class="Shblitz.DeepZoom.Page"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <MultiScaleImage x:Name="objDeepZoom" Source="shblitz/info.bin"></MultiScaleImage>
    </Grid>
</UserControl>

Grid 콘트롤 안에 MultiScaleImage을 추가하고 이름과 소스를 지정합니다. 소스는 웹 프로젝트의 ClientBin에 포함시킨 이미지 갤러리 입니다.

이젠 다시 빌드를 해준 후 브라우저 보기로 확인을 해보도록 하겠습니다.

사용자 삽입 이미지


웹 프로젝트에서 Shblitz.DeepZoomTestPage.aspx 파일을 선택 후 마우스 오른쪽 버튼을 눌러 [브라우저에서 보기]를 선택합니다. 그러면 위와 같이 브라우저에 이미지가 나타나게 됩니다. 만약 이미지가 나오는 않는다면 소스 경로를 다시 확인해 보시기 바랍니다.

여기까지 잘 따라 오셨나요?? 여기가 끝이 아닙니다. 이미지가 확대가 되고 축소가 되고 그래야하는데 아무런 반응이 없을 것입니다. 이제부터 기능을 추가하도록 하겠습니다.


4. 기능을 추가하여 확대 / 축소 기능 사용하기
- 이 기능은 외국사이트(기억안남)에서 참고한 소스입니다.

Page.xaml 파일 소스에서 이벤트를 추가하도록 하겠습니다.

<UserControl x:Class="Shblitz.DeepZoom.Page"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300"
    MouseMove="Page_MouseMove"
    MouseLeftButtonDown="Page_MouseLeftButtonDown"
    MouseLeftButtonUp="Page_MouseLeftButtonUp">
    <Grid x:Name="LayoutRoot" Background="White">
        <MultiScaleImage x:Name="objDeepZoom" Source="shblitz/info.bin" MouseLeave="objDeepZoom_MouseLeave"></MultiScaleImage>
    </Grid>
</UserControl>

UserControlMouseMove, MouseLeftButtonDown, MouseLeftButtonUp 이렇게 3개의 이벤트를 추가하고 MultiScaleImageMouseLeave를 추가합니다.

다음은 Page.xaml.cs 파일에 각 이벤트에 대한 로직을 추가합니다.

// 각 좌표를 저장할 전역 변수
Point lastMousePos = new Point();
bool mouseButtonPressed = false;
bool mouseIsDragging = false;
Point dragOffset;
Point currentPosition;
public double ZoomFactor { get; set; }

확대 / 축소 기능을 할 함수를 만들어 줍니다.

/// <summary>
/// 확대 / 축소
/// </summary>
/// <param name="zoom"></param>
/// <param name="pointToZoom"></param>
public void Zoom(double zoom, Point pointToZoom)
{
    Point logicalPoint = this.objDeepZoom.ElementToLogicalPoint(pointToZoom);
    this.objDeepZoom.ZoomAboutLogicalPoint(zoom, logicalPoint.X, logicalPoint.Y);
}

각 이벤트에 대한 로직을 작성해 줍니다.

/// <summary>
/// 마우스 클릭
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    mouseButtonPressed = true;
    mouseIsDragging = false;
    dragOffset = e.GetPosition(this);
    currentPosition = objDeepZoom.ViewportOrigin;
}
/// <summary>
/// 마우스 이동
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Page_MouseMove(object sender, MouseEventArgs e)
{
    if (mouseButtonPressed)
    {
        mouseIsDragging = true;
    }
    this.lastMousePos = e.GetPosition(this.objDeepZoom);
    if (mouseIsDragging)
    {
        Point newOrigin = new Point();
        newOrigin.X = currentPosition.X - (((e.GetPosition(objDeepZoom).X - dragOffset.X) / objDeepZoom.ActualWidth) * objDeepZoom.ViewportWidth);
        newOrigin.Y = currentPosition.Y - (((e.GetPosition(objDeepZoom).Y - dragOffset.Y) / objDeepZoom.ActualHeight) * objDeepZoom.ViewportWidth);
        objDeepZoom.ViewportOrigin = newOrigin;
    }
}
/// <summary>
/// 마우스 클릭 해제
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    mouseButtonPressed = false;
    if (mouseIsDragging == false)
    {
        bool shiftDown = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
        ZoomFactor = 2.0;
        if (shiftDown) ZoomFactor = 0.5;
        Zoom(ZoomFactor, this.lastMousePos);
    }
    mouseIsDragging = false;
}
/// <summary>
/// 마우스 객체 읽음
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void objDeepZoom_MouseLeave(object sender, MouseEventArgs e)
{
    mouseIsDragging = false;
}

마우스 휠 기능도 사용할 수 있도록 하겠습니다.
MouseWheelHelper.cs 클래스를 하나 추가하여 아래와 같이 작성해 줍니다.

// 상단에 Browser 참조 추가
using System.Windows.Browser;

// 마우스 휠 전용 이벤트 Args 만들기
public class MouseWheelEventArgs : EventArgs
{
    private double delta;
    private bool handled = false;
    public MouseWheelEventArgs(double delta)
    {
        this.delta = delta;
    }
    public double Delta
    {
        get { return this.delta; }
    }
    // Use handled to prevent the default browser behavior!
    public bool Handled
    {
        get { return this.handled; }
        set { this.handled = value; }
    }
}

// 마우스 휠 클래스 작성
public class MouseWheelHelper
{
    public event EventHandler<MouseWheelEventArgs> Moved;
    private static Worker worker;
    private bool isMouseOver = false;
    public MouseWheelHelper(FrameworkElement element)
    {
        if (MouseWheelHelper.worker == null)
            MouseWheelHelper.worker = new Worker();
        MouseWheelHelper.worker.Moved += this.HandleMouseWheel;
        element.MouseEnter += this.HandleMouseEnter;
        element.MouseLeave += this.HandleMouseLeave;
        element.MouseMove += this.HandleMouseMove;
    }
    private void HandleMouseWheel(object sender, MouseWheelEventArgs args)
    {
        if (this.isMouseOver)
            this.Moved(this, args);
    }
    private void HandleMouseEnter(object sender, EventArgs e)
    {
        this.isMouseOver = true;
    }
    private void HandleMouseLeave(object sender, EventArgs e)
    {
        this.isMouseOver = false;
    }
    private void HandleMouseMove(object sender, EventArgs e)
    {
        this.isMouseOver = true;
    }
    private class Worker
    {
        public event EventHandler<MouseWheelEventArgs> Moved;
        public Worker()
        {
            if (HtmlPage.IsEnabled)
            {
                HtmlPage.Window.AttachEvent("DOMMouseScroll", this.HandleMouseWheel);
                HtmlPage.Window.AttachEvent("onmousewheel", this.HandleMouseWheel);
                HtmlPage.Document.AttachEvent("onmousewheel", this.HandleMouseWheel);
            }
        }
        private void HandleMouseWheel(object sender, HtmlEventArgs args)
        {
            double delta = 0;
            ScriptObject eventObj = args.EventObject;
            if (eventObj.GetProperty("wheelDelta") != null)
            {
                delta = ((double)eventObj.GetProperty("wheelDelta")) / 120;

                if (HtmlPage.Window.GetProperty("opera") != null)
                    delta = -delta;
            }
            else if (eventObj.GetProperty("detail") != null)
            {
                delta = -((double)eventObj.GetProperty("detail")) / 3;
                if (HtmlPage.BrowserInformation.UserAgent.IndexOf("Macintosh") != -1)
                    delta = delta * 3;
            }
            if (delta != 0 && this.Moved != null)
            {
                MouseWheelEventArgs wheelArgs = new MouseWheelEventArgs(delta);
                this.Moved(this, wheelArgs);
                if (wheelArgs.Handled)
                    args.PreventDefault();
            }
        }
    }
}

Page.xaml.cs 파일의 Page() 함수에 위에서 작성한 마우스 휠 기능을 추가하도록 하겠습니다.

public Page()
{
    InitializeComponent();
    new MouseWheelHelper(this).Moved += delegate(object sender, MouseWheelEventArgs e)
    {
        e.Handled = true;
        if (e.Delta > 0)
            ZoomFactor = 1.2;
        else
            ZoomFactor = .80;
        Zoom(ZoomFactor, this.lastMousePos);
    };

}

휴!!~~ 모든 로직을 추가 했습니다. 이젠 다시 빌드 후 브라우저로 보시기 바랍니다.

사용자 삽입 이미지
 
오!!~~ 확대가 되었습니다.. 성공입니다.. 실패 하신분은 천천히 로직을 다시 살펴 보시기 바랍니다.

마우스 왼쪽을 클릭하면 확대, Shift 를 누르고 클릭하면 축소입니다.
그리고 휠도 위/아래 이동해 보세요!! 확대 / 축소가 됩니다.
또, 마우스 클릭 후 이동하면 중심점이 바뀌게 됩니다!!~~

프로젝트 예제 소스 :


이것으로 강좌를 마치도록 하겠습니다. 지금까지 정말 수고하셨습니다!!~~ 짝짝짝!!

작성자 : 상현넘™ [http://www.shblitz.net]
Posted by 상현넘™

댓글을 달아 주세요

  1. 슈퍼낙훈  댓글주소 수정/삭제 댓글쓰기 2008/03/11 17:20

    안녕하세요!

    정말 좋은 강좌와 소스 감사합니다~

    시간 날때 꼭 공부해 볼게요!

  2. 스페샬존  댓글주소 수정/삭제 댓글쓰기 2008/03/11 23:29

    낼름 구경 하고 갑니다~

    저도 컴퓨터 밀어버리면 그때 도전 해보도록 하겠습니다!!

  3. 요원  댓글주소 수정/삭제 댓글쓰기 2008/03/12 01:13

    ㅎㅎ 좋은글 감사해요~
    찾고있었는데.. 보고 바로 해봤어요 -_-b

    근데, 캠프에서 공도님이 3줄만에 했다는건 멀까요?;;;;

  4. 공도  댓글주소 수정/삭제 댓글쓰기 2008/03/20 10:03

    ^^ 약간의 트릭이랄까요...
    물론 내부로는 저런 로직을 넣었지만 한번 만들면 변경할 일이 없죠.
    즉, 유저 컨트롤을 만들어서 실제로 사용할 때에는 3줄만 있으면 돼요^^
    늦었지만, 강좌 잘 봤습니다. :D

    • 상현넘™  댓글주소 수정/삭제 2008/03/21 00:16

      하하^^ 유저 컨트롤로 만들어 놓으면
      간단하게 사용할 수 있죠^^..
      저도 자주 쓸수 있는것이나 유용한것들은
      편하게 빼서 재사용을 많이 이용합니다^^

  5. 도리도리  댓글주소 수정/삭제 댓글쓰기 2008/05/06 15:44

    좋은 강좌 너무 감사합니다..^_^

  6. 폴라리스  댓글주소 수정/삭제 댓글쓰기 2008/05/19 16:20

    강좌 잘 봤습니다.
    머가 잘못되었는지 잘 안되서 수정해가면서..
    여튼 잘 보고 갑니다.

  7. 왕초초초보  댓글주소 수정/삭제 댓글쓰기 2008/09/07 17:35

    전 안되는데.. 저기 Export 시키는 화면이 저랑 다른데요 어떤식으로 해야하는지
    너무 막막 합니다.. info.bin 파일이 안생겨요.. ㅠ
    버전이 다른가요 8월 3일 버전이네요

    • 상현넘™  댓글주소 수정/삭제 2008/09/08 09:44

      최근 버전에서는 어떻게 변경이 되었는지는 잘 모르겠네요!!
      바쁘다보니 새 버전을 테스트를 못해봤습니다..

  8. 쇼너짱  댓글주소 수정/삭제 댓글쓰기 2008/11/26 13:44

    멋진 강좌 잘봤습니다^^
    위에 왕초초초보님 말씀처럼 컴포저 새버전은 많이 업그레이드가 되었더군요,
    제가 방금해보니깐 최근 버전에서는 자동으로 실버라이트 프로젝트파일까지 생성이되어서,
    훨씬 편해진듯해요...위의 강좌에서 하나하나 코딩했던것을 아예 기본 아웃풋 파일에 생성이 되어 있더군요^^

Deep Zoom 기능은 실버라이트 2를 지원하는 기능입니다.
이 기능을 사용하여 아주 환상적인 UI를 간단히 만들수 있습니다.

참고 사이트
- 공도소프트 : http://gongdo.tistory.com/251
- UX Factory : http://uxfactory.com/270

Tools 다운로드
- Visual Studio 2008
- Silverlight 2 Beta1 Runtime
- Silverlight Tools Beta 1 for Visual Studio 2008
- Deep Zoom Composer Preview


Deep Zoom 강좌 : 1. Deep Zoom Composer를 이용하여 Image gallery 만들기

1. 프로젝트 생성
- Deep Zoom Composer를 다운로드하여 설치 후 실행을 합니다.

사용자 삽입 이미지

위 이미지와 같이 [Project], [Help] 탭이 존재합니다. [Project] 탭에서 [New Project...]를 선택합니다.

사용자 삽입 이미지

Deep Zoom Project의 이름과 경로를 지정하고 [OK] 버튼을 눌러 프로젝트를 생성합니다.


2. 이미지 불러오기
- 새 프로젝트가 생성되면 프로그램의 레이아웃은 [Import], [Compose], [Export]로 나누어져 있습니다.

사용자 삽입 이미지

[Import] 탭의 화면구성은 오른쪽으로 이미지 목록이 있으며, 왼쪽으로는 미리보기 창이 있습니다.

[Add Image...] 버튼을 눌러 갤러리로 사용할 이미지를 선택합니다. 사용이 가능한 이미지 확장자는 png, jpg, bmp, tiff 입니다. gif는 아쉽게도 지원지 되지 않는거 같습니다.
(이미지는 기왕 보기 좋게 국내 여자 연예인들로.. ㅎㅎ^^)


3. 이미지 구성하기
- 화면 상단의 [Compose] 탭을 눌러 이미지 구성화면으로 이동을 합니다.

사용자 삽입 이미지

왼쪽 이미지 목록에서 마우스로 이미지를 끌어와 오른쪽 작업영역에 포함을 시킵니다. 그런후 선택된 이미지의 사이즈 조절 및 위치를 조절하여 원하는 이미지 구성을 하면 됩니다.


4. 이미지 갤러리 내보내기
- 화면 상단의 [Export] 탭을 눌러 이미지 갤러리 내보내기 화면으로 이동을 합니다.

사용자 삽입 이미지

왼쪽에는 이전에 구성한대로 미리보기가 나옵니다. 오른쪽에 보면 이미지 갤러리의 이름과 저장할 경로를 설정할 수 있습니다.

원하는 이미지 갤러리 이름과 저장할 위치를 선택한 후 [Export] 버튼을 누르면 됩니다.


5. 생성된 이미지 갤러리 확인

사용자 삽입 이미지

본인이 지정한 경로로 이동해보면 위 이미지와 같이 파일 및 폴더가 구성이 되어 있을것입니다.

이것으로 Deep Zoom Composer를 이용하여 Image gallery를 만들어 보았습니다.

다음은 비주얼스튜디오 2008을 이용하여 실버라이트 프로젝트를 생성하려 Deep Zoom 기능의 프로젝트를 만들어 보도록 하겠습니다. (바로가기)

작성자 : 상현넘™ [http://www.shblitz.net]







Posted by 상현넘™

댓글을 달아 주세요

  1. dykin  댓글주소 수정/삭제 댓글쓰기 2008/03/13 19:51

    좋은 강좌 감사합니다. :)

  2. HOONS  댓글주소 수정/삭제 댓글쓰기 2008/03/14 00:39

    잘보고 갑니다 ^_^

  3. mintday  댓글주소 수정/삭제 댓글쓰기 2008/09/16 22:22

    초보인 저에게 많은 도움이 되었습니다. 감사합니다~

URL Access Policy와 관련하여, 크로스 도메인 문제를 해결하기 위해 해당 서버에 접근 정책을 설정하는 방법에 대해 설명한 글이에요. 자세한 것은 원문을 보시고 여기에서는 HOW TO 부분만 가져왔습니다.

원문 : How to: Make a Service Available Across Domain Boundaries
번역 : http://gongdosoft.com/255

실버라이트는 크로스 도메인 접근에 두 가지 매커니즘을 지원합니다.

  • clientaccesspolicy.xml
    ; 크로스 도메인 접근cross-domain-access하기 위한 서비스를 설정하기 위해 도메인의 루트에 놓는 파일.
  • crossdomain.xml
    ; 서비스가 호스트된 도메인의 루트에 놓는 파일. 파일은 반드시 공개할 도메인을 기록해야 합니다. 플래시에서 사용했던 방식으로 실버라이트도 이 스키마의 서브셋을 지원합니다.

clientaccesspolicy.xml 파일을 사용하여 크로스 도메인 접근하기

1. 실버라이트 클라이언트가 접근 가능한 서비스를 만듭니다. 자세한 정보는 실버라이트 클라이언트를 위한 서비스 만들기를 보세요.

2. 서비스에 접근을 허용하기 위해 clientaccesspolicy.xml 파일을 생성합니다. 다음 설정은 다른 어떤 도메인에서도 현재 도메인에 있는 모든 리소스를 접근하도록 허용합니다.

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from>
                <domain uri="*"/>
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

3. clientaccesspolicy.xml 파일을 서비스가 호스트되고 있는 도메인의 루트에 저장합니다. 예를 들어, http://fabrikam.com 에서 호스트되고 있는 서비스라면 반드시 http://fabrikam.com/clientaccesspolicy.xml에 위치해야 합니다.

4. 반면, http://contoso.com과 같은 딱 하나의 도메인에서만 접근을 허용하길 원한다면 clientaccesspolicy.xml은 다음과 같은 설정을 포함해야 합니다.

<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from>
                <domain uri="http://contoso.com" />
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

5. 다른 도메인에서 서비스를 호출했을 때 접근이 가능한지 테스트합니다.


crossdomain.xml 파일을 사용하여 크로스 도메인 접근하기

1. 실버라이트 클라이언트에서 접근이 가능한 서비스를 만듭니다.

2. 다음 설정을 포함하는 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="*" />
</cross-domain-policy>

3. 서비스가 호스트된 도메인의 루트에 crossdomain.xml 파일을 서비스가 호스트되고 있는 도메인의 루트에 저장합니다. 예를 들어, http://fabrikam.com 에서 호스트되고 있는 서비스라면 반드시 http://fabrikam.com/crossdomain.xml에 위치해야 합니다.

4. 다른 도메인에서 서비스를 호출했을 때 접근이 가능한지 테스트합니다.

Posted by 상현넘™

댓글을 달아 주세요