삽질의 현장/- .NET

#111_닷넷(.NET)_ WPF_ 리소스(Resource)

shovelman 2015. 11. 30. 00:54


안녕하세요 삽잡이입니다.


지난 시간에는 데이터 바인딩을 XAML 코드로써 나타냈습니다.

이번 시간에는 WPF에서의 리소스에 대해서 알아보려고합니다.


리소스는 지금까지의 개념으로는 

즉, UI에서 사용하는 리소스가 아닌 일반적인 리소스의 개념은

시스템으로부터 얻고, 사용한 뒤에 반환해줘야하는 자원들이었습니다.


그런데, API로부터 리소스란 의미는

디자이너와 프로그래머가 분류해서 협업하기 위한 구성요소중

디자이너에 있는 요소들을 리소스라고 불렀습니다.


헷갈리게도 WPF에서 또 용어의 의미가 약간 달라집니다.

데이터에다가 이름을 붙일 수 있으면 모두 다 리소스라고 부르게 된 것입니다.

즉, 개념이 확장된 것이지요.


지금부터 WPF에서의 리소스에 대해서 알아보겠습니다.


WPF에서 리소스는 이름만 설정할 수 있으면,

이미지이던, 객체이던, 문자열이던, 상수이던 상관없이 리소스가 될 수 있습니다.


사실, 리소스가 될 수 있는 것은 object 형식입니다.

그런데 이 형식이 확장 된 것이지요.


XAML에서는 리소스를 미리 정의할 수 있습니다.

굳이 C# 코드로 만들 필요 없이,

선언 언어인 XAML에서 리소스를 만들 수 있고,

이름만 가지게 되면 리소스를 가질 수 있다는 소리이니,

리소스로 어떤 객체도 만들 수 있다는 사실을 알 수 있게 됬습니다.


또한, 모두라고 할 수는 없지만,

대부분의 UI요소, XAML에서의 요소들에는 

Resources라는 속성을 가지고 있습니다.


이 Resoureces 속성을 통해

Element 내부에서 필요로 하는 리소스를 정의할 수 있게되지요.


리소스는 미리 존재하면 굳이 내가 필요할때마다 

만들 필요 없이 가져다 쓰면 되기에 정의할 수 있습니다.


쉽게, WPF는 이름만 가지면 리소스라고 생각하셔도 됩니다.

이제 이 리소스를 어디에서 정의할지에 대해 생각해보겠습니다.


만약, 컴퓨터 전체에 필요한 리소스라면 

OS에 리소스를 넣을 수 있겠지요.

또한, 해당 프로그램 전체에 사용하는 리소스라면 

어플리케이션 단에 리소스를 넣을 수 있겠지요.



이와 같이 필요한 범위 내에서 XAML로 표현 및 정리를 할 수 있게 되고,

이게 바로 Resources라는 속성의 기능입니다.


필요한 범위내에서 사용할 수 있도록 계층 구조를 사용하는 이유는..

모든 곳에서 사용하는 것이 아닌,

어떤 리소스가 어디에서 사용되는지

즉, 종류 및 범위를 나눠놓기 위해서 사용하는 것입니다.


위의 예제에서는 NickNames라는 클래스...

즉, C#코드에서 사용자가 정의해 사용하는 Class를 

XAML로 명시해주고 있습니다.

이는 C#코드에서 객체를 생성하려는 것이 아닌,

XAML에서도 객체가 생성할 수 있음을 알려주는 것입니다.


Resources 속성만 가지고 있다면, 어떤 객체도 정의할 수 있습니다.

Element 하나는 객체 생성과 똑같습니다.

기본 생성자를 이용한 객체 생성이지요.



이와 같은 리소스 내부에는 이름을 가져야하는데,

이 이름은 바로 'Key'의 값입니다.


즉, 위의 예제 코드의 경우

Nicknames라는 타입의 리소스 이름이 names가 된다는 것입니다.


그런데, Nicknames는 C#코드에서 정의했기 때문에 XAML에서 모릅니다.



C# 코드에서 정의했다는 의미로써,

local이라는 명칭을 만들고, 해당 명칭을 통해 알려줄 수 있습니다.

명칭 뒤에는 정의한 Namespace를 명시해줍니다.


지금까지의 예제는 모두 객체를 생성한 것입니다.

리소스로써 객체 생성을 하나 했는데 그 객체의 이름이 names라는 것이죠.



다시 해당 코드를 보자면,

Button같은 경우 자식 요소를 콘텐츠로 갖겠지만,

Collection의 경우에는 자식으로 원소를 갖게 됩니다.

즉, Add() 함수를 호출하는 것과 같은 것이지요.


참고로, XAML에서 Add() 함수를 호출하는 것과 같기 위해서는

해당 클래스는 ObservableCollection<T> 형식을 상속받아야합니다.


아무튼... 

리소스로 만들고, 바인딩 원본으로 선택까지 해봤습니다.


해당 예제에서 리소스에서 만든 객체는 names라고 명했습니다.

이제 해당 객체를 C# 코드에서 쓰기 위해서는 

C# 코드로 해당 컬렉션을 가져올 수 있어야합니다.



리소스를 부르는 몇가지의 방법 중 하나로써,

XAML상에 놓여있는 리소스 Key 즉, 이름으로 

객체의 참조를 얻는 방법이 있습니다.


FindResource() 메서드는 이름에 해당하는 객체를 찾게되면, 

object형식의 객체 참조를 반환하기 때문에 

형식변환을 통해 참조를 얻을 수 있습니다.


리소스를 통해 바인딩 원본을 선택한 것이 되는 셈이죠.



그런데, 바인딩 소스가 선택되지 않고 객체만 만들어져있기 때문에

바인딩에 대한 원본을 선택해줘야합니다.

즉, DataContext는 바인딩 원본을 선택해주는 일을 하기 때문에 

바인딩 원본 설정을 이처럼 하면 되는 것이지요.


그런데, 이렇게 코드에서 할 필요없이,

바인딩 원본으로 사용할 객체를 XAML에서 리소스로 만들었기 때문에,

XAML에서도 설정을 할 수 있습니다.



코드를 통해 설정할 때에는 이름을 알고 있고, 속성을 직접 달았습니다.

하지만, 이제는 XAML상 DataContext에 { }...

즉, MarkUp 확장 문법을 통해 StaticResource에 

names라는 컬렉션 리소스를 넣어 해당 리소스를 DataContext로 설정할 수 있습니다.


만약, 필요한 리소스 키를 찾는데 없다면 부모 트리까지 찾게 됩니다.

모든 XML, XAML 언어는 트리구조를 가지고 있습니다.

즉, 부모 트리로 하나씩 올라가며 리소스 키를 찾을 수 있다 이겁니다.


C#에서 리소스를 검색하는 함수가 몇가지 있는데,

그 중에서 우리는 FindResource() 메서드를 알아봤었습니다.

이 메서드가 부모 트리까지 올라가며 찾는 역할을 해주지요.


FindResource() 함수는 

부모 트리까지 올라가며 리소스 키가 있는지 확인해주는 기능의 메서드입니다.

구조적으로 굉장히 편하게 만들었습니다.


그런데, 모든 메서드가 부모 트리까지 올라가며 찾는 것은 아닙니다.

부모 트리 검색 없이 Direct로 찾고 없으면 땡인 메서드도 있다 이것입니다.




지금까지 데이터 바인딩을 하면서 배운 내용들을 간략하게 정리해보겠습니다.


WPF는 대부분의 기능을 XAML에서도,

모든 기능을 C#에서도 할 수 있다는 사실을 알았습니다.

XAML의 경우 동적 생성을 할 수 없지요.

정적 생성 즉, 컴파일시 만들어지는 것들은

XAML에서 만들면 훨씬 효율적으로 작성할 수 있게 됩니다.


그리고 이 리소스는 이처럼 굉장히 확장되서 표현되지요.

리소스는 이름만 있으면 모든 것이 다 올 수 있습니다.

이 리소스 때문에 가능한 기술들이 굉장히 많지요.



이번 시간은 여기까지 알아보겠습니다.


이상 삽잡이였습니다!