화면에 노출되는 프로퍼티는?




머릿말


앞서 xaml 코드를 조금 살펴 보았습니다. 그런데 조금 특이한게 보이네요.


<TextBlock>Hello, World!</TextBlock>


위 코드와 아래 코드는 동일합니다.


<TextBlock Text="Hello, World!"></TextBlock>


어떻게 이게 가능할까요? Property 를 명시적으로 지정하지 않고, 그냥 Node 안에 값을 넣었는데, 자동으로 Text 프로퍼티에 값이 들어갑니다.




ContentProperty


비밀은 ContentProperty 안에 있습니다. msdn 에 찾아보면, 

Indicates which property of a type is the XAML content property. A XAML processor uses this information when processing XAML child elements of XAML representations of the attributed type.


이렇게 설명이 되어 있습니다. XAML 프로세서가 XAML 의 자식 엘리먼트를 프로세싱할때 사용하는 정보라고 되어 있네요.


테스트를 위해서 코드를 만들어 보겠습니다.




테스트 코드


아래처럼 UserTextControl 이라는 UserControl 을 하나 만들었습니다.



    [UserTextControl.cs]


public class UserTextControl : Control
{
    static UserTextControl() {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(UserTextControl), new FrameworkPropertyMetadata(typeof(UserTextControl)));
    }

    public string Text {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(UserTextControl), new PropertyMetadata(string.Empty));
}





    [Themes.Generic.xaml]


<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Test">


    <Style TargetType="{x:Type local:UserTextControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:UserTextControl}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <ContentPresenter Content="{TemplateBinding Text}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>





자동으로 생성된 UserTextControl 의 스타일에 ContentPresenter 를 추가해 주었습니다. 그리고 화면에 Text 가 바인딩되어 출력되도록 하였습니다.



    [MainWindow.xaml]


<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:test="clr-namespace:Test"
        x:Class="Test.MainWindow"
        Title="MainWindow" Height="100" Width="200">
    <Grid>
        <test:UserTextControl Text="Hello, World"></test:UserTextControl>
    </Grid>
</Window>




실행하면, 화면에 Hello,World 가 출력됩니다.




이제 이번 본론으로 돌아와서, 아래처럼 MainWindow 를 수정해 보도록 하겠습니다.

<test:UserTextControl>Hello, World</test:UserTextControl>


그대로 빌드하면 오류가 발생하네요. TextBlock 의 경우, 위와 같은 형태로 코드를 작성해도 알아서 Text 라는 프로퍼티로 값이 설정되었는데.... 의도한대로 동작하지 않습니다. ContentProperty 를 설정해 보도록 하죠.



    [UserTextControl.cs]


[ContentProperty("Text")]
public class UserTextControl : Control
{
// 생략...




매우 간단합니다. class 선언부분에 ContentProperty 라는 Attribute 를 추가해 주면 됩니다. 파라미터는 프로퍼티 이름을 넣어주면 됩니다. 다시 빌드해서 실행해 보면, 잘 동작하는 것을 확인 하실 수 있습니다.




추가 테스트 코드


이번엔 조금 변형하여, 아래 코드가 동작하도록 해 봅시다.


    [변형된 형태]


<test:UserTextControl>
            <system:String>Hello, World #1</system:String>
            <system:String>Hello, World #2</system:String>
            <system:String>Hello, World #3</system:String>
        </test:UserTextControl>




화면에 리스트 형태가 출력되도록 먼저 스타일을 수정하도록 하겠습니다.



<Style TargetType="{x:Type local:UserTextControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:UserTextControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ListBox ItemsSource="{TemplateBinding Lines}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>



그리고 난 뒤, 아래처럼 UserTextControl.cs 를 수정해 주면 됩니다.



    [UserTextControl.cs]


[ContentProperty("Lines")]
public class UserTextControl : Control
{
    static UserTextControl() {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(UserTextControl), new FrameworkPropertyMetadata(typeof(UserTextControl)));
    }


    public ObservableCollection<string> Lines {
        get { return (ObservableCollection<string>)GetValue(LinesProperty); }
        set { SetValue(LinesProperty, value); }
    }

    public static readonly DependencyProperty LinesProperty =
        DependencyProperty.Register("Lines", typeof(ObservableCollection<string>), typeof(UserTextControl), new PropertyMetadata(new ObservableCollection<string>()));
}





요컨데, ContentProperty 가 없었다면, 아래처럼 작성해야 했을 것입니다 :)



<test:UserTextControl>
            <test:UserTextControl.Lines>
                <system:String>Hello, World #1</system:String>
                <system:String>Hello, World #2</system:String>
                <system:String>Hello, World #3</system:String>
            </test:UserTextControl.Lines>
        </test:UserTextControl>






'Microsoft > WPF' 카테고리의 다른 글

TreeView Template 을 통한 Canvas 만들기  (1) 2014.11.12
MEF(Managed Extensibility Framework)  (2) 2014.05.19
TypeConverter  (0) 2014.05.12
XAML 의 문법구조  (0) 2014.05.12
xaml 과 cs 파일의 관계  (1) 2014.05.08