본문 바로가기
Programming/WPF

WPF style. #1

by 곰네Zip 2022. 11. 11.

WPF에서 많은 컨트롤들을 사용할 수 있다. 근데, 그 컨트롤들의 배경색이나 끝마감, 텍스트의 폰트 크기등을 미리 정의할 수 있다. (CSS에 대응된다고 생각하면 쉽다.)

스타일의 장점은

1. 화면에 보이는 UI컨트롤들의 특징을 공통되게 적용할 수 있다. 즉, 일괄 적용이 필요한 것을 해당 style에서 수정하면 된다. (즉, 일이 엄청나게 줄어든다.)

2. 상속이 가능하므로, 상속을 사용하여 일을 더 줄일수 있다.

 

<Window blabla(namespace선언등 여러가지)>
   <Window.Resources>
       <Style x:Key="MyBaseStyle" TargetType="{x:Type Button}">
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="Background" Value="Red" />
        </Style>

        <Style 
            x:Key="MyChildStyle" //이 스타일의 키 이름은?
            TargetType="{x:Type Button}" //어느 컨트롤에 적용할것인지?
            BasedOn="{StaticResource ResourceKey=MyBaseStyle}" //혹시 상속받는다면 부모 키 이름은?
         >
            <Setter Property="VerticalAlignment" Value="Top" />
         </Style>
   </Window.Resources>
   <StackPanel>   
   	    <Button x:Name="BaseBtn" Style="{StaticResource ResourceKey=MyBaseStyle}" Content="BtParent" />
        <Button x:Name="ChildBtn" Style="{StaticResource ResourceKey=MyChildStyle}" Content="BtChild" />
   </StackPanel>
 </Window>

위와 같이 선언하면 스타일이 만들어진다. BasedOn 은 상속받고자 하는 부모 스타일의 키 이름을 적어주면 된다. (없으면 안써도 된다.)

지금 MyChildStyle은 MyBaseStyle 의 속성을 상속받았다. 그래서, MyChildStyle은 VerticalAlignment는 Top, HorizontalAlignment는 Center로 설정되어있는거다. 버튼의 배경색은 Red인거고. 

  적용하는 방법은 StackPanel에 붙인것 처럼 컨트롤에서 Style="{StaticResource Resourcekey=키이름}" << 이렇게 선언하면 스타일이 적용된다.

 다만, 주의할 것은.. 스타일에 선언한 TargetType와 해당 스타일을 사용하는 컨트롤의 Type이 같을 것!

 즉, 스타일의 TargetType이 Textblock인데, 그 스타일을 Button에다가 적용하려들지 말것.. (당연히...)

  그리고 Style은 Resource영역에 선언 가능한데.. 이걸 별도의 Resource파일에 선언하고, 각 xaml에서 해당 resource를 import해서 사용할 수 있다.

 예를들어 내가 ./Resources/BaseStyle.xaml 이라는 resource파일을 만들었다고 하면.. 각 UI를 담당한 xaml에서는 다음과 같이 사용할 수 있다.

<Window namespaces...blabla>
	<Window.Resources>
    	<ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MyAssembly;Resources/BaseStyle.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
</Window>

 위와 같이 ResourceDictionary.MergedDictionaries안에 포함할 ResourceDictionary이름을 적어주면 된다.

Source는 상대경로, 절대경로 다 가능하다. 상대경로로 한다면.. pack://...; 부분을 지우고, ../Resources/ << 이런식으로 작성해주면 된다. 다만, 절대경로로 처리하는 것이 나중에 좀 더 깔끔해진다. 상대경로는 폴더 위치가 변경되거나 하면.. 저 경로를 다시 다 맞추어야한다. 절대경로를 추천..

 참.. 저 ResourceDictionary끼리도 참조 가능하다.

 그래서 ResourceDictionary에 어디에는 Button Style만, 어디에는 TextBox Style만, 또 어디에는 Color ( Brush)만 정의하고, 필요에 따라 각각의 ResourceDictionary를 import하여 새로운 ResourceDictionary를 만들고, 그걸 xaml에서 가져다 쓰도록 만드는 것도 가능하다.

 

 그리고 Resource를 StaticResource로 찾아서 가져오도록 해 두었다. 필요에 따라 DynamicResource로 하는 것도 가능하다. Dynamic은 말 그대로 동적으로 리소스를 찾는거.. 컴파일타임에 정의하지 않기에 스타일같은거 반영이 디버깅하면서 바로 확인은 잘 안된다. 그리고, 리소스를 불러올 때 해당 리소스가 없으면? 문제발생. 

 하지만, 동적으로 리소스가 변경이 가능하다는 장점이 있다. 

 Static은 그 반대이다. 컴파일 타임에 리소스를 적재하니까 속도는 좀 더 빠르다. 그리고, 개발하면서 변경되는 사항은 바로바로 반영 및 확인이 쉽다. 하지만 정적이다.

 

  그리고.. Style적용 시, Style="{StaticResource ResourceKey=키이름}" 이런식으로 작성하고, Style선언 시, TargetType에 {x:Type Button} 이런식으로 작성해 두었는데.. Style="{StaticResource 키이름}", TargetType="{Button}" 으로 해도 되긴 한다. 근데, 조금 더 명확하게 누구를 찾아라! 라고 지정하기위해 항상 작성하던 습관이 있어서 ResourceKey=키이름 << 이런식으로 작성한다. 가급적이면 저렇게 명확하게 해주세요. :)

 

반응형

댓글