UserControl #1

guru chun (haechul chun)·2025년 6월 13일
0

WPF 개발

목록 보기
10/10

펌프, 팬, 밸브, LED 등을 표시하는 Animation Control을 만들어 보자.

  • 우선 User Control에 익숙해지기 위해 Animation 없는 LED를 만들고,
  • ON/OFF 시에 Animation 효과를 적용한 밸브 컨트롤을 만들어 보겠다.
  • 이어서 좀 복잡한 모양을 가지는 FAN을 만들겠다.
  • 펌프는 외관만 다르고 동작방식은 동일하므로 생략한다.

LED 컨트롤 만들기

복잡한 모양의 UserControl은 SVG를 로딩해서 Animation하는 것도 가능하다. 이것은 나중에 따로 살펴보기로 하고, 우선 XAML로 UserControl을 그리고, Animation하는 방법으로 진행한다.

  • UserControl 그리기: Circle
  • 오브젝트의 속성(내부) 정의: 라인 색상, 채우기 색상
  • UserControl 속성(외부) Binding하기: LED 동작 모드, LED 상태
  • 런타임에 컨트롤 편집

컨트롤 그리기

Page(View)에서 UserControl의 상태(Value) 속성을 설정하면, 동작모드에 따라 LED 오브젝트의 색상을 변경한다.

  • LED는 Disabled, ON, OFF 3가지 상태를 가진다.
  • 동작모드에 따라 Disabled, Normal, Warning, Error, Blink 등 여러가지 상태를 가지도록 정의할 수 있다.
    여기서는 ON/OFF LED를 만들기 위해 예로 아래와 같이 정의한다.
<UserControl x:Class="MyApp.Views.Controls.LED"
             xmlns="http://..."
             d:DesignHeight="30" d:DesignWidth="30">
    <Grid>
        <Ellipse x:Name="Light"
                 Width="20" Height="20"
                 Stroke="DarkGray" StrokeThickness="1"/>
        <TextBlock x:Name="Label"
                   Text="LABEL"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Bottom"/>
    </Grid>
</UserControl>

컨트롤 속성

UserControl은 최소한 다음 속성을 제공해야 한다. Page(Container, Parent Window)는 XAML에서 이 UserControl의 속성을 설정할 수 있다.

  • Value: LED 상태(ON/OFF)
  • LabelText: LED 라벨
  • LabelAlignment: 라벨의 위치를 지정한다.
<!-- page code -->
xmlns:uc="clr-namespace:MyApp.Views.Controls"
...
<uc:LED Canvas.Left="100" Canvas.Top="50"
        LabelText="ABC"
		Value="True"/>

코드비하인드에서 속성은 다음과 같이 정의된다.

// xaml에서 설정할 수 있는 속성 정의
public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register(nameof(Value),
            	typeof(bool), typeof(Indicator),
                new PropertyMetadata(false));
// Value 속성 정의
public bool Value
{
	get => (bool)GetValue(ValueProperty);
	set { 
		SetValue(ValueProperty, value);
	}
}

컨트롤 업데이트

LabelText나 LabelAlignment 속성은 편집모드에서만 변경될 것이다. Value 속성은 런타임에 실시간으로 변경될 것이므로 Value 속성이 변경될 때 컨트롤의 색상이 변경되도록 해보자.
UserControl의 Ellipse 객체를 업데이트하는 방법은 2가지가 있다.

  • 코드비하인드에서 Ellipse 객체의 이름으로 Stroke, StrokeThickness, FillColor를 직접 업데이트한다.
  • Ellipse 객체의 Stroke, ... 을 UserControl Property에 Binding해서 값이 변경될 때 자동으로 업데이트되게 한다.

Update Directly

코드 비하인드에서 직접 업데이트하려면 Value 속성이 바뀔 때 이벤트를 처리해야 한다. 이를 위해서는 Value 속성에 Changed 이벤트 핸들러 OnValueChanged를 등록해 준다.

// xaml에서 설정할 수 있는 속성 정의
public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register(nameof(Value),
            	typeof(bool), typeof(Indicator),
                new PropertyMetadata(false, OnValueChanged));
                
// OnValueChanged 정의
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
	var control = d as Indicator;
	control?.UpdateVisuals();
}

private void UpdateVisuals()
{
	Light.Fill = Value ? _colorOn : _colorOff;
	Light.Stroke = Value ? _borderOn : _borderOff;
}

Binding Property

단순한 컨트롤이지만 LED를 그리기 위해 최소한 다음과 같은 속성의 Binding이 필요하다.

  • BorderColor: Ellipse.Stroke
  • FillColor: Ellipse.Fill
  • TextColor: TextBlock.Forground
    UserControl의 Value 속성을 Set할 때 위 속성을 업데이트한다.
    또는 Ellipse 객체가 FillColor 속성을 Get할 때 Value 속성으로부터 Color를 결정한다.
public Brush FillColor
{
	get => (bool)GetValue(ValueProperty) ? _colorOn : _colorOff;
}

이 속성들은 다음과 같이 Ellipse 객체에 바인딩된다.

<Ellipse x:Name="Light"
         Width="20" Height="20"
         Stroke="{Binding BorderColor}" StrokeThickness="1"
         Fill="{Binding FillColor}"/>

컨트롤 편집

디자인 타임에 컨트롤을 배치하고, 그대로 Application을 만들어 배포하면 UserControl을 만드는 것은 어렵지 않다.
하지만 화면에디터(저작도구, 작화)를 제공해서 런타임에 컨트롤을 추가하고 이동하고, 크기를 변경할 수 있게 해달라는 요구사항을 받는다. 이를 위해서는 UserControl에 더 많은 기능이 추가되어야 한다.
이 부분은 나중에 따로 다루겠다.

profile
오늘도, 내일도 코딩을 즐기자

0개의 댓글