펌프, 팬, 밸브, LED 등을 표시하는 Animation Control을 만들어 보자.
복잡한 모양의 UserControl은 SVG를 로딩해서 Animation하는 것도 가능하다. 이것은 나중에 따로 살펴보기로 하고, 우선 XAML로 UserControl을 그리고, Animation하는 방법으로 진행한다.
Page(View)에서 UserControl의 상태(Value) 속성을 설정하면, 동작모드에 따라 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의 속성을 설정할 수 있다.
<!-- 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가지가 있다.
코드 비하인드에서 직접 업데이트하려면 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;
}
단순한 컨트롤이지만 LED를 그리기 위해 최소한 다음과 같은 속성의 Binding이 필요하다.
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에 더 많은 기능이 추가되어야 한다.
이 부분은 나중에 따로 다루겠다.