XAML or HTML

031. 데이터템플릿 & 셀렉터(DataTemplate & Selector) #2

XAML 뽀개기

이전 포스트에서는 데이타템플릿(DataTemplate) 하는 기능을 알아보았고 컨버터(Converter) 이용해 내가 보낸 메시지와 다른 사람이 보낸 메시지를 다르게 보이게 하는 방법을 살펴봤습니다. 이번 포스트에서는 셀렉터(Selector) 어떤 기능을 하는지 어떻게 사용하는지 살펴봅니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
<!-- Template Selector -->
<DataTemplate x:Key="DataTemplate_Message_Left" DataType="{x:Type local:ExchangeMessage}">
    <StackPanel>
        <TextBlock Text="{Binding Name}" 
                   Visibility="{Binding IsMine, Converter={StaticResource BooleanToVisibilityConverter}, 
                                                ConverterParameter=inverted}"/>
    <Border Background="{Binding IsMine, Converter={StaticResource BooleanToBrushConverter}}" 
            CornerRadius="5" Margin="0,3">
        <TextBlock Text="{Binding Message}" TextWrapping="Wrap" Grid.Column="1" FontSize="11" Margin="5,3,5,7"/>
    </Border>
    <TextBlock x:Name="PART_Time" Text="{Binding ConfirmedTime, StringFormat=hh:mm:ss}" FontSize="8"/>
</DataTemplate>
cs

 

기존의 데이타템플릿의 키값을 DataTemplate_Message_Left로 변경하고 전체 XAML 코드를 [복사 > 붙여넣기]합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<DataTemplate x:Key="DataTemplate_Message_Right" DataType="{x:Type local:ExchangeMessage}">
    <StackPanel>
        <TextBlock Text="{Binding Name}" 
                   Visibility="{Binding IsMine, Converter={StaticResource BooleanToVisibilityConverter}, 
                                                ConverterParameter=inverted}"/>
        <Border Background="{Binding IsMine, Converter={StaticResource BooleanToBrushConverter}}" 
                CornerRadius="5" Margin="0,3">
            <TextBlock Text="{Binding Message}" TextWrapping="Wrap" Grid.Column="1" FontSize="11" Margin="5,3,5,7"/>
        </Border>
        <TextBlock x:Name="PART_Time" Text="{Binding ConfirmedTime, StringFormat=hh:mm:ss}" FontSize="8"
                   HorizontalAlignment="Right"/>
    </StackPanel>
</DataTemplate>
cs

 

복사+붙여넣기한 데이타템플릿의 키값은 DataTemplate_Message_Right으로 변경합니다. 데이타템플릿이 2 준비되었습니다. 확인 시간을 오른쪽으로 정렬하기 위해 PART_Time의 HorizontalAlignment 속성을 Right 선언했습니다.

 

MessageStyleTemplateSelector.cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MessageTemplateSelector : DataTemplateSelector
{
    public DataTemplate LeftTemplate { get; set; }
    public DataTemplate RightTemplate { get; set; }
    public string PropertyToCheck { get; set; }
    public string PropertyValue { get; set; }
 
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var exchangeMessage = (ExchangeMessage)item;
        var type = exchangeMessage.GetType();
        var property = type.GetProperty(PropertyToCheck);
 
        if (property.GetValue(exchangeMessage, null).ToString() == PropertyValue)
        {
            return RightTemplate;
        }
        else
        {
            return LeftTemplate;
        }
    }
}
cs

 

DataTemplateSelector를 상속 받은 MessageTemplateSelector 추가합니다. SelectTemplate 메소드를 재정의합니다. Selector 작성할 메소드를 재정의하는 일은 필수입니다. 사용자가 지정한 프로퍼티(PropertyToCheck) 지정한 (PropertyValue) 일치하면 지정한 데이터템플릿을 리턴하도록 코드를 작성했습니다.

 

1
xmlns:slt="clr-namespace:Sample.Selector" 
cs

 

셀렉터를 XAML 코드에서 사용하려면 네임스페이스를 선언해야 합니다.

 

1
2
3
4
<slt:MessageTemplateSelector x:Key="MessageTemplateSelector" 
                             PropertyToCheck="IsMine" PropertyValue="True" 
                             LeftTemplate="{StaticResource DataTemplate_Message_Left}" 
                             RightTemplate="{StaticResource DataTemplate_Message_Right}"/>
cs

 

MessageTemplateSelector를 리소스에 선언합니다. 이전 포스트에서는 IsMine 프로퍼티에 True 값이 될때 컨버터가 동작하도록 했었습니다. 이번에도 마찬가지 방식으로 지정한 데이타템플릿이 리턴되도록 했습니다.

 

1
2
3
4
5
6
7
8
9
10
11
<!-- Style & Template Selector -->
<ListBox ItemTemplateSelector="{StaticResource MessageTemplateSelector}" 
         Grid.Column="1">
    <ListBox.ItemsSource>
        <x:Array Type="{x:Type local:ExchangeMessage}">
            <local:ExchangeMessage Name="X Friend" Message="Charles~ R u there?" ConfirmedTime="2018-03-01 12:24:33" IsMine="False"/>
            <local:ExchangeMessage Name="Me" Message="Yeah~ i'm here. What's up?" ConfirmedTime="2018-03-01 12:25:44" IsMine="True"/>
            <local:ExchangeMessage Name="X Friend" Message="Do u have time tonight? Let's get it!" ConfirmedTime="2018-03-01 12:26:55" IsMine="False"/>
        </x:Array>
    </ListBox.ItemsSource>
</ListBox>
cs

 

ItemTemplateSelector 속성에 셀렉터를 선언합니다.

 


확인 시간이 오른쪽으로 정렬되었습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- Style Selector -->
<Style x:Key="Style_Message_Left" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <ContentPresenter x:Name="PART_ListBoxItem" 
                                  HorizontalAlignment="Left" 
                                  Margin="5,0,20,5"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="Style_Message_Right" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <ContentPresenter x:Name="PART_ListBoxItem" 
                                  HorizontalAlignment="Right" 
                                  Margin="20,0,5,5"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
cs

 

추가로 스타일셀렉터를 살펴봅니다. 아이템 전체를 오른쪽으로 정렬하려고 합니다. 데이타템플릿과 마찬가지로 Style_Message_Left, Style_Message_Right 2개의 스타일을 정의합니다. PART_ListBoxItem의 HorizontalAlignment, Margin 속성을 서로 반대로 정의합니다.

 

1
2
3
4
<slt:MessageStyleSelector x:Key="MessageStyleSelector" 
                          PropertyToCheck="IsMine" PropertyValue="True"
                          LeftStyle="{StaticResource Style_Message_Left}"
                          RightStyle="{StaticResource Style_Message_Right}"/>
cs

 

MessageTemplateSelector와 마찬가지로 MessageStyleSelector를 리소스에 선언합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
<!-- Style & Template Selector -->
<ListBox ItemTemplateSelector="{StaticResource MessageTemplateSelector}" 
         ItemContainerStyleSelector="{StaticResource MessageStyleSelector}" 
         Grid.Column="1">
    <ListBox.ItemsSource>
        <x:Array Type="{x:Type local:ExchangeMessage}">
            <local:ExchangeMessage Name="X Friend" Message="Charles~ R u there?" ConfirmedTime="2018-03-01 12:24:33" IsMine="False"/>
            <local:ExchangeMessage Name="Me" Message="Yeah~ i'm here. What's up?" ConfirmedTime="2018-03-01 12:25:44" IsMine="True"/>
            <local:ExchangeMessage Name="X Friend" Message="Do u have time tonight? Let's get it!" ConfirmedTime="2018-03-01 12:26:55" IsMine="False"/>
        </x:Array>
    </ListBox.ItemsSource>
</ListBox>
cs

 

ItemContainerStyleSelector속성에 셀렉터를 선언합니다.


 

실행해서 태스트해봅니다

 

이처럼 셀렉터는 하나의 컨트롤에 여러 개의 템플릿이나 여러 개의 스타일을 함께 표현할 있게 해줍니다.

 

참고 : JERRIE PELSER > 3 Techniques you can use to make your data templates dynamic