Dynamically displaying Items using FlipView and DataTemplateSelector in WinRT
I think the way to achieve what you are looking for is to expose the data in a way that better represents what you want to display. Then, you can use nested controls to display it. I just threw this together (using my own test data). It is probably not exactly what you want, but it should help you figure things out.
ViewModel
Here I made a helper method to build the collection with sub-collections that each have 3 items.
class FlipViewDemo{ private List<object> mData; public IEnumerable<object> Data { get { return mData; } } public FlipViewDemo() { mData = new List<object>(); mData.Add("Test String"); for (int i = 0; i < 18; ++i) { AddData("Test Data " + i.ToString()); } } private void AddData(object data) { List<object> current = mData.LastOrDefault() as List<object>; if (current == null || current.Count == 3) { current = new List<object>(); mData.Add(current); } current.Add(data); }}class TemplateSelector : DataTemplateSelector{ public DataTemplate ListTemplate { get; set; } public DataTemplate ObjectTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (item is List<object>) return ListTemplate; return ObjectTemplate; }}
Xaml
Here I use an ItemsControl to vertically stack the items in the data. Each item is either a list of three objects or a single object. I use a FlipView
for each of the lists of three objects and a simple ContentPresenter
for the single objects.
<Page.Resources> <DataTemplate x:Key="ListTemplate"> <FlipView ItemsSource="{Binding}"> <FlipView.ItemTemplate> <DataTemplate> <ContentPresenter Margin="0 0 10 0" Content="{Binding}" /> </DataTemplate> </FlipView.ItemTemplate> </FlipView> </DataTemplate> <DataTemplate x:Key="ObjectTemplate"> <ContentPresenter Margin="0 0 10 0" Content="{Binding}" /> </DataTemplate> <local:TemplateSelector x:Key="TemplateSelector" ListTemplate="{StaticResource ListTemplate}" ObjectTemplate="{StaticResource ObjectTemplate}" /></Page.Resources><ItemsControl ItemsSource="{Binding Data}" ItemTemplateSelector="{StaticResource TemplateSelector}" />
Note: You usually would not need a template selector for something like this, but since you need to select between a List<T>
and an Object
, there is no way I know of to recognize the difference using only the DataTemplate.TargetType
property from Xaml due to List<t>
being a generic type. (I tried {x:Type collections:List`1}
and it did not work.)
You need to group items in viewmodel, and databind ItemsSource to the groups. In flipview's itemtemplate you display items in group.
public class PageGroup : PageBase { public ObservableColection<BaseClass> Items { get; set; }}public ObservableCollection<PageBase> Pages { get; set; }
<FlipView ItemsSource="{Binding Pages}"> <FlipView.ItemTemplate> <DataTemplate DataType="local:PageGroup"> <ItemsControl ItemsSource="{Binding Items}" ItemTemplateSelector="{StaticResource MyDataTemplateSelector}" /> </DataTemplate> </FlipView.ItemTemplate> </FlipView>
In order to display first page differently from others:
public class FirstPage : PageBase { public string Title { get; }}Pages.Insert(0, new FirstPage());
and you need to use another datatemplaeselector or impicit datatemplates in FlipView to differentiate between FirstPage and PageGroup
<FlipView ItemsSource="{Binding Pages}" ItemTemplateSelector="{StaticResource PageTemplateSelector}" />
You don't need to worry about selecting the appropriate template based on the class type, you can simply define the class in the DataTemplate
itself.
<DataTemplate TargetType="{x:Type myNamespace:FirstItem}"> ...</DataTemplate>
You'll need to specify where the class is by adding the namespace at the top of your page:
xmlns:myNamespace="clr-namespace:MyApp.MyNamespace"