TOC

This article has been localized into Korean by the community.

WPF application:

리소스

WPF는 매우 편리한 개념을 도입했습니다 : 데이터를 리소스 형태로 저장하는 것입니다. 컨트롤이나 윈도우를 지역적으로 저장하거나, 전체 어플리케이션을 전역으로 저장할 수 있습니다. 이때 데이터는 당신이 원하는 모든 데이터입니다. 실제 정보일수도 있고, WPF 컨트롤들의 계층구조일 수도 있습니다. 이 개념은 데이터를 한 곳 또는 몇몇 장소에 저장해서 사용할 수 있어 매우 유용합니다.

이 개념은 스타일과 템플릿에서 자주 사용합니다. 이번 챕터에서는 간략히만 알아보고 나중에 다시 다루겠습니다. 당신은 이 개념을 매우 다양한 곳에서 활용할 수 있습니다. 다음의 간단한 예제에서 증명해 보겠습니다 :

<Window x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ResourceSample" Height="150" Width="350">
    <Window.Resources>
        <sys:String x:Key="strHelloWorld">Hello, world!</sys:String>
    </Window.Resources>
    <StackPanel Margin="10">
        <TextBlock Text="{StaticResource strHelloWorld}" FontSize="56" />
        <TextBlock>Just another "<TextBlock Text="{StaticResource strHelloWorld}" />" example, but with resources!</TextBlock>
    </StackPanel>
</Window>

리소스는 x:Key 속성으로 키를 받습니다. 키를 이용해 어플리케이션 내 다른 위치에 있는 값을 참조할 수 있습니다. 키는 markup extension인 StaticResource와 결합되어 있습니다. 이 예제에서는 간단한 문자열을 저장하였고 두 개의 다른 TextBlock 컨트롤에서 사용했습니다.

StaticResource와 DynamicResource

지금까지의 예제에서는 리소스를 참조하기 위해 StaticResource markup extension을 사용했습니다. 하지만 DynamicResource라는 다른 형태의 대안이 있습니다.

정적 리소스의 경우, XAML이 로드될 때 단 한번 할당된다는 것이 주요 특징입니다. StaticResource를 사용하면 나중에 리소스가 변경되더라도 변경사항이 반영되지 않습니다.

반면에 DynamicResource는 실제 필요할 때마다 할당합니다. 리소스가 변경될 때 마다 반복해서 할당할 수 있습니다. 정적인 값을 바인딩하는 경우와, 이 값을 모니터링하여 변경 시 값을 전달하는 기능을 바인딩하는 경우를 생각해보겠습니다. 정답이 될 수는 없지만 어떤 방법을 사용하는 것이 나을 지에 대하여 좋은 아이디어를 줄 수 있습니다. 동적인 리소스는 디자인 타임에는 존재하지 않았던 리소스들도 사용할 수 있습니다. 예를 들어 어플리케이션을 시작할 때 Code-behind에서 추가할 수 있습니다.

다양한 리소스 타입

간단한 문자열을 사용하는 것은 쉬운 예지만, 그 외에 많은 것들도 할 수 있습니다. 다음의 예제에서는 문자열로 이루어진 배열과 배경으로 쓰일 gradient brush를 추가해보겠습니다. 리소스를 가지고 얼마나 많은 일들을 할 수 있는지에 대해 좋은 아이디어를 줄 것입니다.

<Window x:Class="WpfTutorialSamples.WPF_Application.ExtendedResourceSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ExtendedResourceSample" Height="160" Width="300"
        Background="{DynamicResource WindowBackgroundBrush}">
    <Window.Resources>
        <sys:String x:Key="ComboBoxTitle">Items:</sys:String>

        <x:Array x:Key="ComboBoxItems" Type="sys:String">
            <sys:String>Item #1</sys:String>
            <sys:String>Item #2</sys:String>
            <sys:String>Item #3</sys:String>
        </x:Array>

        <LinearGradientBrush x:Key="WindowBackgroundBrush">
            <GradientStop Offset="0" Color="Silver"/>
            <GradientStop Offset="1" Color="Gray"/>
        </LinearGradientBrush>
    </Window.Resources>
    <StackPanel Margin="10">
        <Label Content="{StaticResource ComboBoxTitle}" />
        <ComboBox ItemsSource="{StaticResource ComboBoxItems}" />
    </StackPanel>
</Window>

이번에는 몇 가지 다른 리소스를 추가했습니다. 윈도우는 간단한 문자열, 문자열 배열, LinearGradientBrush를 포함하고 있습니다. 문자열은 라벨에서 이용하고 문자열 배열은 콤보박스 컨트롤에서 이용합니다. gradient brush는 전체 윈도우 배경에 이용합니다. 위에서 볼 수 있듯이 리소스로 어떤 것이든 저장할 수 있습니다.

로컬 리소스와 어플리케이션 리소스

지금까지는 윈도우 레벨에서 리소스를 저장했습니다. 즉 윈도우의 모든 부분에서 리소스에 접근할 수 있었습니다.

하나의 특정 컨트롤을 위한 리소스가 필요할 경우, 윈도우가 아닌 컨트롤에 추가해서 지역적으로 사용할 수 있습니다. 작동 방식은 동일합니다. 유일한 차이점은 생성된 컨트롤 범위 내에서만 접근할 수 있다는 것입니다 :

<StackPanel Margin="10">
    <StackPanel.Resources>
        <sys:String x:Key="ComboBoxTitle">Items:</sys:String>
    </StackPanel.Resources>
    <Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>

이 경우에는 StackPanel에 리소스를 추가하고 하위 컨트롤인 Label에서 추가한 리소스를 사용했습니다. StackPanel 내 다른 컨트롤도 마찬가지로 이 리소스를 사용할 수 있습니다. 하위 컨트롤의 하위 컨트롤도 사용할 수 있습니다. 그러나 StackPanel 외부에서는 접근할 수 없습니다.

여럿의 윈도우에서 리소스에 접근해야 하는 경우도 가능합니다. 윈도우나 WPF 컨트롤이 리소스를 포함할 수 있는 것처럼 App.xaml 파일도 리소스를 포함할 수 있습니다. App.xaml 파일에 리소스를 저장하면, 전역적으로 프로젝트 내 모든 윈도우와 컨트롤에서 접근할 수 있습니다. 윈도우에 리소스를 저장하고 사용하는 방식과 동일하게 작동합니다 :

<Application x:Class="WpfTutorialSamples.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             StartupUri="WPF application/ExtendedResourceSample.xaml">
    <Application.Resources>
        <sys:String x:Key="ComboBoxTitle">Items:</sys:String>
    </Application.Resources>
</Application>

사용 방법도 동일합니다 - WPF는 주어진 리소스를 찾기 위해 자동으로 로컬 컨트롤에서 윈도우로, App.xaml로 범위를 올려갑니다.

<Label Content="{StaticResource ComboBoxTitle}" />

Code-behind의 리소스

지금까지는 markup extension을 이용해서 XAML에서 바로 리소스에 접근했습니다. 하지만 Code-behind에서도 리소스에 접근할 수 있으며 몇몇 경우에는 더 유용할 수 있습니다. 이전 예제에서 어떻게 리소스를 각기 다른 곳에 저장하는지 알아보았습니다. 다음 예제에서는 Code-behind 각기 다른 곳에 저장된 리소스에 접근해보도록 하겠습니다.

App.xaml:

<Application x:Class="WpfTutorialSamples.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             StartupUri="WPF application/ResourcesFromCodeBehindSample.xaml">
    <Application.Resources>
        <sys:String x:Key="strApp">Hello, Application world!</sys:String>
    </Application.Resources>
</Application>

Window:

<Window x:Class="WpfTutorialSamples.WPF_Application.ResourcesFromCodeBehindSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ResourcesFromCodeBehindSample" Height="175" Width="250">
    <Window.Resources>
        <sys:String x:Key="strWindow">Hello, Window world!</sys:String>
    </Window.Resources>
    <DockPanel Margin="10" Name="pnlMain">
        <DockPanel.Resources>
            <sys:String x:Key="strPanel">Hello, Panel world!</sys:String>
        </DockPanel.Resources>

        <WrapPanel DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="10">
            <Button Name="btnClickMe" Click="btnClickMe_Click">Click me!</Button>
        </WrapPanel>

        <ListBox Name="lbResult" />
    </DockPanel>
</Window>

Code-behind:

using System;
using System.Windows;

namespace WpfTutorialSamples.WPF_Application
{
	public partial class ResourcesFromCodeBehindSample : Window
	{
		public ResourcesFromCodeBehindSample()
		{
			InitializeComponent();
		}

		private void btnClickMe_Click(object sender, RoutedEventArgs e)
		{
			lbResult.Items.Add(pnlMain.FindResource("strPanel").ToString());
			lbResult.Items.Add(this.FindResource("strWindow").ToString());
			lbResult.Items.Add(Application.Current.FindResource("strApp").ToString());
		}
	}
}

위와 같이 우리는 3개의 다른 "Hello, world!" 메시지를 저장했습니다 : App.xaml에 하나, window 내부에 하나, 지역적으로 main panel에 하나 입니다. 인터페이스는 버튼 하나와 리스트박스 하나로 구성되어 있습니다.

Code-behind에서는 버튼의 클릭 이벤트를 다룹니다. 스크린샷에서 볼 수 있듯이, 각각의 문자열 텍스트를 추가합니다. FindResource()라는 메소드를 사용해서 리소스를 (찾으면) object로 리턴합니다. 그리고 ToString() 메소드를 사용해 우리가 알고있는 string으로 변환합니다.

각기 다른 계층에서 어떻게 FindResource() 메소드를 사용하는지 주목해봅시다 - 첫 번째는 panel, 두 번째는 window, 마지막은 current Application object 입니다. 이미 알고 있는 곳에서 리소스를 찾는 것이 일반적이지만, 이전에 언급했던 대로 리소스를 찾지 못하면 계층 구조를 따라 검색합니다. 기본적으로 세 리소스 모두 Panel 계층에서 FindResource() 메소드를 사용해 찾을 수 있습니다. panel 레벨에서 찾지 못할 경우 window, application 레벨까지 탐색을 이어가기 때문입니다.

다른 방법으로는 같은 결과를 얻을 수 없습니다 - 검색은 트리구조의 아래 방향으로 진행하지 않습니다. 즉 리소스가 컨트롤에 지역적으로, 또는 윈도우에 정의되어 있으면 application 레벨부터 검색해서는 찾을 수 없습니다.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!