티스토리 뷰
2022.09.06 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내v1.0 part9-2 StyleSelector
2022.08.31 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part9-1 DataTemplateSelector
2022.08.08 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-3 Template
2022.08.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-2 Template
2022.07.21 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-1 Template
2022.07.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part7 Behavior
2022.07.05 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part6 Command
2022.06.27 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part5 Converter
2022.06.15 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-2 Data Binding
2022.06.13 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part4-1 Data Binding
2022.06.07 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-3
2022.06.02 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-2
2022.05.30 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 V1.0 part3-1
2022.05.11 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part2
2022.05.09 - [WPF .NET] - MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part1
1. DataTemplateSelector Overview
데이터 객체 및 데이터 바인딩된 요소를 기반으로 DataTemplate를 선택하는 방법을 제공하는 컨트롤입니다.
더 자세한 사항은 여기를 참고합니다.
예제를 이용해서 빠르게 살펴보도록 하겠습니다.
MainWindow.xaml
리스트 박스 한개와 DataTemplate 한개를 추가합니다.
<DataTemplate x:Key="MyDataTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.RowSpan="2" Content="{StaticResource My}" />
<TextBlock Grid.Column="1" Text="{Binding Message}" />
<TextBlock
Grid.Row="1"
Grid.Column="1"
Text="{Binding CreateAt, StringFormat={}{0:t}}" />
</Grid>
</DataTemplate>
<ListBox
x:Name="NormalMessageList"
ItemTemplate="{StaticResource MyDataTemplate}"
ItemsSource="{Binding Messages}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
MessageModel.cs
셈플 모델입니다.
public class MessageModel
{
public int Id { get; set; }
public string MessageType { get; set; }
public string Message { get; set; }
public DateTime CreateAt { get; set; } = DateTime.Now;
}
MainViewModel.cs
MessageModel을 이용해서 셈플 데이터를 생성합니다.
생성된 데이터를 Messages 프로퍼티에 입력합니다.
public class MainViewModel : ObservableObject
{
private IList<MessageModel> _messages = new ObservableCollection<MessageModel>();
/// <summary>
/// 메시지 목록
/// </summary>
public IList<MessageModel> Messages
{
get { return _messages; }
set { SetProperty(ref _messages, value); }
}
public MainViewModel()
{
Messages = new ObservableCollection<MessageModel>
{
new MessageModel{ Id = 1, MessageType = "System", Message = "Start message" },
new MessageModel{ Id = 2, MessageType = "Me", Message = "Hello", CreateAt = DateTime.Now.AddMinutes(1) },
new MessageModel{ Id = 3, MessageType = "Bot", Message = "How can I help you?", CreateAt = DateTime.Now.AddMinutes(1) },
new MessageModel{ Id = 4, MessageType = "Me", Message = "Sing a song", CreateAt = DateTime.Now.AddMinutes(1) },
new MessageModel{ Id = 5, MessageType = "System", Message = "Please wait for a moment" , CreateAt = DateTime.Now.AddMinutes(60)},
new MessageModel{ Id = 6, MessageType = "Bot", Message = "I can't sing" , CreateAt = DateTime.Now.AddMinutes(60)},
new MessageModel{ Id = 7, MessageType = "Me", Message = "Quit" , CreateAt = DateTime.Now.AddMinutes(1)},
new MessageModel{ Id = 8, MessageType = "System", Message = "End message" , CreateAt = DateTime.Now.AddMinutes(1)},
};
}
}
기본 실행 화면
기본적으로 ListBox컨트롤은 1개의 DataTemplate만을 사용할 수 있습니다.
그런데, DataTemplateSelector은 Data 유형 혹은 Data의 내용을 이용해서 여러개의 DataTemplate을 사용할 수 있도록 지원합니다.
여기에서는 MessageType 프로퍼티의 값을 이용해서 3개의 DataTemplate를 어떻게 사용하는지 알아 보도록 하겠습니다.
2. MessageDataTemplateSelector 생성
- DataTemplateSelector를 상속 받은 클래스를 생성합니다.
- SelectTemplate 메소드를 override합니다.
- 내부에 로직을 구현합니다.
- 반환할 DataTemplate들은 미리 추가해 놓습니다.
/// <summary>
/// Message DataTemplateSelector - 반드시 DataTemplateSelector를 상속 받습니다.
/// </summary>
public class MessageDataTemplateSelector : DataTemplateSelector
{
public DataTemplate MyDataTemaplte { get; set; }
public DataTemplate BotDataTemplate { get; set; }
public DataTemplate SystemDataTemplate { get; set; }
/// <summary>
/// 템플릿 선택용 로직 실행 메소드 - 반드시 override합니다.
/// </summary>
/// <param name="item"></param>
/// <param name="container"></param>
/// <returns></returns>
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
//item을 MessageModel인지 확인합니다.
if (item is MessageModel message)
{
//MessageType에 따라서 DataTemplate를 각각 반환합니다.
switch(message.MessageType)
{
case "Me":
return MyDataTemaplte;
case "Bot":
return BotDataTemplate;
case "System":
return SystemDataTemplate;
}
}
return base.SelectTemplate(item, container);
}
}
3. MessageDataTemplateSelector 인스턴스 생성
- MyDataTemplate은 이미 만들어져있는 템플릿을 사용했습니다.
- BotDataTemplate와 SystemDataTemplate는 아래와 같이 구현했습니다.
<local:MessageDataTemplateSelector x:Key="MessageDataTemplateSelector" MyDataTemaplte="{StaticResource MyDataTemplate}">
<local:MessageDataTemplateSelector.BotDataTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.RowSpan="2" Content="{StaticResource Bot}" />
<Border
Grid.Column="1"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="5">
<TextBlock Margin="5" Text="{Binding Message}" />
</Border>
<TextBlock
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Right"
Text="{Binding CreateAt, StringFormat={}{0:t}}" />
</Grid>
</DataTemplate>
</local:MessageDataTemplateSelector.BotDataTemplate>
<local:MessageDataTemplateSelector.SystemDataTemplate>
<DataTemplate>
<Border
Background="LightGray"
BorderBrush="LightGray"
BorderThickness="1"
CornerRadius="5">
<Grid HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl
Grid.RowSpan="2"
VerticalAlignment="Center"
Content="{StaticResource System}" />
<StackPanel
Grid.Column="1"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock Text="{Binding CreateAt, StringFormat={}{0:G}}" />
<TextBlock Margin="10,0,0,0" Text="{Binding Message}" />
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</local:MessageDataTemplateSelector.SystemDataTemplate>
</local:MessageDataTemplateSelector>
4. MessageDataTemplateSelector 사용
- ItemTemplateSelector를 사용할때는 ItemTemplate를 사용할 수 없습니다.
<ListBox
x:Name="SelectorMessageList"
Grid.Column="1"
ItemTemplateSelector="{StaticResource MessageDataTemplateSelector}"
ItemsSource="{Binding Messages}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
MessageDataTemplateSelector 사용 결과
5. 소스
항상 질문은 환영 입니다~
6. 추가 사항
DataTemplate 내부에서 이벤트가 발생했을 때 Command를 실행하는 부분을 소스에 추가했습니다.
우선 Behavior가 필요하기 때문에 Microsoft.Xaml.Behaviors.Wpf nuget package를 추가했고, 아래와 같이 수정했습니다.
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
이렇게 사용하니 디자인 타임에 아래 오류가 발생하네요;;
System.Windows.Markup.XamlParseException: ''Cannot set unknown member '{http://schemas.microsoft.com/xaml/behaviors}Interaction.Triggers'.' Line number 'xx' and line position 'xx'.'
xmlns:b="clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors"
이렇게 바꾸워서 사용하면 디자인 타임에 잘 보입니다.
TextBlock에 MouseLeftButtonDown 이벤트를 뷰모델의 ClickCommand와 연결 시켰습니다.
MainWindow.xaml
<TextBlock Grid.Column="1" Text="{Binding Message}">
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseLeftButtonDown">
<b:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext.ClickCommand}" CommandParameter="My" />
</b:EventTrigger>
</b:Interaction.Triggers>
</TextBlock>
MainViewModel.cs
/// <summary>
/// 클릭 커맨드
/// </summary>
public ICommand ClickCommand { get; set; }
public MainViewModel()
{
//커맨드 생성
ClickCommand = new RelayCommand<string>(OnClick);
}
private void OnClick(string para)
{
_ = MessageBox.Show($"Clicked message on {para}");
}
WpfTest/SelectorSample at master · kaki104/WpfTest (github.com)
'WPF .NET' 카테고리의 다른 글
사용자 정의 컨트롤 만들기 Custom XAML Control - part1 (0) | 2022.10.06 |
---|---|
MVVM Pattern을 사용하는 개발자를 위한 안내v1.0 part9-2 StyleSelector (0) | 2022.09.06 |
MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-3 Template (0) | 2022.08.08 |
MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-2 Template (2) | 2022.08.02 |
MVVM Pattern을 사용하는 개발자를 위한 안내 v1.0 part8-1 Template (0) | 2022.07.21 |
- Total
- Today
- Yesterday
- PRISM
- XAML
- IOT
- ef core
- uno-platform
- Cross-platform
- C#
- Bot Framework
- LINQ
- Microsoft
- kiosk
- #MVVM
- ComboBox
- #Windows Template Studio
- Windows 10
- uno platform
- windows 11
- #uwp
- Behavior
- visual studio 2019
- Build 2016
- .net
- UWP
- #prism
- WPF
- Visual Studio 2022
- .net 5.0
- Always Encrypted
- MVVM
- dotNETconf
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |