How to do xaml template like Bing app for windows 8? - c#

The standard GridApp template is as follows:
Variable Sized Grouped GridView template is as follows:
How to make a template for your application, so that it looks like this:
For example, this design in all applications Bing for windows 8:
Code for Variable Sized Grouped GridView template:
<UserControl.Resources>
<!-- Collection of grouped items displayed by this page -->
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"
ItemsPath="Items"
d:Source="{Binding ItemGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>
<DataTemplate x:Key="CustomTileItem">
<Grid >
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding Image}" Stretch="UniformToFill"/>
</Border>
<StackPanel VerticalAlignment="Bottom" >
<TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="30" Margin="15,0,15,0"/>
<TextBlock Text="{Binding Subtitle}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>
</UserControl.Resources>
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Grid.Column="1" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
<!-- Horizontal scrolling grid used in most view states -->
<ScrollViewer
x:Name="itemGridScrollViewer"
AutomationProperties.AutomationId="ItemGridScrollViewer"
Grid.Row="1"
Margin="0,-3,0,0"
Style="{StaticResource HorizontalScrollViewerStyle}">
<local:MyGridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Margin="116,0,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource CustomTileItem}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<local:MyGridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</local:MyGridView.ItemsPanel>
<local:MyGridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="1,0,0,6">
<Button
AutomationProperties.Name="Group Title"
Content="{Binding Title}"
Click="Header_Click"
Style="{StaticResource TextButtonStyle}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid ItemWidth="75" ItemHeight="150" Orientation="Vertical" Margin="0,0,80,0" MaximumRowsOrColumns="3"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</local:MyGridView.GroupStyle>
</local:MyGridView>
</ScrollViewer>
and:
public class MyGridView : GridView
{
private int rowVal;
private int colVal;
private Random _rand;
private List<Size> _sequence;
public MyGridView()
{
_rand = new Random();
_sequence = new List<Size> {
LayoutSizes.PrimaryItem,
LayoutSizes.SecondarySmallItem, LayoutSizes.SecondarySmallItem,
LayoutSizes.SecondarySmallItem,
LayoutSizes.SecondaryTallItem,
LayoutSizes.OtherSmallItem, LayoutSizes.OtherSmallItem, LayoutSizes.OtherSmallItem
};
}
protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
SampleDataItem dataItem = item as SampleDataItem;
int index = -1;
if (dataItem != null)
{
index = dataItem.Group.Items.IndexOf(dataItem);
}
if (index >= 0 && index < _sequence.Count)
{
colVal = (int)_sequence[index].Width;
rowVal = (int)_sequence[index].Height;
}
else
{
colVal = (int)LayoutSizes.OtherSmallItem.Width;
rowVal = (int)LayoutSizes.OtherSmallItem.Height;
}
VariableSizedWrapGrid.SetRowSpan(element as UIElement, rowVal);
VariableSizedWrapGrid.SetColumnSpan(element as UIElement, colVal);
}
}
public static class LayoutSizes
{
public static Size PrimaryItem = new Size(6, 2);
public static Size SecondarySmallItem = new Size(3, 1);
public static Size SecondaryTallItem = new Size(3, 2);
public static Size OtherSmallItem = new Size(2, 1);
}
For example with "Variable Sized Grouped GridView template", we can combine the rows or columns, and how to set the first element height = "auto", and all other elements that have different widths and heights, but grouped as "Variable Sized Grouped GridView template"?

View this post:
http://blogs.msdn.com/b/synergist/archive/2012/09/25/windows-store-app-xaml-gridview-with-variable-templates.aspx
I think this is what you need.

Related

How to add multiple elements to the wrappanel?

I am trying to insert several StackPanel inside the WrapPanel as you can see the XAML below:
Only the TextBlock inside the StackPanel will be modified so as not to repeat the Title and Text.
<Window x:Class="ambient_test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ambient_test"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ScrollViewer CanContentScroll="True">
<WrapPanel x:Name="wrappanel">
<StackPanel x:Name="panel1" Width="120" Margin="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Background="#FF38C59F"></StackPanel>
<TextBlock Grid.Row="2" Text="Title 1" Foreground="LightGray" VerticalAlignment="Top" TextAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Text 1" Foreground="#FF747474" TextAlignment="Center" Margin="0 15 0 0"/>
</Grid>
</StackPanel>
<StackPanel x:Name="panel2" Width="120" Margin="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Background="#FF38C59F"></StackPanel>
<TextBlock Grid.Row="2" Text="Title 2" Foreground="LightGray" VerticalAlignment="Top" TextAlignment="Center"/>
<TextBlock Grid.Row="1" Text="Text 2" Foreground="#FF747474" TextAlignment="Center" Margin="0 15 0 0"/>
</Grid>
</StackPanel>
</WrapPanel>
</ScrollViewer>
</Grid>
</Window>
I created a class called Info to change the Title and the Text. In the method constructor I have a for loop that will add 10 contents to the List.
public MainWindow()
{
InitializeComponent();
List<Info> infos = new List<Info>();
for (int i = 0; i < 10; i++)
{
infos.Add(new Info()
{
Title = $"title {i}",
Text = $"text {i}"
});
}
}
public class Info
{
public string Title { get; set; }
public string Text { get; set; }
}
For example, my List has 100 records, so I need to add 100 StackPanel inside my WrapPanel following the same Title and Text as the List.
Is there any way to do this? For example using Binding?
You would use an ItemsControl that uses a WrapPanel as its ItemsPanel, and defines the layout of the items by an appropriate DataTemplate:
<ItemsControl x:Name="itemsControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Title}" .../>
<TextBlock Grid.Row="1" Text="{Binding Text}" .../>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and assign the List<Info> to its ItemsSource property:
itemsControl.ItemsSource = infos;

Image Gallery with Flipview

I want to create a gallery image on the first page contains a thumbnail for that category and when thumbnail is selected, it will open the image and description of the selected image in flipview (can be swipe to the right and to the left when thumbnail is selected for the image before and after). I have difficulties when applying it into flipview.
Code:
MainPage XAML
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="3"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick" Background="#FF6996D1" >
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="240" Height="180">
<Border>
<Image Source="{Binding ImagePath}" Stretch="Uniform" AutomationProperties.Name="{Binding Title}"/>
</Border>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid GroupPadding="0,0,70,0"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
MainPage:
public MainPage()
{
this.InitializeComponent();
Gallery();
}
private async void Gallery()
{
var sampleDataGroups = await DataItemSource.GetGroupsAsync();
this.DefaultViewModel["Groups"] = sampleDataGroups;
}
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
// Navigate to the appropriate destination page, configuring the new page
// by passing required information as a navigation parameter
var itemId = ((SampleDataItem)e.ClickedItem).UniqueId;
this.Frame.Navigate(typeof(ItemDetailPage), itemId);
}
ItemDetailPage XAML:
<Grid Grid.Row="1" x:Name="contentRegion" Background="#FF6996D1">
<Image Source="{Binding ImagePath}" HorizontalAlignment="Left" Height="559" Margin="84,20,0,49" VerticalAlignment="Center" Width="732"/>
<ScrollViewer x:Name="myScroll" VerticalScrollBarVisibility="Auto" Margin="852,60,50,91" VerticalScrollMode="Auto" HorizontalScrollBarVisibility="Auto">
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" Height="2210" Width="425" FontSize="27" TextAlignment="Justify" />
</ScrollViewer>
</Grid>
ItemDetailPage Code:
public ItemDetailPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += navigationHelper_LoadState;
}
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var item = await DataItemSource.GetItemAsync((String)e.NavigationParameter);
this.DefaultViewModel["Item"] = item;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
navigationHelper.OnNavigatedTo(e);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
navigationHelper.OnNavigatedFrom(e);
}
How do I apply flipview on ItemDetailPage?
Note:
For more code detail you can view the sample
To apply flipview on ItemDetailPage, we can add FlipView under "contentRegion" and set the Image and ScrollViewer as FlipView's ItemTemplate like following:
<Grid x:Name="contentRegion" Grid.Row="1" Background="#FF6996D1">
<FlipView ItemsSource="{Binding Group.Items}" SelectedItem="{Binding Item, Mode=TwoWay}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Width="732"
Height="559"
Margin="84,20,0,49"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Source="{Binding ImagePath}" />
<ScrollViewer x:Name="myScroll"
Margin="852,60,50,91"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
VerticalScrollMode="Auto">
<TextBlock Width="425"
Height="2210"
FontSize="27"
Text="{Binding Description}"
TextAlignment="Justify"
TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
And in code-behind, set the data source like following:
private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var item = await DataItemSource.GetItemAsync((String)e.NavigationParameter);
var group = await DataItemSource.GetGroupByItemAsync(item);
this.DefaultViewModel["Group"] = group;
this.DefaultViewModel["Item"] = item;
}
Here I add a GetGroupByItemAsync(SampleDataItem item) method in DataItemSource which can retrieve the group according to the item.
public static async Task<SampleDataGroup> GetGroupByItemAsync(SampleDataItem item)
{
await _DataItemSource.GetSampleDataAsync();
// Simple linear search is acceptable for small data sets
var matches = _DataItemSource.Groups.Where(group => group.Items.Contains(item));
if (matches.Count() == 1) return matches.First();
return null;
}
Besides these, we also need to remove DataContext="{Binding Item}" form root Grid and put in in <Grid Background="#FF6996D1" DataContext="{Binding Item}">.
After this, the FlipView should be able to work. However here is a strange behavior, if we select the second or third image, the previous image in flip view won't show like following
We are investigating on this issue. As a workaround, we can disable FlipView's virtualization by changing its ItemsPanel like:
<FlipView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</FlipView.ItemsPanel>
The complete XAML code of ItemDetailPage might like:
<Page x:Class="ImageGalerry.ItemDetailPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="using:ImageGalerry.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="using:ImageGalerry.Data"
xmlns:local="using:ImageGalerry"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding DefaultViewModel,
RelativeSource={RelativeSource Self}}"
mc:Ignorable="d">
<Grid d:DataContext="{Binding Groups[0].Items[0], Source={d:DesignData Source=/DataModel/DataItem.json, Type=data:DataItemSource}}" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid Background="#FF6996D1" DataContext="{Binding Item}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1366" />
</Grid.ColumnDefinitions>
<Button x:Name="backButton"
Margin="39,59,0,0"
VerticalAlignment="Top"
AutomationProperties.AutomationId="BackButton"
AutomationProperties.ItemType="Navigation Button"
AutomationProperties.Name="Back"
Command="{Binding NavigationHelper.GoBackCommand,
ElementName=pageRoot}"
Style="{StaticResource NavigationBackButtonNormalStyle}" />
<TextBlock x:Name="pageTitle"
Margin="120,40,30,40"
VerticalAlignment="Top"
IsHitTestVisible="false"
Style="{StaticResource HeaderTextBlockStyle}"
Text="{Binding Title}"
TextWrapping="NoWrap" />
<!--<MediaElement x:Name="mediaplayer" Source="images/ost.mp3" AudioCategory="BackgroundCapableMedia" />
<Button x:Name="PlayButton" Content="Stop" Click="PlayButton_Click" Margin="1274,72,0,30" />-->
</Grid>
<Grid x:Name="contentRegion" Grid.Row="1" Background="#FF6996D1">
<FlipView ItemsSource="{Binding Group.Items}" SelectedItem="{Binding Item, Mode=TwoWay}">
<FlipView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</FlipView.ItemsPanel>
<FlipView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Width="732"
Height="559"
Margin="84,20,0,49"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Source="{Binding ImagePath}" />
<ScrollViewer x:Name="myScroll"
Margin="852,60,50,91"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
VerticalScrollMode="Auto">
<TextBlock Width="425"
Height="2210"
FontSize="27"
Text="{Binding Description}"
TextAlignment="Justify"
TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Grid>
</Grid>
</Page>
Please note that disabling UI virtualization for FlipView may negatively impact performance especially when there are a lot of images. If you have a lot of images, you can try to use incremental loading and data virtualization.

Windows Phone 8.1 Listview unique first and last item template

Last year I made an app for Windows Phone 8, containing a LongListSelector with a unique first and last item template, as described here:
LongListSelector different item template for first and last item
I recently updated the app to Windows Phone 8.1 Store and this functionality broke. Here's my class (the only difference from the post being, that I'm using a ListView instead of a LongListSelector for Windows Phone 8.1 Store, since LongListSelector is not a part of the Windows Phone 8.1 Store framework):
public abstract class TemplateSelector : ContentControl
{
public abstract DataTemplate SelectTemplate(object item, int index, int totalCount, DependencyObject container);
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
var parent = GetParentByType<ListView>(this);
var index = (parent.ItemsSource as IList).IndexOf(newContent);
var totalCount = (parent.ItemsSource as IList).Count;
ContentTemplate = SelectTemplate(newContent, index, totalCount, this);
}
private static T GetParentByType<T>(DependencyObject element) where T : FrameworkElement
{
T result = null;
DependencyObject parent = VisualTreeHelper.GetParent(element);
while (parent != null)
{
result = parent as T;
if (result != null)
{
return result;
}
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
}
The problem is that this:
DependencyObject parent = VisualTreeHelper.GetParent(element);
of the GetParentByType function returns null for some reason. Anyone knows why or have an alternative solution?
Below is my XAML code(with a few xmlns's removed). The DataTrigger is there because sometimes a unique first item template is enough (controlled by the LoadMore property of the ViewModel, which is a bool).
<controls:WP81Page
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<controls:WP81Page.Resources>
<DataTemplate x:Key="first">
<Grid HorizontalAlignment="Left" Width="Auto" Height="200">
<Border BorderThickness="1" BorderBrush="Black" Visibility="{Binding NoLargeImage, Converter={StaticResource BoolToVisibilityConverter}}" >
<Image Source="/Images/default-image.png" Stretch="UniformToFill" />
</Border>
<Border BorderThickness="1" BorderBrush="Black" Visibility="{Binding NoLargeImage, Converter={StaticResource BoolToVisibilityConverterReverse}}" >
<Image Source="{Binding LargeImageUrl}" Stretch="UniformToFill" />
</Border>
<StackPanel VerticalAlignment="Bottom" Background="#7F000000" >
<TextBlock Text="{Binding Header}" VerticalAlignment="Center" TextWrapping="Wrap" Foreground="White" FontWeight="Bold" Margin="15,0,15,15"/>
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="default">
<StackPanel Orientation="Horizontal" Margin="0,10,0,0" Height="105" Width="Auto">
<Border BorderThickness="1" BorderBrush="Black" Margin="0,2" Visibility="{Binding NoSmallImage, Converter={StaticResource BoolToVisibilityConverter}}" >
<Image Source="/Images/default-image.png" Width="130" Height="100" Stretch="UniformToFill" />
</Border>
<Border BorderThickness="1" BorderBrush="Black" Margin="0,2" Visibility="{Binding NoSmallImage, Converter={StaticResource BoolToVisibilityConverterReverse}}">
<Image Source="{Binding SmallImageUrl}" Width="130" Height="100" Stretch="UniformToFill"/>
</Border>
<StackPanel Orientation="Vertical" Width="300" Margin="8,0,0,0">
<TextBlock Text="{Binding Header}" TextWrapping="Wrap" FontWeight="Bold" />
<TextBlock Margin="0,3,0,0" Text="{Binding DisplayDate}" TextWrapping="Wrap" Foreground="#FFB9B9B9" FontSize="16" />
</StackPanel>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="last">
<TextBlock Text="hent flere nyheder" FontSize="25" Margin="0,20" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center" Height="75" />
</DataTemplate>
<DataTemplate x:Key="UniqueFirstTemplateSelector">
<common:UniqueFirstTemplateSelector Content="{Binding}" First="{StaticResource first}" Default="{StaticResource default}" HorizontalAlignment="Stretch"/>
</DataTemplate>
<DataTemplate x:Key="UniqueFirstAndLastTemplateSelector">
<common:UniqueFirstAndLastTemplateSelector Content="{Binding}" First="{StaticResource first}" Default="{StaticResource default}" Last="{StaticResource last}" HorizontalAlignment="Stretch"/>
</DataTemplate>
</controls:WP81Page.Resources>
<controls:WP81Page.DataContext>
<viewModels:NewsViewModel/>
</controls:WP81Page.DataContext>
<Grid x:Name="LayoutRoot" Style="{Binding Source={StaticResource Background}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ProgressBar Grid.Row="0" VerticalAlignment="Top" IsIndeterminate="True" Background="Transparent" Foreground="White" Visibility="{Binding IsLoading, Converter={StaticResource BoolToVisibilityConverter}}" />
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="NYHEDER" FontSize="35" FontWeight="Bold" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1">
<controls:WP81ListView x:Name="listSelector" Margin="22,0" Grid.Row="2" ItemsSource="{Binding News}" Command="{Binding NewsEntrySelectedCommand}" >
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{Binding LoadMore}" Value="True">
<core:ChangePropertyAction TargetObject="{Binding ElementName=listSelector}"
Value="{StaticResource UniqueFirstAndLastTemplateSelector}"
PropertyName="ItemTemplate" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{Binding LoadMore}" Value="False">
<core:ChangePropertyAction TargetObject="{Binding ElementName=listSelector}"
Value="{StaticResource UniqueFirstTemplateSelector}"
PropertyName="ItemTemplate" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</controls:WP81ListView>
</Grid>
</Grid>
</controls:WP81Page>
Thank you in advance.
EDIT
Alright, so what I want is not for the first and last item to be unique all the time. I'm making a news feed where the last item is only unique when there are more news entries to load (when the last item are clicked, more news entries are added to the ListView). If however, the end of the news entries are reached, the last item must not be unique (hence the combination with interactivity).
ListView has a property called ItemTemplateSelector which accepts objects based on DataTemplateSelector. So you need to change a couple of things to get it to work.
First of all, the definition of your template selector. It needs to be based on DataTemplateSelector and override method called SelectTemplateCore. It takes an object which is a ListViewItem. At that point you can go up the VisualTree to get the ListView and choose the DataTemplate based on index.
public class MyTemplateSelector : DataTemplateSelector
{
public DataTemplate First { get; set; }
public DataTemplate Default { get; set; }
public DataTemplate Last { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var listViewItem = container as ListViewItem;
var listView = GetParentByType<ListView>(listViewItem);
var index = (listView.ItemsSource as IList).IndexOf(item);
var totalCount = (listView.ItemsSource as IList).Count;
if (index == 0)
return First;
else if (index == totalCount - 1)
return Last;
else
return Default;
}
private T GetParentByType<T>(DependencyObject element) where T : FrameworkElement
{
T result = null;
DependencyObject parent = VisualTreeHelper.GetParent(element);
while (parent != null)
{
result = parent as T;
if (result != null)
{
return result;
}
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
}
Then, you need to create an instance of it in static resources
<local:MyTemplateSelector x:Key="SelectingTemplate"
First="{StaticResource first}"
Default="{StaticResource default}"
Last="{StaticResource last}" />
with the First, Default and Last DataTemplates, just like you did before.
The last step is to apply it to the ListView you're using.
<ListView ItemsSource="{Binding SomeItemsSource}"
ItemTemplateSelector="{StaticResource SelectingTemplate}" />
And that's it!

Binding ObservableCollection of List

In my Windows Phone application I have a listBox with ContentItems binding :
private ObservableCollection<ContentItemViewModel> _contentItems;
public ObservableCollection<ContentItemViewModel> ContentItems
{
get { return _contentItems; }
}
<ListBox x:Name="ContentListBox" Margin="0,117,12,0" VirtualizingStackPanel.VirtualizationMode="Standard" Logic1:TiltEffect.IsTiltEnabled="True" ItemsSource="{Binding ContentItems}" Tap="ContentListBox_Tap" MinHeight="656" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="vertical" >
<Grid Height="{Binding ItemHeight}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" x:Name="itemIco1" Width="Auto" Height="Auto" HorizontalAlignment="Left" Source="{Binding IconURL}" Stretch="Fill" CacheMode="BitmapCache" VerticalAlignment="Top" Margin="5,5,5,5" Visibility="Visible"/>
<ListBox IsHitTestVisible="False" Grid.Column="1" VerticalAlignment="Center" >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<TextBlock x:Name="ContentCategoryTitle" Height="70" Text="{Binding ContentTitle}" Width="460" Margin="5,34,0,0" TextTrimming="WordEllipsis" TextWrapping="NoWrap" FontSize="28" FontFamily="Segoe WP Semibold" Foreground="#FFF7F7F7" VerticalAlignment="Bottom" />
</ListBox>
</Grid>
<Rectangle Fill="#FF585858" Height="1" Margin="0,0,0,0" Width="460" VerticalAlignment="Bottom" HorizontalAlignment="Left" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Is it possible to binding not an ObservableCollection<ContentItemViewModel>, but - ObservableCollection<List<ContentItemViewModel>> ?
Yes that is possible, if you have a collection of collections. Or why not this?
ObservableCollection<ObservableCollection<ContentItemViewModel>>
If you want your UI to be notified of collection changes to your sub collections.
Update
For example:
View Model
public ObservableCollection<ObservableCollection<ContentItemViewModel>> ContentItems
{
get { return _contentItems; }
set { _contentItems = value; // Notify of property change here, this allows you to change the ContentItems reference after view model construction }
}
public MyViewModel()
{
// Populate content items
this.ContentItems = new ObservableCollection
{
new ObservableCollection { new ContentItemViewModel() },
new ObservableCollection { new ContentItemViewModel(), new ContentItemViewModel() }
};
}
View
<ListBox ItemsSource="{Binding ContentItems}" ...>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding MyContentItemViewModelProperty}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>

Grouping GridView in Windows 8 Metro App

Can someone give me some hints how to accomplish the grouping
within a GridView for Metro Apps as shown in the Screenshot below.
This Screenshot is from the Developer Resources for Windows Metro Apps,
but unfortunately there is no description how to accomplish it.
I have the following code snippet:
Xaml:
...
<Page.Resources>
<CollectionViewSource x:Name="cvs" IsSourceGrouped="true"/>
</Page.Resources>
<Grid Background="{StaticResource DefaultBackground}">
<GridView x:Name="DefaultGridView" ItemsSource="{Binding Source={StaticResource cvs}}">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding}" Width="100" Height="100" Margin="0 0 5 0"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text='{Binding Key}' Foreground="Gray" Margin="5" FontSize="30" FontFamily="Segoe UI Light" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid MaximumRowsOrColumns="2" Orientation="Horizontal" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</Grid>
...
C#:
In the Code-Behind I do the following in the OnNavigateTo Method:
List<string> strList = new List<string>() {
"Red", "Red", "Red", "Red", "Red", "Red",
"Green", "Green","Green","Green","Green",
"Blue","Blue","Blue","Blue" };
var groupedList = from s in strList
group s by s into g
orderby g.Key
select g;
cvs.Source = groupedList;
No matter what I do, I am not able to group the Items in a continues list like in the
Screenshot. The Code results in separate lists grouped side by side.
I may have a solution. In my projet, I had to create a list of contacts in alphabetic order, like the People app.
I used a GridView (with this sample), a CollectionViewSource and a wrappanel I found in the WinRT XAML Toolkit (you can get with NuGet package or copy/paste the source code). It allow you to put your items in columns.
Example
ViewModel
class ContactListViewModel
{
public ContactListViewModel()
{
ContactSource = new CollectionViewSource();
Contacts = new ObservableCollection<Contact>();
Contacts.Add(new Contact("Gates","Bill"));
Contacts.Add(new Contact("Bush","Georges"));
Contacts.Add(new Contact("Obama","Barack"));
Contacts.Add(new Contact("Hollande","François"));
Contacts.Add(new Contact("Affleck","Ben"));
Contacts.Add(new Contact("Allen","Woody"));
Contacts.Add(new Contact("Hendrix","Jimi"));
Contacts.Add(new Contact("Harrison", "Georges"));
Contacts = new ObservableCollection<Contact>(Contacts.OrderBy(c => c.Name));
ContactSource.Source = GetGroupsByLetter();
ContactSource.IsSourceGrouped = true;
}
#region Contacts
public ObservableCollection<Contact> Contacts
{
get;
protected set;
}
public CollectionViewSource ContactSource
{
get;
protected set;
}
#endregion
internal List<GroupInfoList<object>> GetGroupsByLetter()
{
List<GroupInfoList<object>> groups = new List<GroupInfoList<object>>();
var query = from item in Contacts
orderby ((Contact)item).Name
group item by ((Contact)item).Name[0] into g
select new { GroupName = g.Key, Items = g };
foreach (var g in query)
{
GroupInfoList<object> info = new GroupInfoList<object>();
info.Key = g.GroupName;
foreach (var item in g.Items)
{
info.Add(item);
}
groups.Add(info);
}
return groups;
}
public class GroupInfoList<T> : List<object>
{
public object Key { get; set; }
public new IEnumerator<object> GetEnumerator()
{
return (System.Collections.Generic.IEnumerator<object>)base.GetEnumerator();
}
}
}
View
<DataTemplate x:Key="contactTemplate">
<Grid Width="225" Height="75" Background="#55FFFFFF">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="20">
<Run Text="{Binding FirstName}"/>
<Run Text="{Binding Name}"/>
</TextBlock>
<TextBlock Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Binding Email}" FontSize="13" Foreground="#FFDDDDDD"/>
</Grid>
</Grid>
</DataTemplate>
<DataTemplate x:Key="letterTemplate">
<Grid Margin="5,0,0,5" Width="225">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Key}" Style="{StaticResource GroupHeaderTextStyle}" VerticalAlignment="Center"/>
<Rectangle Grid.Row="1" Fill="#BBEEEEEE" Height="1" Margin="0,7,0,0"/>
</Grid>
</DataTemplate>
</Page.Resources>
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" Style="{StaticResource BackButtonStyle}" Opacity="0"/>
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="Manager" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
<GridView Grid.Row="1"
ItemsSource="{Binding Path=ContactSource.View}"
SelectionMode="Multiple"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
Padding="116,10,40,46"
ItemTemplate="{StaticResource contactTemplate}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<local:WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource letterTemplate}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</Grid>
http://code.msdn.microsoft.com/windowsapps/GroupedGridView-77c59e8e
It can't be done using the default grid view styles.
You may have to use one none-grouped item list and add special items with different item template ...
Sorry
I would add the headers as items to the gridview, and use a TemplateSelector to display the elements the right way...

Categories