본문 바로가기
프로그래밍 언어/WPF

[C#] WPF - 토글 스위치(Toggle Switch) 생성

by Jinwood 2023. 12. 26.
반응형

토글 스위치가 필요하여 구글링으로 알게 된 내용과 구현하고자 하는 방식에 차이가 있어 일부 내용을 수정하여 만들게 되었다.  수정하던 중 이상한 현상이 있어 내용을 기록해 본다.

 

생성하려는 토글 스위치(좌:False / 우:True)

 

1. Animation 사용

위 이미지의 토글 스위치에서 IsChecked = True일 경우, Border 배경 색상이 변경된다.

이 코드를 Storyboard에서 Animation으로 설정했는데, 토글 버튼인 Ellipse를 이동시키는 Animation과 함께 사용된다.

아래 코드를 보면 ColorAnimation과 ThicknessAnimation이 함께 사용됨을 확인할 수 있다.

 

이렇게 사용하면 IsChecked 속성 변경 시 배경색이 변경되며 토글 버튼이 이동하는데, 이상한 점은 xaml에서 IsChecked 속성을 변경해도 빌드해 보면 적용이 되지 않는다는 것이다. 자세히 설명하자면 아래와 같다.

  1. 토글 버튼의 기본 위치는 IsChecked = False의 위치
  2. xaml에서 IsChecked = True로 설정하면 토글 버튼의 위치가 변경됨
  3. 빌드하여 폼에서 확인하면 IsChecked = False 상태로 표시됨
    - 하지만 해당 토글 버튼의 IsChecked 속성을 확인해 보면 True
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
32
33
34
35
<ControlTemplate.Triggers>
    <EventTrigger RoutedEvent="Checked">
        <BeginStoryboard>
            <Storyboard>
                <ColorAnimation Storyboard.TargetName="Border"
                            Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                            To="GreenYellow"
                            Duration="0:0:0.5" />
                <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                Storyboard.TargetProperty="Margin"
                                To="20 1 2 1"
                                Duration="0:0:0.2" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
    <EventTrigger RoutedEvent="Unchecked">
        <BeginStoryboard>
            <Storyboard>
                <ColorAnimation Storyboard.TargetName="Border"
                            Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                            To="#FFF5F5F5"
                            Duration="0:0:0.2" />
                <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                Storyboard.TargetProperty="Margin"
                                To="2 1 2 1"
                                Duration="0:0:0.2" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
 
    <Trigger Property="IsEnabled" Value="false">
        <Setter Property="Opacity" Value="0.35" />
    </Trigger>
 
</ControlTemplate.Triggers>
cs

 

다른 토글 스위치를 만들어 테스트를 해보았으나 해답은 Animation 사용에 있었다.

Storyboard에 Animation을 2개 사용하면 위 설명된 내용처럼 IsChecked 상태가 꼬이게(?) 된다. 정확한 이유는 잘 모르겠으나, Animation을 1개만 사용하면 위 현상이 발생하지 않았다.

 

2. 토글 스위치 최종 결과

결국 Animation은 하나만 사용하고, Trigger에서 배경색을 변경하는 것으로 코드를 작성했다. 코드는 아래와 같다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<Style TargetType="{x:Type local:ToggleSwitch}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ToggleSwitch}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Viewbox Grid.Column="0">
                        <Border x:Name="Border" CornerRadius="10" Background="#FFF5F5F5" 
                                Width="40" Height="20" BorderThickness="1" BorderBrush="Black" >
                            <Border.Effect>
                                <DropShadowEffect ShadowDepth="0" Direction="0" Opacity="0" />
                            </Border.Effect>
                            <Ellipse x:Name="Ellipse" Fill="Magenta" Stretch="Uniform"
                             Margin="2 1 2 1" Stroke="Lime" StrokeThickness="1" 
                             HorizontalAlignment="Stretch">
                            </Ellipse>
                        </Border> 
                    </Viewbox>
                    <ContentPresenter Grid.Column="1" Content="{TemplateBinding Content}" 
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                      Visibility="{TemplateBinding IsReadOnly}" /> 
                </Grid>
                <ControlTemplate.Resources>
                    <Storyboard x:Key="right">
                        <ThicknessAnimation Storyboard.TargetName="Ellipse" 
                                Storyboard.TargetProperty="Margin" Duration="0:0:0.2" To="20 1 2 1">
                            <ThicknessAnimation.EasingFunction>
                                <CircleEase EasingMode="EaseOut"/>
                            </ThicknessAnimation.EasingFunction>
                        </ThicknessAnimation>
                    </Storyboard>
                    <Storyboard x:Key="left">
                        <ThicknessAnimation Storyboard.TargetName="Ellipse" 
                                Storyboard.TargetProperty="Margin" Duration="0:0:0.2" To="2 1 2 1">
                            <ThicknessAnimation.EasingFunction>
                                <CircleEase EasingMode="EaseOut"/>
                            </ThicknessAnimation.EasingFunction>
                        </ThicknessAnimation>
                    </Storyboard>
                </ControlTemplate.Resources>
                <ControlTemplate.Triggers>
                    <Trigger Property="ToggleButton.IsChecked" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource right}" x:Name="rightt"/>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource left}" x:Name="leftt"/>
                        </Trigger.ExitActions>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Opacity" Value="0.35"/>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsChecked" Value="True"/>
                            <Condition Property="IsEnabled" Value="True"/>
                        </MultiTrigger.Conditions>
                        <Setter TargetName="Border" Property="Border.Background" Value="GreenYellow"/>
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
cs

 

 

참고 자료 : https://www.youtube.com/watch?v=5oz2zJF_jM4

반응형

댓글