블로그 이미지
* Microsoft MVP - Windows Development 2014 ~ 2019 5ring * LINE : kaki104 * facebook : https://www.facebook.com/kaki104 https://www.facebook.com/groups/w10app/ kaki104

카테고리

List All (551)
Xamarin Forms (4)
Bot Framework (19)
Azure (9)
Windows 10 (35)
Facebook News & Tips (158)
Windows App(Universa.. (83)
Windows 8&8.1 (113)
Windows Phone 8 (42)
Silverlight (37)
HTML5 & MVC4 (16)
WPF (1)
Portable Class Library (2)
Uncategorised Tips a.. (3)
Kinect for Windows (2)
ETC (12)
kaki104 Scrap (4)
App News (11)
Total522,039
Today48
Yesterday101

앱을 만들다 보면, 기본 컨트롤로는 표현하기 힘든 내용이나, 개성있는 나만의 컨트롤을 만들어서 사용하고 싶을 때가 있다. 그럴 때 사용할 사용자 정의 컨트롤에는 어떤 종류가 있으며 어떻게 만들어야 하는지에 대해서 알아보자.

 

 

1. 참고 포스트

1-1. Building C# custom controls in WinRT Metro

http://blogs.u2u.be/diederik/post/2012/01/21/Building-C-custom-controls-in-WinRT-Metro.aspx

 

1-2. Building Custom Controls for Windows 8 Store apps

http://blogs.u2u.be/diederik/post/2012/12/06/Building-Custom-Controls-for-Windows-8-Store-apps.aspx

 

1-3. A Radial Gauge for Universal Windows Apps

http://blogs.u2u.be/diederik/post/2014/04/14/A-Radial-Gauge-for-Universal-Windows-Apps.aspx

 

 

2. 사용자 정의 컨트롤의 종류

사용자 정의 컨트롤은 UserControl과 CustomControl를 이용해서 만들 수 있다.

 

The differences between CustomControls and UserControls

http://www.wpftutorial.net/customvsusercontrol.html

 

위의 포스트에 내용을 간추려 보면 아래와 같다.

 

UserControl (Composition)

. 존재하는 여러 컨트롤을 조합해서 그룹 형태로 만드는 것

. XAML과 비하인드 코드로 구성 - UI와 코드가 함께 있음

. 여러 컨트롤을 조합하기 때문에 단일 Style/template 를 사용할 수 없음

. UserControl에서 도출되었기 때문에 기본 특성을 상속 받음 - CustomControl에 비해 무거움

 

 

 

CustomControl (Extending an existing control)

. 기존 컨트롤에 기능을 추가 확장하는 것 - 여러 컨트롤을 하나의 묶음 처럼 사용할 수도 있음

. XAML과 비하인드 코드가 분리되어 있음 - 1개의 기본 style이 Themes/Generic.xaml에 존재

. 단일 style/template 를 사용할 수 있음

. Control에서 도출되었기 때문에 UserControl에 비해 가벼움

 

 

 

3. 사용자 정의 컨트롤 만들기 시작

1-1번 포스트가 WinRT Metro앱에서 사용하는 컨트롤을 만드는 예제이기는 하지만, 개발자 경험은 상속된다! 그러므로..동일한 방법으로 만들면 된다.

 

 기본 컨셉

 

 

File -> New Project

 

 

프로젝트 폴더에서 마우스 오른쪽 버튼눌러서

Add -> New Item

 

 

컨트롤 이름은 SimpleSlider

이렇게 추가를 하면 프로젝트에 Themes 폴더와 Generic.xaml 파일이 자동으로 추가된다.

 

 

4. 의존성 프로퍼티 추가

 

SimpleSlider.cs 파일을 열고 SimpleSlider class안에 커서를 두고

 

Ctrl+K,X를 입력해서 NetFX30을 선택하면

 

Define a DependencyProperty 선택

 

아래와 같이 변경한다.

 

        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

 

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(SimpleSlider), new PropertyMetadata(0.0, OnValueChanged));

 

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var customSlider = (SimpleSlider) d;
            customSlider.UpdateControls();

        }


 

디펜던시 프로퍼티는 디자인 타임에 오른쪽 프로퍼티 창에 표시되는 녀석이다.

그리고 OnValueChanged 메소드는 Value 프로퍼티에 값이 변경되면 실행되는 녀석으로 내부 코딩은 대체적으로 d를 자기 자신으로 받은 후 특정 기능을 실행한다.

 

최소값과 최대값 프로퍼티를 위와 같은 방법으로 추가한다.

 

 

5. 디자인

 

블랜드를 이용해서 프로젝트를 연다. 그리고 MainPage.xaml을 선택하고, 오른쪽 Resources 탭을 선택한다. Generic.xaml을 확장하고 [SimpleSlider default] 오른쪽에 <> 부분을 클릭해서 편집 모드로 들어간다.

 

 

컨트롤 디자인을 하기 위해 아래와 같이 클릭 후 Edit Template -> Edit Current를 클릭한다.

 

노란색 부분을 클릭하면 편집을 종료하고 원래 화면으로 복귀한다.

빨간색 부분이 아이템 템플릿 부분으로, 이곳을 블로그의 Styling 섹션같이 만들어 보자.

 

1) Border를 선택하고 마우스 오른쪽 버튼을 클릭해서 Change Layout Type -> Grid를 선택한다.

 이렇게 변환을 하면 필요없는 프로퍼티들이 지정된다. 소스를 보면서 정리해 준다.

 

 

2) 완성된 XAML 코드

    <Style TargetType="local:SimpleSlider" >
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:SimpleSlider">
                    <Grid Height="8">
                        <Border Height="8" Background="LightGray"
                                VerticalAlignment="Stretch"/>
                        <Canvas MinHeight="8">
                            <Rectangle x:Name="PART_Rectangle" Fill="Yellow" Height="8" />
                            <Thumb x:Name="PART_Thumb" Height="8" Width="8" Background="Green" />
                        </Canvas>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

 

 

6. 다시 코드 작업

 

처음 그림에서 Thumb과 Rectangle가 중요한 역할을 하기 때문에 해당 컨트롤을 코드에서 직접 제어를 해야한다. 그래서,  TemplatePart라고 속성을 추가하고, OnApplyTemplate()에서 각 내부 변수들에 GetTemplateChild를 이용해서 인스턴스를 땡겨온다.

 

    [TemplatePart(Name = ThumbPartName, Type = typeof (Thumb))]
    [TemplatePart(Name = RectanglePartName, Type = typeof (Rectangle))]
    public sealed class SimpleSlider : Control
    {
        private const string ThumbPartName = "PART_Thumb";
        private const string RectanglePartName = "PART_Rectangle";

 

        private Thumb _thumb;
        private Rectangle _rectangle;

...

...

 

사용자 정의 컨트롤에서 중요한 부분은 OnApplyTemplate()에 대부분 구현이 된다. 특히 이벤트 핸들러를 추가하는 부분이 여기서 들어간다.

 

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _thumb = GetTemplateChild(ThumbPartName) as Thumb;
            if (_thumb == null) return;
            _thumb.DragDelta += _thumb_DragDelta;
            _rectangle = GetTemplateChild(RectanglePartName) as Rectangle;
            SizeChanged += SimpleSlider_SizeChanged;
        }

 

나머지 코드는 위치 이동하고 크기 조정하는 코드들이다. 전체 소스를 참고한다.

 

6. 완성된 셈플 화면

 

 

7. 개선할 사항

썸을 마우스로 클릭해서 드래그 해야지만 값이 변경되는데, 그걸 그냥 마우스 클릭해서 값이 변경되도록 하면 좋을 듯하다. 다음에는 1-2 블로그를 따라해 보기로 하겠다

 

 

CustomControlSample.zip

 

 

Posted by MVP kaki104

티스토리 툴바