Reputation: 8852
I have a GridView
and it's bind to List
of items. I want it to have a static item so that users can click on it to add more items. if I click on other items I produce a item detail page.
How can I have that static tile which have entirely diferent behavior from every other grid item in the GridView
? Like the last tile in image below.
Upvotes: 2
Views: 2182
Reputation: 84
You can simply edit GridView's control template:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridView">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<ScrollViewer x:Name="ScrollViewer">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Your custom buttons -->
<StackPanel Orientation="Vertical"
Grid.Column="0">
</StackPanel>
<ItemsPresenter Grid.Column="1"
HeaderTemplate="{TemplateBinding HeaderTemplate}"
Header="{TemplateBinding Header}"
HeaderTransitions="{TemplateBinding HeaderTransitions}"
Padding="{TemplateBinding Padding}" />
</Grid>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
Upvotes: 1
Reputation: 8290
In our projects, we have found a clean solution to do that: Your GridView ItemsSource is bound to a collection of ViewModels. The last one can be a well known VM, for instance a LoadMoreViewModel
instance.
It allows you to create a DataTemplateSelector implementation and set it to the ItemTemplateSelector property of the GridView.
public class LoadMoreTemplateSelector: DataTemplateSelector
{
public DataTemplate LoadMoreTemplate { get; set; }
public DataTemplate DefaultTemplate { get; set; }
protected override Windows.UI.Xaml.DataTemplate SelectTemplateCore(object item, Windows.UI.Xaml.DependencyObject container)
{
if (item is LoadMoreViewModel)
{
return LoadMoreTemplate;
}
else
{
return DefaultTemplate;
}
}
}
Create an instance of this TemplateSelector as a resource in your xaml file, and set the appropriate templates:
<selectors:LoadMoreTemplateSelector x:Key="LoadMoreTemplateSelector"
DefaultTemplate="{StaticResource Template1}"
LoadMoreTemplate="{StaticResource LoadMoreTemplate}"/>
Your gridView can use this Template selector
<GridView ...
ItemTemplateSelector="{StaticResource LoadMoreTemplateSelector}" />
The LoadMoreTemplate should look like something like this:
<DataTemplate x:Key="LoadMoreTemplate">
<Button Command="{Binding LoadMore}" Content="+"/>
</DataTemplate>
The only remaining issue being that you will have to implement an ICommand in your LoadMoreViewModel to bind the load more button to in the template, or create an UserControl to be able to react to the Click event.
EDIT: Here is a simple ICommand implementation. It will execute the action passed to the constructor when the button is clicked.
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute,
Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public override bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public override void Execute(object parameter)
{
_execute(parameter);
}
public void RaiseCanExecuteChanged()
{
if( CanExecuteChanged != null )
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
When you instantiate your LoadMoreViewModel, you can provide the action to be executed when the User clicks the load more button.
public class LoadMoreViewModel:BindableBase
{
public ICommand LoadMore{get;private set;}
public LoadMoreViewModel(Action<object> action)
{
LoadMore = new DelegateCommand(action);
}
}
And in the page ViewModel, when Loading more items in the list, remove current LoadMoreViewModel at the end of the list, then add additionnal items, and finally add again the LoadMoreViewModel (if required):
public void LoadMoreItems()
{
if(Items.Last() is LoadMoreViewModel)
{
Items.Remove(Items.Last());
}
//Insert here add new items logic.
Items.Add(new LoadMoreViewModel(_=>LoadMoreItems());
}
Upvotes: 11