Tech/Silverlight2009. 10. 9. 15:10

지난 번에 만들었던 Behavior를 사용해 보겠습니다.
이름은 ChangeRotation이라는 Behavior이며 TargetTriggerAction입니다.

ChangeRotation Behavior의 목적 ?
- Rotation 변경을 특정한 조건이 발생할 때마다 일으키고 싶을 때에 사용합니다.
- 예를 들어, Target의 RotationY를 버튼이 클릭 될 때마다 90도씩 회전하고 싶을 때 이 Behavior를 사용합니다.

이 Behavior를 사용하는데에는 몇 가지 제약 있습니다.

1. Target의 type은 Grid여야 합니다.
2. Rotation 변경이 되는 Target은 두 종류 입니다.
- Grid 본인
- Grid의 Children

그럼 이제 실제로 Blend 3에서 Behavior를 어떻게 사용할 수 있는지 보도록 하겠습니다.
이미 만들어놓은 SketchFlow Project를 열어 트리 구조를 보면, 아래 사진과 같이 보입니다.
녹색 박스 안의 ImageSlideViewerContainer는 Grid이며 안에는 4장의 이미지가 있습니다.
첫번째 이미지의 RotationY는 0
두번째 이미지의 RotationY는 -90
세번째 이미지의 RotationY는 90
네번째 이미지의 RotationY는 180
이런 식으로 설정되어 있으며 4장의 이미지들의 CenterRotationZ를 Image의 Width의 절반으로 값을 주었습니다.

원하는 움직임은 btnLeft (왼쪽 방향 화살표)를 눌렀을 때, 이 이미지들이 90도씩 RotationY가 변하여 회전하길 바라는 것입니다.




Assets의 Behaviors로 들어가면 ChangeRotation이 있습니다. 이것을 마우스로 Drag하여 btnLeft에 Drop을 하면 됩니다.



Drop을 하면 오른쪽 Properties창에 Behavior를 설정할 수 있도록 아래 사진과 같은 내용들이 나타납니다.

  • Trigger
    • TriggerType : Trigger를 설정할 수 있습니다.
    • SourceName : Event를 발생시키는  Object입니다.
    • EventName : Event를 설정할 수 있습니다.
  • Common Properties
    • TargetName : Action을 일으키는 Object입니다.


사용자가 btnLeft를 마우스 외쪽 버튼으로 클릭하게 되면 ImageSlideViewerContainer가 ChangeRotation을 일으킵니다.

그 하위에 Rotation, Rotation Properties, Target은 Behavior 소스 코드 상에서 직접 Catalog를 만든 것입니다.

ImageSlideViewerContainer의 Children인 4장의 이미지를 회전시키고 싶은 것이기 때문에, Target Catalog에서 isChildren을 체크합니다. 그 후에, RotationY를 체크하고 DeltaY에 90을 입력하게 되면 모든 설정을 마친 것입니다. ^_^



이제 직접 프로젝트를 빌드하고 수행해보면 이미지들이 90씩 왼쪽으로 잘 돌아가게 됩니다 ^ㅁ^)/

'Tech > Silverlight' 카테고리의 다른 글

[Blend 3 Element Binding]  (0) 2009.10.12
[SketchFlow를 만들자 2]  (0) 2009.10.09
[Sketch Flow를 만들자]  (0) 2009.10.06
[Behavior 만들기]  (0) 2009.10.01
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 10. 6. 18:18




SketchFlow Project를 만들어봅니다.
1. Expression Blend3 를 실행
2. New Project
3. Silverlight 3 SketchFlow Application 프로젝트 생성


SketchFlow 화면 구성
빨강 : 프로젝트 파일부터 Resource 파일들의 목록 및 Assets, States를 설정할 수 있는 부분
주황 : 스크린을 구성하고 있는 UIElement들의 Tree 구조
노랑 : 미리보기 화면
초록 : 각 Screen들의 상관관계와 흐름을 한 눈에 볼 수 있는 Map
파랑 : Element들의 속성 및 Resource와 Data들의 정보를 조작

SketchFlow Map을 제외하곤 Expression Blend와 거의 동일한 화면 구성이다.


Screen? 실제로 보여지는 화면
1. UserControl Class를 생성하듯이 SketchFlow에서만 쓰이는 Screen들을 마우스로 끌어내는 것만으로 쉽게 생성할 수 있다.
2. Screen의 이름을 바꿀 수 있다.
3. 목적에 따라 한 눈에 알아 볼 수 있도록 색을 바꿀 수 있다.
4. 화살표 방향으로 각 Screen들끼리의 소통과 흐름을 파악할 수 있다.


Component Screen? 반복적인 요소

1. 어떠한 부분이 필요에 의해 여러 Screen에 중복적으로 쓰일 때 Component Screen을 이용한다.
2. Component Screen을 연결한 Screen에는 Component Screen이 삽입된다.

그리고 나는,
...ImageSlidePlayer를 SketchFlow Project로 만들며 삽질을 하였다...

SketchFlow Project를 만들며 알게 된 점
1. 평범하고 단편적인 애니메이션은 Behavior를 이용하면 된다.
2. 평범하지 않은 애니메이션은 스스로 Behavior를 만들거나 코딩이 필요하다.
3. Insert시킨 Screen의 속성을 건드릴 수가 없다. (Element Binding을 시키려 할 때나 애니메이션을 적용시킬 때 이 문제 때문에 한참을 헤매다 포기했다.)
4. 버튼이나 기타 Element를 활용한 Screen이동이 활발한 프로그램일 수록 SketchFlow 효과도 좋다. (본인이 적용한 프로그램은 한 화면에서 움직이기 때문에, Screen이동이 거의 없어 밋밋하고 Component Screen을 쓰기도 힘들었다.)
5. Resources에 DataTemplate을 만들어서 ListBox에 DataBinding을 했을 때, ListBox의 Items.Count는 0이다. (몰랐다.) SelectedItem을 뽑아보려는 짓은 부질없었으며 Data접근도 복잡하다.

아직도 모르겠는 것 - State 사용법, SketchFlow Animation

아직 안 해 본 것 - 포토샵이나 일러스트레이터 프로젝트 파일이 없어 Import 시켜보지 않았다.

MS Word로 Export 시켜낸 결과물 (보고서)

삽질을 너무 많이 했는데, 결과물이 요것뿐이 안 나와서 좌절... OTL

'Tech > Silverlight' 카테고리의 다른 글

[SketchFlow를 만들자 2]  (0) 2009.10.09
[Blend에서 Behvaior 사용해보기]  (0) 2009.10.09
[Behavior 만들기]  (0) 2009.10.01
[MVVM/Command Pattern]  (0) 2009.10.01
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 10. 1. 17:40

본 목적은 Sketch Flow를 만들어보자 였던 것 같은데; Sketch Flow에 애니메이션 적용이 필요하게 되어 뒤적뒤적하다보니 Behavior가 필요하게 되고~ 그러다보니 또 Behavior를 새로 만들어야 하는 필요성이 생기게 되어 "Behavior를 만들자"가 되었다.


... OTL (뭐 이래)

간단하게 Behavior는 세 분류로 나뉘는데, Behavior는 그냥 밑도 끝도 없이 Action을 한다. TriggerAction은 Trigger(입력되는 Event나 상황 조건)에 따라 Action을 한다. TargetedTriggerAction은 Trigger에 따라 TargetedObject가 Action을 하는 것을 의미한다.

Behavior를 만드는 방법을 굉장히 친절하게 설명해 놓은 글이 있으니 중복으로 쓰지 않고 링크를 남겨두도록 하겠다.

http://openlightgroup.net/Blog/tabid/58/EntryId/17/Creating-a-simple-Silverlight-3-Behavior.aspx


중요한 부분은 새로이 정의한 Behavior에 System.Windows.Interactivity.dll을 참조시키는 것이고 그 후에 SilverlightApp 프로젝트 쪽에 정의한 Behavior를 참조추가 하는 것이다. 이렇게 한 후에, 빌드하면 Blend를 띄웠을 때, Behavior 리스트에 새로이 정의한 Behavior가 잘~ 보일 것이다.


지금 나에게 필요한 Behavior는 TargetTriggerAction Behavior이며, 해당 Target의 Chidren들의 Rotation이 바뀌도록 해 주는 것이다.
TargetTriggerAction Behavior Class는 다음과 같이 정의한다.


1. TargetedTriggerAction을 상속받아 Invoke()를 오버라이드한다.

public class ChangeChildrenRotation : TargetedTriggerAction<Grid>
{
        protected override void Invoke(object parameter)
        {
            //수행 동작 내용
       
}

2. 동작을 수행하는데 필요한 데이터 정보를 받을 DependencyProperty를 정의한다.
ex) X축을 중심으로 회전할 각도를 받을 DependencyProperty를 정의한다.

public static readonly
DependencyProperty DeltaXProperty = DependencyProperty.Register(
"DeltaX", typeof(double), typeof(ChangeChildrenRotation), new PropertyMetadata(Double.Parse("0")));

3. Blend에서 DependencyProperty를 입력받을 수 있도록 해주고, Category로 분류시킨다.

[Category("Rotation")]
public bool RotateX
{
       get { return (bool)GetValue(RotateXProperty); 
       set { SetValue(RotateXProperty, value); }
}

끗.

참 잘했어요 ' ㅅ')/ 뿌우

'Tech > Silverlight' 카테고리의 다른 글

[Blend에서 Behvaior 사용해보기]  (0) 2009.10.09
[Sketch Flow를 만들자]  (0) 2009.10.06
[MVVM/Command Pattern]  (0) 2009.10.01
Deep Zoom Composer 에서 개별 이미지 요소 정보 얻기  (0) 2009.08.03
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 10. 1. 16:50

  최근 ViewModel관련 Pattern에 대한 관심이 급증하고 있는데, 그 이유는 Silverlight와 WPF에서 제공하고 있는 데이터 바인딩의 장점을 적극 활용할 수 있기 때문이다.
  MVVM Pattern과 Command Pattern에 대해 Silverlight/WPF 개발을 하는데 내가 이해한 대로만 짧은 개념을 여기에 적는다.
 

  MVVM(Model-View-ViewModel) Pattern은 사용자 인터페이스에 최적화된 맞춤형 Model을 만들 수 있다.

 

이름

기능 설명

Model/
DataModel

Metadata의 정보들을 갖고 있다.

View

사용자 인터페이스, UI 요소들로 이루어져 있으며 오로지 UI 요소에게만 관심이 있으며, 그 이하 동작 과정에 관심이 없다.

ViewModel

View에 보여지거나 필요한 정보들을 갖고 있으며, View에게서 request가 들어오면 해당 동작을 수행한다.

 
  Model/DataModel은 Parser와 같은 역할을 하여 metadata들을 갖고 있고 metadata는 필요(사용자의 Request)에 따라 service될 것이다.
사용자의 Request가 View를 통해 접수되면, ViewModel이 Request에 적합한 동작을 수행하고, 그 동작에 필요한 데이터 정보는 Model/DataModel로부터 얻는다.


 
자, 그렇다면 Command Pattern은 왜 필요할까? Command Pattern은
ViewModelView Request를 받아 동작을 수행하는 과정에적용시킨다. Command Pattern은 각종 Request들에 반응하는 Action들을 개별로 캡슐화시킬 수 있기 때문에, 재활용성이 용이하며 View와 ViewModel을 분리시키는데 한 몫을 한다.



  자세한 설명은 밑에 Nikhilk과, 길버트라는 분들이 자세히 설명과 적용 사례까지 적어 놓았으니 참조하면 좋겠다.


참조 링크

http://www.nikhilk.net/Silverlight-ViewModel-Pattern.aspx

http://error1001.com/36

'Tech > Silverlight' 카테고리의 다른 글

[Sketch Flow를 만들자]  (0) 2009.10.06
[Behavior 만들기]  (0) 2009.10.01
Deep Zoom Composer 에서 개별 이미지 요소 정보 얻기  (0) 2009.08.03
Silverlight 3 _ 3D  (0) 2009.06.18
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 8. 3. 13:06
Deep Zoom 강좌 by ONESTONE


1. 개별 이미지의 위치 정보 얻기


1. 개별 이미지의 위치 정보 얻기

- Deep Zoom Composer를 통해 내보내기 한 결과물에서 Metadata.xml 파일을 보면 다음과 같은 정보를 얻을 수 있다.


AspectRatio : 전체 이미지의 Width / Height 비율
x, y : 이미지의 위치, 1을 기준으로 비율에 맞추어 변경한 값
width, height : 이미지의 크기, 1을 기준으로 비율에 맞추어 변경한 값

하지만 MultiScaleImage 컨트롤은 Metadata.xml 파일을 사용하는 것이 아니라, 추가적으로 내보내기 되는 dzc_output.xml 파일을 사용한다.

- dzc_output.xml 파일에서는 다음과 같은 정보를 얻을 수 있다.

Size : 원본 이미지의 Width, Height
Viewport.Width : 원본 이미지를 얼마만큼 확대/축소 하였는지 나타나는 비율
Viewport.X, Y : Viewport.Width의 비율에 따라서 이미지의 X, Y 위치, 1을 기준으로 비율에 맞추어 변경한 값

- 실제 개별 이미지의 영역 정보를 얻기 위해서는 MultiScaleImage 컨트롤로 부터 얻을 수 있는 MultiScaleSubImage들의 Collection을 이용하면 된다. 이것은 MultiScaleImage의 SubImages를 통해서 얻을 수 있다. 얻은 Collection은 MultiScaleImage의 Collection이고 각각의 MultiScaleImage에서 위에서 얻을 수 있는 Viewport Width, X, Y 정보를 얻을 수 있게 된다.

- SubImage의 Viewport 정보를 이용해서 SubImage의 X, Y, Width, Height는 다음과 같이 계산할 수 있다.

- 위 식을 이용하여 특정 Point가 속해 있는 SubImage를 얻는 코드는 다음과 같다.

<MultiScaleImage x:Name="msi" ... />

Point pt = msi.ElementToLogicalPoint(구하기 원하는 Point)
foreach (MultiScaleSubImage subImage in msi.SubImages)
{
if (pt.X >= -subImage.ViewportOrigin.X / subImage.ViewportWidth &&
    pt.X <= -subImage.ViewportOrigin.X / subImage.ViewportWidth + 1 / subImage.ViewportWidth &&
    pt.Y >= -subImage.ViewportOrigin.Y / subImage.ViewportWidth &&
    pt.Y <= -subImage.ViewportOrigin.Y / subImage.ViewportWidth + 1 / subImage.ViewportWidth / subImage.AspectRatio)
{
// 찾았다!!!
}
}



'Tech > Silverlight' 카테고리의 다른 글

[Behavior 만들기]  (0) 2009.10.01
[MVVM/Command Pattern]  (0) 2009.10.01
Silverlight 3 _ 3D  (0) 2009.06.18
ImageButton 만들기  (0) 2009.06.11
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 6. 18. 19:05
Silverligh 3의 UI Element에 Projection 프라퍼티가 추가되었다. 
이를 이용하면 간단한 3D 효과를 구현할 수 있다.

Image와 Button을 각각 Y축으로 30도 Z축으로 35도 회전하는 것을 다음과 같은 코드로 구현할 수 있다.

<Image x:Name="myImage" Source="[0253].jpg">
<Image.Projection>
<PlaneProjection RotationY="30"/>
</Image.Projection>
</Image>

<Button Content="Button" Click="Button_Click">
<Button.Projection>
<PlaneProjection RotationZ="35" />
</Button.Projection>
</Button>


Projection에서 제공하는 것은 회전 x,y,z 축 회전 외에도 다음과 같은 것들이 있다.
- 회전 중심점 변경 (CenterOf...)
- 회전 축 고정 평행 이동 (GlobalOffset...)
- 회전 축 변경 평형 이동 (LocalOffset...)

'Tech > Silverlight' 카테고리의 다른 글

[MVVM/Command Pattern]  (0) 2009.10.01
Deep Zoom Composer 에서 개별 이미지 요소 정보 얻기  (0) 2009.08.03
ImageButton 만들기  (0) 2009.06.11
Silverlight2 Unit Test  (0) 2009.05.19
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 6. 11. 16:37
참고 자료 _ [강좌] ImageButton 만들기, Dependency Property의 이해

1. Blend를 통한 Image 버튼 만들기
2. 동적으로 Image 변경이 가능한 ImageButton 클래스 만들기
3. ImageButton 클래스를 사용하기


1. Blend를 통한 image 버튼 만들기

- 참고 자료에 있는 강좌를 보면 Blend를 사용해 손쉽게 Image 버튼을 생성할 수 있다. 생성한 코드를 살펴보면 다음과 같다.

Page.xaml
<UserControl.Resources>
<ControlTemplate x:Key="ImageButtonTemplate" TargetType="Button">
<Grid>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="FocusStates">
<vsm:VisualState x:Name="Unfocused"/>
<vsm:VisualState x:Name="Focused"/>
</vsm:VisualStateGroup>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="NormalButton" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="OverButton" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="Normal"/>
<vsm:VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="NormalButton" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="PressedButton" Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="Disabled"/>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Image x:Name="NormalButton" Source="Normal.png" Stretch="Fill" />
<Image x:Name="OverButton" Source="Over.png" Stretch="Fill" Visibility="Collapsed" />
<Image x:Name="PressedButton" Source="Pressed.png" Stretch="Fill" Visibility="Collapsed" />
</Grid>
</ControlTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White">
<Button Template="{StaticResource ImageButtonTemplate}" Width="300" Height="100" />
</Grid>

- 위 코드를 보면 버튼의 각각의 상태를 정의할때 StoryBoard를 사용하는 것을 알 수 있으며, 차후 버튼에 효과를 줄때 해당 StordyBoard를 사용하면 된다.


2. 동적으로 Image 변경이 가능한 ImageButton 클래스 만들기

- Button 클래스를 상속받은 클래스를 만든다. (ImageButton.cs)
- xaml 에서 Property를 설정하면 동적으로 변경될 수 있게 DependencyProperty를 추가한다.
(버튼 상태에 따른 이미지를 설정할 수 있는 Property를 각각 NormalImageSource, OverImageSource, PressedImageSource 라고 이름을 짓는다.)

NormalImageSource DenpendencyProperty를 추가한 ImageButton.cs의 소스는 다음과 같다.

ImageButton.cs
public class ImageButton : Button
{
#region NormalImageSource
public ImageSource NormalImageSource
{
get { return (ImageSource)GetValue(NormalImageSourceProperty); }
set { SetValue(NormalImageSourceProperty, value); }
}

public static readonly DependencyProperty NormalImageSourceProperty =
DependencyProperty.Register(
  "NormalImageSource",
  typeof(ImageSource),
  typeof(ImageButton),
  null);
#endregion NormalImageSource

...

}

- OverImageSource, PressedImageSource도 같은 형태로 추가하면 xaml에서 사용할 수 있는 ImageButton 클래스의 제작이 끝난다.


3. ImageButton 클래스를 사용하기

- Page.xaml에서 사용하고 있는 Button을 ImageButton으로 바꾸기 위해서는 우선 xmlns를 추가해야 한다.
xmlns:test="clr-namespace:SilverlightApplication1;assembly=SilverlightApplication1"

- 사용하고 있는 ControlTemplate을 수정한다.
<ControlTemplate x:Key="ImageButtonTemplate" TargetType="test:ImageButton">
...
<Image x:Name="NormalButton" Source="{TemplateBinding NormalImageSource}" Stretch="Fill" />
<Image x:Name="OverButton" Source="{TemplateBinding OverImageSource}" Stretch="Fill" Visibility="Collapsed" />
<Image x:Name="PressedButton" Source="{TemplateBinding PressedImageSource}" Stretch="Fill" Visibility="Collapsed" />

- Button을 ImageButton으로 변경하고 각각의 상태에 따른 이미지를 설정한다.
<test:ImageButton x:Name="TestBtn" Template="{StaticResource ImageButtonTemplate}" Width="300" Height="100" NormalImageSource="Normal.png" OverImageSource="Over.png" PressedImageSource="Pressed.png" />

- 위에 정의된 Button의 이미지를 코드 내부에서 바꾸려면 다음과 같이 하면 된다.
TestBtn.NormalImageSource = new BitmapImage(new Uri("Normal.png", UriKind.Relative));

'Tech > Silverlight' 카테고리의 다른 글

Deep Zoom Composer 에서 개별 이미지 요소 정보 얻기  (0) 2009.08.03
Silverlight 3 _ 3D  (0) 2009.06.18
Silverlight2 Unit Test  (0) 2009.05.19
Rhino Mocks in Silverlight  (2) 2009.05.15
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 5. 19. 15:15

참고 자료 _ Unit Testing with Silverlight 2
원문 _ Silverlight2 Unit Test


1. Unit Test 환경 만들기
2. API Unit Test
3. UI Unit Test


1. Unit Test 환경 만들기

Silverlight에서 UnitTest 환경을 구축하기 위해서는 우선 UnitTest Framework을 준비해야 한다.
Framework는 MSDN에서 다운로드 받을 수 있다Microsoft Silverlight Unit Test Framework
(UnitTest를 위한 Template도 같이 받아두면 편리하다.)


다운로드 받은 Framework 파일은 아래 경로에 복사한다.
(Microsoft.Silverlight.Testing.dll, Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll)

%programfiles%\Microsoft SDKs\Silverlight\v2.0\Libraries\Client

다운로드 받은 Template 파일은 유저 템플릿으로 등록한다.
Template 파일의 압축을 풀어보면 Project Template과 Class Template으로 나뉘는데 각각을 아래 경로에 복사한다. (압축 파일 자체를 복사하면 된다.)

Project Template _ %userprofile%\Documents\Visual Studio 2008\Templates\ProjectTemplates
Class Template _ %userprofile%\Documents\Visual Studio 2008\Templates\ItemTemplates

<주의사항>
현재 최신 버전의 Framework에 포함된 dll 파일의 버전이 Template에 명시된 버전과 다른 문제가 있다.
정상적으로 사용하기 위해서는 Template의 내용을 수정해야 하는데, Template 파일의 압축을 풀고 각각의 Template 별로 아래의 내용을 수정하자.

2009.3.10 기준으로 
Microsoft.Silverlight.Testing.dll의 버전은 2.0.21103.1925, Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll의 버전은 2.0.21024.1838 이다.

Project Template _ SilverlightTestProject.csproj 파일을 열고 각각의 Reference 버전을 수정한다.
Class Template _ MyTemplate.vstemplate 파일을 열고 각각의 Assembly 버전을 수정한다.

위 작업이 다 끝난 이후에 Visual Studio 2008을 실행시켜보면
새 프로젝트 생성시 Visual C# 카테고리를 선택하면 내 템플릿에 Silverlight Test Project가 생성되어 있고
프로젝트에 Class 추가를 실행하면 Visual C# 카테고리의 내 템플릿에 Silverlight Test Class가 등록되어 있는 것을 확인할 수 있다.



2. API Unit Test

UnitTest를 위해 UnitTestApp 라는 이름을 가진 Silverlight Application을 생성한다.
UnitTestApp에 MyTestClass 클래스를 추가하고 아래와 같은 함수를 구현한다.

public int add(int value1, int value2)
{
    return value1 + value2;
}

이제 add 함수를 테스트 하기 위해서 실제로 UnitTest를 수행할 프로젝트를 생성한다.
UnitTestApp 솔루션에 Test라는 새 프로젝트를 추가한다. (템플릿은 Silverlight Test Project를 선택한다)

생성된 Test.cs 파일을 살펴보면 Test Class 앞에는 [TestClass]가 선언 되어 있고 테스트 함수 앞에는 [TestMethod]가 선언 되어있는 것을 알 수 있다.

Test 프로젝트를 실행하면 [TestClass]로 선언된 Class 안에 포함된 [TestMethod]를 수행하여 실제 UnitTest를 수행하게 된다.

아래와 같은 Test 함수를 추가하여 add 함수를 테스트 한다.

[TestMethod]
public void AddTest()
{
MyTestClass myTestClass = new MyTestClass();
Assert.AreEqual(3, myTestClass.add(1, 2));
}

이때 MyTestClass는 Test 프로젝트에 포함되어 있지 않기 때문에 Test 프로젝트 참조에 UnitTestApp를 추가하고 Test.cs에 using UnitTestApp; 를 추가해야 정상적으로 빌드 된다.


빌드가 완료되어 Test 프로젝트를 실행하면 다음과 같은 화면을 통해 테스트가 정상적으로 수행 되었음을 알 수 있다.


테스트 오류 상황을 확인하기 위해 Assert.AreEqual(3, myTestClass.add(1, 2)); 부분을 Assert.AreEqual(5, myTestClass.add(1, 2)); 로 수정해본다. 수정 후 실행 결과는 다음과 같다.


AddTest 함수에서 오류가 발생한 것을 알 수 있으며 기대값과 실제 값을 확인할 수 있다. 이때 AddTest를 클릭하면 더 자세한 정보를 확인할 수 있다.

다음은 컬렉션의 값이 추가 되었을때 정상적으로 이벤트가 발생하는지 테스트하는 항목을 만들어본다.
MyTestClass에 다음과 같은 멤버 변수와 함수를 추가한다.

internal ObservableCollection<int> collection = new ObservableCollection<int>();

public void addCollection(int value)
{
collection.Add(value);
}

그리고 addCollection 함수를 테스트 하기 위해 Test 프로젝트의 Test 클래스에 다음과 같은 Test 함수를 추가한다.
테스트 내용은 addCollection을 한번 호출하였을 때 Collection의 값이 변동이 되었다는 이벤트를 받아 이벤트가 정상적으로 발생 되었는지, Collection에 포함된 자료의 갯수가 한개인지 확인하게 된다.

[TestMethod]
public void CollectionTest()
{
MyTestClass myTestClass = new MyTestClass();

bool changedValue = false;

myTestClass.collection.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e)
{
changedValue = true;
Assert.AreEqual(NotifyCollectionChangedAction.Add, e.Action);
Assert.AreEqual(1, e.NewItems.Count);
};

myTestClass.addCollection(5);
Assert.IsTrue(changedValue);

}

이 코드를 추가하고 다시 빌드를 실행하면 internal로 선언된 collection 때문에 오류가 발생한다. 이는 Test 프로젝트와 UnitTestApp가 서로 다른 namespace이기 때문인데, 테스트를 위해서 collection을 public으로 바꾸는 방법도 있지만, UnitTestApp에 있는 AssemblyInfo.cs 파일을 수정하여 UnitTestApp에 있는 internal 을 Test 어셈블리에서도 access 가능하게 수정하도록 한다.

internal로 선언된 변수를 다른 어셈블리에 공개하려면 AssemblyInfo.cs 파일에 다음을 추가하면 된다. (AssemblyInfo.cs 파일은 Properties 폴더에 있음)

[assembly: InternalsVisibleTo("Test")]

빌드가 정상적으로 되고 Test 프로젝트를 실행하면 정상적으로 테스트를 성공하는 것을 확인할 수 있다.


3. UI Unit Test

UI를 테스트 하기 위해서는 테스트 대상이 될 어플리케이션을 임시로 생성하고 사용자 입력을 자동으로 만들어서 테스트를 수행하여야 한다.

UnitTestApp의 Page.xaml에 다음과 같은 코드를 생성하자.

<StackPanel>
<TextBox x:Name="InputText" />
<Button Content="Click" Click="Button_Click" />
<TextBlock x:Name="OutputText" />
</StackPanel>

Button을 클릭하면 InputText에 있는 내용을 OutputText로 뿌려주도록 한다.

private void Button_Click(object sender, RoutedEventArgs e)
{
OutputText.Text = InputText.Text;
}

구현한 위의 동작을 테스트 하기 위해서 Test 프로젝트에 새로운 테스트 클래스인 UITest를 생성하자. (Silverlight Test Class 템플릿을 사용)

UITest를 이용해서 어플리케이션의 UI를 테스트 하기 위해서는 [TestMethod]가 수행될 때마다 어플리케이션을 임시로 생성해야 하는데, 이것은 [TestInitialize]를 이용하여 할 수 있다. 함수 앞에 [TestInitialize]를 선언하면 그 함수는 [TestMethod]가 수행될때마다 [TestMethod]이전에 실행되어서 원하는 값들을 초기화 시킬 수 있다.
(초기화 뿐만 아니라 [TestCleanup]을 이용하여 [TestMethod] 수행 종료 이후에 테스트 후의 환경을 정리할 수도 있다.)

[TestInitialize] -> [TestMethod] -> [TestCleanup] 순서로 수행 됨

실제로 테스트를 수행하기 위해서는 [TestInitialize] 함수에서 UnitTestApp의 페이지를 생성하고, 그 페이지를 SilverlightTest 클래스안에 있는 TestPanel의 Children에 추가시켜야 한다. 이것을 위해서 실제 테스트 클래스를 SilverlightTest를 상속받는 클래스로 생성한다.

using UnitTestApp;
using Microsoft.Silverlight.Testing;

[TestClass]
public class UITest : SilverlightTest
{
private Page testPage;

[TestInitialize]
public void PreparePage()
{
testPage = new Page();
TestPanel.Children.Add(testPage);
}
}

준비가 끝났으면 실제 테스트를 수행하는 함수를 작성한다.

[TestMethod]
public void TextBoxTest()
{
testPage.InputText.Text = "TextBoxTest";
testPage.Button_Click(this, null);

Assert.AreEqual("TextBoxTest", testPage.OutputText.Text);
}

빌드를 해보면 오류가 발생한다. Page.xaml.cs 파일을 보면 Button_Click이 private으로 선언 되어 있는데 이것을 internal로 수정한다.
(internal로 수정해서 빌드가 가능한 이유는 AssemblyInfo.cs 파일에 Test 어셈블리를 internal 범위에 포함시켰기 때문이다. internal 범위에 포함시키지 않았다면 testPage의 InputText나 OutputText도 사용할 수 없다.)

빌드가 정상적으로 진행되어 실행해보면, 작성한 Page.xaml의 내용이 화면에 깜박거리면서 테스트가 진행되는 것을 볼 수 있으며 다음과 같은 결과를 확인할 수 있다. (실제로는 UI 화면이 깜박거리면서 사라진다.)




이 포스팅에 사용된 샘플 소스

저작자 표시

'Tech > Silverlight' 카테고리의 다른 글

Silverlight 3 _ 3D  (0) 2009.06.18
ImageButton 만들기  (0) 2009.06.11
Rhino Mocks in Silverlight  (2) 2009.05.15
DataGrid 사용법  (0) 2009.04.06
Posted by wafe
Tech/Silverlight2009. 5. 15. 18:41
Rhino Mocks 홈페이지

1. What is Rhino Mocks?
2. 설치
3. Silverlight Unit에서 사용하기
4. Example

1. What is Rhino Mocks?

A dynamic mock object framework for the .Net platform. It's purpose is to ease testing by allowing the developer to create mock implementations of custom objects and verify the interactions using unit testing.

Licensing: Rhino Mocks is Free Software which is released under the BSD license.




2. 설치


Rhino Mocks 3.5 - For Silverlight 

위의 파일을 받아서 압축을 풀어보면 다음과 같은 파일이 들어 있는 것을 확인할 수 있다.


테스트 프로젝트의 참조에 Rhino.Mocks 3.5 Silverlight.dll을 포함시키고 using Rhino.Mocks를 추가하면 된다.




3. Silverlight Unit에서 사용하기


Rhino Mocks를 사용하기 위해서는 다음을 지켜야 한다.

1. Mock Object로 만들 대상 Class의 함수가 상속 가능해야 한다. (virtual)

2. MockRepository에 Mock Object에 대한 선언이 끝나면 ReplayAll을 호출한다.

3. Test가 끝나면 VerifyAll을 호출해 정의한 대로 실행되었는지 확인한다.

 - VerifyAll을 호출하였을 때 정의한 대로 실행되지 않았다면 Test Fail이 발생한다.


Rhino Mocks로 클래스/인터페이스를 Mocking하기 위해서 다음과 같은 절차를 거친다.

1. MockRepository를 만든다.
ex. MockRepository mocks = new MockRepository();

2. 클래스인 경우에 PartialMock, 인터페이스인 경우에 StrickMock을 이용해 MockObject를 만든다.
ex. ContentsPlayerMain cpMain = mocks.PartialMock<ContentsPlayerMain>();

Mock Object에서 가상으로 사용할 함수를 선언한다.

return value가 있을 경우 _ Expect.Call(function)
return value가 void인 경우 _ Expect.Call(delegate{function;}) or ...; LastCall

-

Expect.Call의 Return 결과물에 새로운 Return Value나 함수 호출 횟수를 설정할 수 있다.

Expect.Call(function).Return(data); - function을 호출하면 data가 return 된다.

Expect.Call(function).Repeat.Once() - function이 한 번만 실행되는 것을 확인한다.

-

Mock Object에서 Expect.Call로 정의된 함수를 호출하게 되면 실제 Class의 해당 함수의 동작을 따르는 것이 아니라 정의한 함수의 동작을 따르게 된다.
ex. Expect.Call(cpMain.GetSynchronizeData(15)).Return(data); 
// GetSynchronizeData 함수에 15가 인자로 들어오면 data를 return 한다.

참고 자료) Rhino Mocks 3.3 Quick Reference.pdf




4. Example


- 다음과 같은 함수를 Mock Object를 통해서 테스트 해본다.

internal virtual void Synchronize(double time, bool isSeek)
{
SynchronizeData synchronizeData = GetSynchronizeData(time);
currentSlide = synchronizeData.slideIndex;
currentEvent = synchronizeData.eventIndex;
if (isSeek)
{
GotoAndStop(currentSlide, currentEvent);
}
else
{
GotoAndPlay(currentSlide, currentEvent);
}
}

위 함수에서 사용하는 클래스 멤버 함수인 GetSynchronizeData, GotoAndStop, GotoAndPlay를 Mock Object를 통해 구현하자.

1. TestCase에는 time이 15와 30이 들어온다고 가정하고, 각각의 time에  대한 Data를 미리 준비한다.
2. Mock Object를 이용해 GeySynchronizeData의 인자로 15와 30이 들어왔을 경우에 준비한 Data를 Return.
3. Mock Object를 이용해 GotoAndPlay에 1, 1이 인자로 들어오고, 한 번만 호출되는 것을 확인
4. Mock Object를 이용해 GotoAndStop에 2, 0이 인자로 들어오고, 한 번만 호출되는 것을 확인

[TestMethod]
public void TestMethod()
{
MockRepository mocks = new MockRepository();

ContentsPlayerMain cpMain = mocks.PartialMock<ContentsPlayerMain>();

SynchronizeData data1 = new SynchronizeData();
data1.slideIndex = 1;
data1.eventIndex = 1;
SynchronizeData data2 = new SynchronizeData();
data2.slideIndex = 2;
data2.eventIndex = 0;

Expect.Call(cpMain.GetSynchronizeData(15)).Return(data1);
Expect.Call(cpMain.GetSynchronizeData(30)).Return(data2);
Expect.Call(delegate { cpMain.GotoAndPlay(1, 1); }).Repeat.Once();
Expect.Call(delegate { cpMain.GotoAndStop(2, 0); }).Repeat.Once();

mocks.ReplayAll();

cpMain.Synchronize(15, false);
Assert.AreEqual(1, cpMain.CurrentSlide);
Assert.AreEqual(1, cpMain.CurrentEvent);
cpMain.Synchronize(30, true);
Assert.AreEqual(2, cpMain.CurrentSlide);
Assert.AreEqual(0, cpMain.CurrentEvent);

mocks.VerifyAll();
}


'Tech > Silverlight' 카테고리의 다른 글

ImageButton 만들기  (0) 2009.06.11
Silverlight2 Unit Test  (0) 2009.05.19
DataGrid 사용법  (0) 2009.04.06
LINQ (Language Integrated Query)  (0) 2009.04.06
Posted by 알 수 없는 사용자
Tech/Silverlight2009. 4. 6. 12:00
1. DataGrid 컨트롤은?
2. DataGrid 컨트롤에서 세부 데이타 표시하기



1. DataGrid 컨트롤은?

System.Windows.Controls 네임스페이스에 속해 있는 리스트 스타일의 컨트롤이다.

DataGrid는 UI가상화를 사용하고 있어서, 몇만 개의 데이터의 행을 지원할 있도록 보장해준다.

UI가상화란 사용자에게 보이는 모든 아이템들은 메모리 안에서 생성된다는 것을 의미한다


DataGrid 컨트롤의 실행 샘플.


2. DataGrid에서 컨트롤에서 세부 데이타 표시하기


XAML에서 DataGrid 컨트롤을 사용을 위한 NameSpace 정의.

<UserControl x:Class="DataGridSample.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    >
    <Grid x:Name="LayoutRoot" Background="White">       
        <data:DataGrid x:Name="myDataGrid" />
    </Grid>
</UserControl>


데이타 소스 설정.

myDataGrid.ItemsSource = GetEoticons();
private  List<Emotion> GetEmoticons()
{
       List<Emotion> emoticons = new List<Emotion>();
       emoticons.Add(new Emotion("철수",    "1.jpg"));
       emoticons.Add(new Emotion("영희",    "2.jpg"));
       emoticons.Add(new Emotion("바둑이", "3.jpg"));
       return emoticons;            
 }

public class Emotion
{       
        private BitmapImage icon = null;
        public Emotion(string name, string imageUrl)
        {
            Name = name;
            Icon = new BitmapImage(new Uri(imageUrl, UriKind.Relative));
        }
        public string Name
        {
            get;
            private set;
        }
        public BitmapImage Icon
        {
            get { return icon;  }
            set
            {
                icon = value;
            }
        }
}


세부 데이타 표시하기
- AutoGenerateColumns False로 설정하고, DataGrid.Columns를 사용하여 데이터를 표시할 칼럼 형식을 정의.

- DataGridTextColumn 클래스의 SortMemberPath로  정렬될 멤버 설정하여 아이템 정렬.
- DataGridTemplateColumn 클래스의 CellTemplate으로 사용자 정의(고유한 열 형식) 템프릿 생성.

<data:DataGrid x:Name="myDataGrid" AutoGenerateColumns="False" IsReadOnly="False">
      <data:DataGrid.Columns>
           <data:DataGridTextColumn Binding="{Binding Name, Mode=twoWay}" SortMemberPath="Name"/>
                <data:DataGridTemplateColumn>
                    <data:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Image Source="{Binding Icon}" Height="100"/>
                        </DataTemplate>
                    </data:DataGridTemplateColumn.CellTemplate>    
           </data:DataGridTemplateColumn>
     </data:DataGrid.Columns>
</data:DataGrid>


DataGrid 편집 하기.
- IsReadOnly를 False로 설정
- Binding Mode를 twoWay로 설정.
- 편집과 관련된 Event. 

BiginningEdit 
- DataGridBeginningEditEventArgs파라미터 안에 Cancel속성을 True 변경하면 편집을 막을 있다.
PrepareCellForEdit 
-
DataGridTemplateColumn 내부의 콘텐트가 편집 모드가 들어갈 발생.
- BeginningEdit 이벤트에서 생성한 변화들을 다시 한번 변경할 있는 기회를 준다.

 

 


 

'Tech > Silverlight' 카테고리의 다른 글

Silverlight2 Unit Test  (0) 2009.05.19
Rhino Mocks in Silverlight  (2) 2009.05.15
LINQ (Language Integrated Query)  (0) 2009.04.06
Silverlight with WEB  (0) 2009.03.30
Posted by 알 수 없는 사용자