반응형
TypedDataTempalteSelector
WPF 프로그램을 개발하면 ItemsControl.ItemTemplate 에 DataTemplate
을 등록해서 ItemsControl.ItemSource 에 ViewModel
이 추가될 때마다 ViewModel
타입에 맞는 View
가 추가되는데, Xamarin 는 WPF 처럼 DataTemplate.DataType을 지원하지 않아 반드시 DataTemplateSelector
를 사용해야만 합니다.
문제는 DataTemplateSelector
를 ViewModel
타입에 따라 선택하게 구현하려면 아래와 같이 클린하지 않은 코드를 만들 수 밖에 없습니다.
public class MyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DataTemplateA { get; set; }
public DataTemplate DataTemplateB { get; set; }
public DataTemplate DataTemplateC { get; set; }
// 새로운 DataTemplate 이 생길 때마다 DataTemplate 속성을 추가합니다.
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if(item is ViewModelA)
return DataTemplateA;
else if(item is ViewModelB)
return DataTemplateB;
// 새로운 DataTemplate 이 생길 때마다 ViewModel을 결정해줍니다.
return null;
}
}
XAML 코드도 마찬가지로 복잡해집니다.
<DataTemplate x:Key="DataTemplateA">
<!-- ViewModelA로 연결하려는 ViewA 정의 -->
</DataTemplate>
<DataTemplate x:Key="DataTemplateB">
<!-- ViewModelB로 연결하려는 ViewB 정의 -->
</DataTemplate>
<!-- 새로운 DataTemplate 를 계속 추가합니다. -->
<MyDataTemplateSelector DataTemplateA="{StaticResource DataTemplateA}"
DataTemplateB="{StaticResource DataTemplateB}"/>
<!-- 새로운 DataTemplate 이 생길 때마다 StaticResource를 추가합니다. -->
그래서 WPF 의 DataType
처럼 XAML 코드로 타입을 지정하면 DataTemplate
이 선택되게 하는 방법을 구현하여 공유드립니다.
TypedDataTemplate
[ContentProperty(name: nameof(Template))]
public class TypedDataTemplate
{
public Type DataType { get; set; }
public DataTemplate Template { get; set; }
}
XAML 코드에서 사용할 TypedDataTemplate
클래스를 구현합니다.
TypedDataTemplateSelector
/// <summary>
/// XAML에서 정의된 DataType에 따라 DataTemplate을 선택합니다.
/// </summary>
public class TypedDataTemplateSelector : DataTemplateSelector
{
// XAML 에서 TypeDataTemplates 에 들어갈 TypeDataTemplate를 정의할 겁니다.
public IList<TypedDataTemplate> TypedDataTemplates { get; set; }
public TypedDataTemplateSelector()
{
TypedDataTemplates = new ObservableCollection<TypedDataTemplate>();
var iNotifyCollectionChanged = (INotifyCollectionChanged)TypedDataTemplates;
// TypeDataTemplates 에 새로운 TypedDataTemplate 이 추가될 때마다,
// TypeDataTemplate 이 제대로 정의되었는지 확인합니다.
iNotifyCollectionChanged.CollectionChanged += OnTypedDataTemplatesChanged;
}
protected virtual void OnTypedDataTemplatesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// XAML 에서 추가한 TypedDataTemplate 설정이 올바른지 검증합니다.
var newTypedDataTemplates = e?.NewItems.Cast<TypedDataTemplate>();
foreach (var newTypedDataTemplate in newTypedDataTemplates)
{
if (newTypedDataTemplate.DataType == null)
{
throw new InvalidOperationException($"ViewModelType 이 지정되지 않아서, ViewModel과 연결할 수 없습니다. ViewModelType을 지정해주세요.");
}
if (newTypedDataTemplate.Template == null)
{
throw new InvalidOperationException($"{newTypedDataTemplate.DataType}과 연결할 DataTemplate이 지정되지 않았습니다. DataTemplate을 지정해주세요.");
}
}
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item == null) return null;
if(TypedDataTemplates.Count < 1)
{
throw new NotImplementedException("TypedDataTemplateSelector에 사용할 수 있는 TypedDataTemplate이 없습니다.");
}
// item 타입에 맞는 DataTemplate을 찾습니다.
var appropriateDataTemplate = TypedDataTemplates.FirstOrDefault(typedDataTemplate =>
{
return typedDataTemplate.DataType.IsAssignableFrom(item.GetType());
});
if(appropriateDataTemplate == null)
{
throw new NotImplementedException($"{item.GetType()}과 알치하는 TypedDataTemplate을 찾을 수 없습니다. TypedDataTemplate을 추가해주세요.");
}
return appropriateDataTemplate.Template;
}
}
XAML
<TypedDataTemplateSelector x:Key="LayerDataTemplateSelector">
<TypedDataTemplateSelector.TypedDataTemplates>
<TypedDataTemplate DataType="{x:Type ViewModelA}">
<DataTemplate>
<!-- ViewModelA로 연결하려는 ViewA 정의 -->
</DataTemplate>
</TypedDataTemplate>
<TypedDataTemplate DataType="{x:Type ViewModelB}">
<DataTemplate>
<!-- ViewModelB로 연결하려는 ViewB 정의 -->
</DataTemplate>
</TypedDataTemplate>
<!-- 새로운 DataTemplate 이 생길 때마다 TypedDataTemplate 만 추가합니다. -->
</TypedDataTemplateSelector.TypedDataTemplates>
</TypedDataTemplateSelector>
이제 XAML 에서 TypedDataTemplate
을 추가하고 DataType
만 지정하면, TypedDataTemplateSelector
가 DataType
에 따라 DataTemplate
을 선택합니다.
반응형
'Develop > MAUI 가이드' 카테고리의 다른 글
[Xamarin] 성능 개선 - Compiled Binding (0) | 2020.08.06 |
---|---|
[Xamarin] 성능 개선 - XAML 컴파일 (0) | 2020.08.06 |
[Xamarin] MvvmCross 데이터 바인딩 (0) | 2020.06.17 |
[Xamarin] Xamarin 프로젝트에서 MvvmCross 사용하기 (0) | 2020.06.13 |
[Xamarin] MvvmCross 소개 (0) | 2020.06.13 |
꾸준히 노력하는 개발자 "김예건" 입니다.