Класс форм xamarin DataTemplate
получает параметр с Type
в ctor.
public class DataTemplate : ElementTemplate, IDataTemplateController
{
public DataTemplate(Type type);
...
}
Как передать тип определенного класса в ctor в XAML? В c # я бы написал new DataTemplate(typeof(DeviceViewModel))
. Но я должен написать это на XAML.
Псевдокод:
<DataTemplate>
<x:Arguments>
<typeof(viewModels:DeviceViewModel)/>
</x:Arguments>
<myControls:MyCustomControl/>
</DataTemplate>
EDIT
Чтобы прояснить свои цели, я создал производный пример. Допустим, есть следующая структура:
- Изображение
- Музыка
- Документ
Мой список содержит эти элементы. Каждый из этого типа должен обрабатываться в собственном DataTemplate
. В моем случае элементы довольно сложны, поэтому я создаю ViewModel для каждого элемента. В коде это может выглядеть так:
public abstract class BaseViewModel
public class PictureViewModel : BaseViewModel
public class MusicViewModel : BaseViewModel
public class DocumentViewModel : BaseViewModel
/* My List full of different ViewModels*/
List<BaseViewModel> itemList;
Теперь я создаю TemplateSelector
, который содержит другие TemplateSelector
. Он вызывает правильную модель в зависимости от типа модели представления:
using System;
using Xamarin.Forms;
using MyApp.ViewModels;
namespace MyApp.TemplateSelectors
{
public class MyItemTemplateSelector : DataTemplateSelector
{
public DataTemplateSelector PictureTemplateSelector { get; set; }
public DataTemplateSelector MusicTemplateSelector { get; set; }
public DataTemplateSelector DocumentTemplateSelector { get; set; }
public DataTemplateSelector DefaultTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
switch (item)
{
case PictureViewModel vm:
return PictureTemplateSelector.SelectTemplate(item, container);
case MusicViewModel vm:
return MusicTemplateSelector.SelectTemplate(item, container);
case DocumentViewModel vm:
return DocumentTemplateSelector.SelectTemplate(item, container);
default:
return DefaultTemplate.SelectTemplate(item, container);
}
}
}
}
В XAML все назначения выполняются:
<DataTemplate x:Key="PictureDefaultTemplate">
<ViewCell>
<Image Source="{Binding FilePath}"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="MusicDefaultTemplate">
<ViewCell>
<Button Text="Play this!"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="DocumentDefaultTemplate">
<ViewCell>
<Label Text="show filename at least"/>
</ViewCell>
</DataTemplate>
<!-- The DocumentTemplateSelector handles file extensions differently -->
<DataTemplate x:Key="MyTxtTemplate">
<ViewCell>
<Label Text="This is a text file"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="MyPdfTemplate">
<ViewCell>
<Label Text="This is a pdf file"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="MyXmlTemplate">
<ViewCell>
<Label Text="This is a xml File"/>
</ViewCell>
</DataTemplate>
<!--provide specific template selectors with initiated datatemplates-->
<templateSelectors:PictureTemplateSelector x:Key="pictureTemplateSelector" DefaultTemplate="{StaticResource PictureDefaultTemplate}"/>
<templateSelectors:MusicTemplateSelector x:Key="musicTemplateSelector" DefaultTemplate="{StaticResource MusicDefaultTemplate}"/>
<templateSelectors:DocumentTemplateSelector x:Key="documentTemplateSelector" DefaultTemplate="{StaticResource DocumentDefaultTemplate}"
TxtTemplate="{StaticResource MyTxtTemplate}"
PdfTemplate="{StaticResource MyPdfTemplate}"
XmlTemplate="{StaticResource MyXmlTemplate}"/>
<!--provide superior template selector with other template selectors -->
<templateSelectors:MyItemTemplateSelector x:Key="myItemTemplateSelector"
PictureTemplateSelector="{StaticResource pictureTemplateSelector}"
MusicTemplateSelector="{StaticResource musicTemplateSelector}"
DocumentTemplateSelector="{StaticResource documentTemplateSelector}"/>
Последнее связывание MyItems (объекты типа BaseViewModel
) и установка улучшенного селектора шаблона. Здесь я установил CachingStrategy
на RecycleElementAndDataTemplate
:
<ListView ItemsSource="{Binding MyItems}"
ItemTemplate="{StaticResource myItemTemplateSelector}"
IsPullToRefreshEnabled="True"
CachingStrategy="RecycleElementAndDataTemplate"/>
Исключение выдается в DocumentTemplateSelector.
using System;
using Xamarin.Forms;
using MyApp.ViewModels;
namespace MyApp.TemplateSelectors
{
public class DocumentTemplateSelector : DataTemplateSelector
{
public DataTemplate TxtTemplate { get; set; }
public DataTemplate PdfTemplate { get; set; }
public DataTemplate XmlTemplate { get; set; }
public DataTemplate DefaultTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var doc = (DocumentViewModel)item;
switch (doc.FileExtension)
{
case "txt":
return TxtTemplate; // Exception
case "pdf":
return PdfTemplate; // Exception
case "xml":
return XmlTemplate; // Exception
default:
return DefaultTemplate; // Exception
}
}
}
}
Выдается следующее исключение:
System.NotSupportedException: RecycleElementAndDataTemplate требует, чтобы DataTemplate активировался, когда ctor принимает тип.
@ IvanIčin @ G.hakim Меня не беспокоит, что механизм по умолчанию не работает, но после изучения кода форм xamarin из github я не вижу другого решения, чтобы заставить его работать без передачи типа в DataTemplate
ctor.